From 3a1720af1d7f43edc5b214cde0be11bfb94d077e Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Wed, 23 Oct 2019 17:52:22 +0000 Subject: Vendor import of stripped compiler-rt trunk r375505, the last commit before the upstream Subversion repository was made read-only, and the LLVM project migrated to GitHub: https://llvm.org/svn/llvm-project/compiler-rt/trunk@375505 --- lib/sanitizer_common/sancov_flags.cc | 58 - lib/sanitizer_common/sancov_flags.cpp | 58 + lib/sanitizer_common/sanitizer_allocator.cc | 267 --- lib/sanitizer_common/sanitizer_allocator.cpp | 267 +++ lib/sanitizer_common/sanitizer_allocator_checks.cc | 22 - .../sanitizer_allocator_checks.cpp | 22 + lib/sanitizer_common/sanitizer_allocator_checks.h | 2 +- lib/sanitizer_common/sanitizer_allocator_report.cc | 136 -- .../sanitizer_allocator_report.cpp | 137 ++ lib/sanitizer_common/sanitizer_asm.h | 4 +- lib/sanitizer_common/sanitizer_atomic_msvc.h | 63 +- lib/sanitizer_common/sanitizer_common.cc | 346 --- lib/sanitizer_common/sanitizer_common.cpp | 346 +++ lib/sanitizer_common/sanitizer_common.h | 29 +- .../sanitizer_common_interceptors.inc | 144 +- .../sanitizer_common_interface.inc | 1 + lib/sanitizer_common/sanitizer_common_libcdep.cc | 139 -- lib/sanitizer_common/sanitizer_common_libcdep.cpp | 139 ++ lib/sanitizer_common/sanitizer_common_nolibc.cc | 34 - lib/sanitizer_common/sanitizer_common_nolibc.cpp | 34 + lib/sanitizer_common/sanitizer_common_syscalls.inc | 12 + lib/sanitizer_common/sanitizer_coverage_fuchsia.cc | 240 -- .../sanitizer_coverage_fuchsia.cpp | 240 ++ .../sanitizer_coverage_libcdep_new.cc | 218 -- .../sanitizer_coverage_libcdep_new.cpp | 218 ++ .../sanitizer_coverage_win_dll_thunk.cc | 20 - .../sanitizer_coverage_win_dll_thunk.cpp | 20 + ...sanitizer_coverage_win_dynamic_runtime_thunk.cc | 26 - ...anitizer_coverage_win_dynamic_runtime_thunk.cpp | 26 + .../sanitizer_coverage_win_sections.cc | 67 - .../sanitizer_coverage_win_sections.cpp | 67 + .../sanitizer_coverage_win_weak_interception.cc | 23 - .../sanitizer_coverage_win_weak_interception.cpp | 23 + .../sanitizer_deadlock_detector1.cc | 194 -- .../sanitizer_deadlock_detector1.cpp | 194 ++ .../sanitizer_deadlock_detector2.cc | 423 ---- .../sanitizer_deadlock_detector2.cpp | 423 ++++ lib/sanitizer_common/sanitizer_errno.cc | 34 - lib/sanitizer_common/sanitizer_errno.cpp | 34 + lib/sanitizer_common/sanitizer_file.cc | 215 -- lib/sanitizer_common/sanitizer_file.cpp | 215 ++ lib/sanitizer_common/sanitizer_flag_parser.cc | 183 -- lib/sanitizer_common/sanitizer_flag_parser.cpp | 184 ++ lib/sanitizer_common/sanitizer_flag_parser.h | 4 +- lib/sanitizer_common/sanitizer_flags.cc | 121 - lib/sanitizer_common/sanitizer_flags.cpp | 121 + lib/sanitizer_common/sanitizer_fuchsia.cc | 527 ----- lib/sanitizer_common/sanitizer_fuchsia.cpp | 527 +++++ lib/sanitizer_common/sanitizer_getauxval.h | 30 +- lib/sanitizer_common/sanitizer_glibc_version.h | 26 + .../sanitizer_interceptors_ioctl_netbsd.inc | 31 +- lib/sanitizer_common/sanitizer_internal_defs.h | 75 +- lib/sanitizer_common/sanitizer_libc.cc | 279 --- lib/sanitizer_common/sanitizer_libc.cpp | 280 +++ lib/sanitizer_common/sanitizer_libignore.cc | 129 -- lib/sanitizer_common/sanitizer_libignore.cpp | 129 ++ lib/sanitizer_common/sanitizer_linux.cc | 2102 ----------------- lib/sanitizer_common/sanitizer_linux.cpp | 2141 +++++++++++++++++ lib/sanitizer_common/sanitizer_linux_libcdep.cc | 850 ------- lib/sanitizer_common/sanitizer_linux_libcdep.cpp | 847 +++++++ lib/sanitizer_common/sanitizer_linux_s390.cc | 221 -- lib/sanitizer_common/sanitizer_linux_s390.cpp | 221 ++ lib/sanitizer_common/sanitizer_mac.cc | 1135 ---------- lib/sanitizer_common/sanitizer_mac.cpp | 1219 ++++++++++ lib/sanitizer_common/sanitizer_mac_libcdep.cc | 29 - lib/sanitizer_common/sanitizer_mac_libcdep.cpp | 29 + lib/sanitizer_common/sanitizer_malloc_mac.inc | 11 +- lib/sanitizer_common/sanitizer_netbsd.cc | 338 --- lib/sanitizer_common/sanitizer_netbsd.cpp | 338 +++ lib/sanitizer_common/sanitizer_openbsd.cc | 115 - lib/sanitizer_common/sanitizer_openbsd.cpp | 115 + .../sanitizer_persistent_allocator.cc | 18 - .../sanitizer_persistent_allocator.cpp | 18 + .../sanitizer_platform_interceptors.h | 24 +- .../sanitizer_platform_limits_freebsd.cc | 525 ----- .../sanitizer_platform_limits_freebsd.cpp | 525 +++++ .../sanitizer_platform_limits_freebsd.h | 1090 ++++----- .../sanitizer_platform_limits_linux.cc | 108 - .../sanitizer_platform_limits_linux.cpp | 108 + .../sanitizer_platform_limits_netbsd.cc | 2345 ------------------- .../sanitizer_platform_limits_netbsd.cpp | 2395 ++++++++++++++++++++ .../sanitizer_platform_limits_netbsd.h | 47 +- .../sanitizer_platform_limits_openbsd.cc | 278 --- .../sanitizer_platform_limits_openbsd.cpp | 278 +++ .../sanitizer_platform_limits_posix.cc | 1271 ----------- .../sanitizer_platform_limits_posix.cpp | 1276 +++++++++++ .../sanitizer_platform_limits_posix.h | 2168 +++++++++--------- .../sanitizer_platform_limits_solaris.cc | 365 --- .../sanitizer_platform_limits_solaris.cpp | 365 +++ .../sanitizer_platform_limits_solaris.h | 7 +- lib/sanitizer_common/sanitizer_posix.cc | 388 ---- lib/sanitizer_common/sanitizer_posix.cpp | 390 ++++ lib/sanitizer_common/sanitizer_posix.h | 2 +- lib/sanitizer_common/sanitizer_posix_libcdep.cc | 486 ---- lib/sanitizer_common/sanitizer_posix_libcdep.cpp | 507 +++++ lib/sanitizer_common/sanitizer_printf.cc | 358 --- lib/sanitizer_common/sanitizer_printf.cpp | 358 +++ lib/sanitizer_common/sanitizer_procmaps.h | 2 +- lib/sanitizer_common/sanitizer_procmaps_bsd.cc | 139 -- lib/sanitizer_common/sanitizer_procmaps_bsd.cpp | 139 ++ lib/sanitizer_common/sanitizer_procmaps_common.cc | 174 -- lib/sanitizer_common/sanitizer_procmaps_common.cpp | 174 ++ lib/sanitizer_common/sanitizer_procmaps_linux.cc | 81 - lib/sanitizer_common/sanitizer_procmaps_linux.cpp | 81 + lib/sanitizer_common/sanitizer_procmaps_mac.cc | 378 --- lib/sanitizer_common/sanitizer_procmaps_mac.cpp | 379 ++++ lib/sanitizer_common/sanitizer_procmaps_solaris.cc | 67 - .../sanitizer_procmaps_solaris.cpp | 67 + lib/sanitizer_common/sanitizer_rtems.cc | 279 --- lib/sanitizer_common/sanitizer_rtems.cpp | 279 +++ lib/sanitizer_common/sanitizer_solaris.cc | 230 -- lib/sanitizer_common/sanitizer_solaris.cpp | 230 ++ lib/sanitizer_common/sanitizer_stackdepot.cc | 149 -- lib/sanitizer_common/sanitizer_stackdepot.cpp | 149 ++ lib/sanitizer_common/sanitizer_stacktrace.cc | 133 -- lib/sanitizer_common/sanitizer_stacktrace.cpp | 133 ++ .../sanitizer_stacktrace_libcdep.cc | 158 -- .../sanitizer_stacktrace_libcdep.cpp | 159 ++ .../sanitizer_stacktrace_printer.cc | 263 --- .../sanitizer_stacktrace_printer.cpp | 263 +++ lib/sanitizer_common/sanitizer_stacktrace_sparc.cc | 85 - .../sanitizer_stacktrace_sparc.cpp | 85 + .../sanitizer_stoptheworld_linux_libcdep.cc | 572 ----- .../sanitizer_stoptheworld_linux_libcdep.cpp | 573 +++++ lib/sanitizer_common/sanitizer_stoptheworld_mac.cc | 177 -- .../sanitizer_stoptheworld_mac.cpp | 177 ++ .../sanitizer_stoptheworld_netbsd_libcdep.cc | 356 --- .../sanitizer_stoptheworld_netbsd_libcdep.cpp | 356 +++ lib/sanitizer_common/sanitizer_suppressions.cc | 181 -- lib/sanitizer_common/sanitizer_suppressions.cpp | 181 ++ lib/sanitizer_common/sanitizer_suppressions.h | 2 +- lib/sanitizer_common/sanitizer_symbolizer.cc | 129 -- lib/sanitizer_common/sanitizer_symbolizer.cpp | 129 ++ .../sanitizer_symbolizer_internal.h | 19 +- .../sanitizer_symbolizer_libbacktrace.cc | 209 -- .../sanitizer_symbolizer_libbacktrace.cpp | 209 ++ .../sanitizer_symbolizer_libcdep.cc | 556 ----- .../sanitizer_symbolizer_libcdep.cpp | 557 +++++ lib/sanitizer_common/sanitizer_symbolizer_mac.cc | 168 -- lib/sanitizer_common/sanitizer_symbolizer_mac.cpp | 173 ++ .../sanitizer_symbolizer_markup.cc | 144 -- .../sanitizer_symbolizer_markup.cpp | 144 ++ .../sanitizer_symbolizer_posix_libcdep.cc | 539 ----- .../sanitizer_symbolizer_posix_libcdep.cpp | 487 ++++ .../sanitizer_symbolizer_report.cc | 283 --- .../sanitizer_symbolizer_report.cpp | 293 +++ lib/sanitizer_common/sanitizer_symbolizer_win.cc | 318 --- lib/sanitizer_common/sanitizer_symbolizer_win.cpp | 318 +++ lib/sanitizer_common/sanitizer_termination.cc | 94 - lib/sanitizer_common/sanitizer_termination.cpp | 94 + lib/sanitizer_common/sanitizer_thread_registry.cc | 351 --- lib/sanitizer_common/sanitizer_thread_registry.cpp | 351 +++ lib/sanitizer_common/sanitizer_tls_get_addr.cc | 154 -- lib/sanitizer_common/sanitizer_tls_get_addr.cpp | 154 ++ lib/sanitizer_common/sanitizer_tls_get_addr.h | 2 +- lib/sanitizer_common/sanitizer_type_traits.cc | 20 - lib/sanitizer_common/sanitizer_type_traits.cpp | 20 + .../sanitizer_unwind_linux_libcdep.cc | 176 -- .../sanitizer_unwind_linux_libcdep.cpp | 180 ++ lib/sanitizer_common/sanitizer_unwind_win.cc | 75 - lib/sanitizer_common/sanitizer_unwind_win.cpp | 75 + lib/sanitizer_common/sanitizer_vector.h | 6 +- lib/sanitizer_common/sanitizer_win.cc | 1115 --------- lib/sanitizer_common/sanitizer_win.cpp | 1124 +++++++++ lib/sanitizer_common/sanitizer_win_defs.h | 12 + lib/sanitizer_common/sanitizer_win_dll_thunk.cc | 101 - lib/sanitizer_common/sanitizer_win_dll_thunk.cpp | 101 + .../sanitizer_win_dynamic_runtime_thunk.cc | 26 - .../sanitizer_win_dynamic_runtime_thunk.cpp | 26 + .../sanitizer_win_weak_interception.cc | 93 - .../sanitizer_win_weak_interception.cpp | 94 + .../symbolizer/sanitizer_symbolize.cc | 80 - .../symbolizer/sanitizer_symbolize.cpp | 80 + .../symbolizer/sanitizer_wrappers.cc | 198 -- .../symbolizer/sanitizer_wrappers.cpp | 198 ++ .../symbolizer/scripts/build_symbolizer.sh | 34 +- .../symbolizer/scripts/global_symbols.txt | 7 + 177 files changed, 25132 insertions(+), 24672 deletions(-) delete mode 100644 lib/sanitizer_common/sancov_flags.cc create mode 100644 lib/sanitizer_common/sancov_flags.cpp delete mode 100644 lib/sanitizer_common/sanitizer_allocator.cc create mode 100644 lib/sanitizer_common/sanitizer_allocator.cpp delete mode 100644 lib/sanitizer_common/sanitizer_allocator_checks.cc create mode 100644 lib/sanitizer_common/sanitizer_allocator_checks.cpp delete mode 100644 lib/sanitizer_common/sanitizer_allocator_report.cc create mode 100644 lib/sanitizer_common/sanitizer_allocator_report.cpp delete mode 100644 lib/sanitizer_common/sanitizer_common.cc create mode 100644 lib/sanitizer_common/sanitizer_common.cpp delete mode 100644 lib/sanitizer_common/sanitizer_common_libcdep.cc create mode 100644 lib/sanitizer_common/sanitizer_common_libcdep.cpp delete mode 100644 lib/sanitizer_common/sanitizer_common_nolibc.cc create mode 100644 lib/sanitizer_common/sanitizer_common_nolibc.cpp delete mode 100644 lib/sanitizer_common/sanitizer_coverage_fuchsia.cc create mode 100644 lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp delete mode 100644 lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc create mode 100644 lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp delete mode 100644 lib/sanitizer_common/sanitizer_coverage_win_dll_thunk.cc create mode 100644 lib/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp delete mode 100644 lib/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cc create mode 100644 lib/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cpp delete mode 100644 lib/sanitizer_common/sanitizer_coverage_win_sections.cc create mode 100644 lib/sanitizer_common/sanitizer_coverage_win_sections.cpp delete mode 100644 lib/sanitizer_common/sanitizer_coverage_win_weak_interception.cc create mode 100644 lib/sanitizer_common/sanitizer_coverage_win_weak_interception.cpp delete mode 100644 lib/sanitizer_common/sanitizer_deadlock_detector1.cc create mode 100644 lib/sanitizer_common/sanitizer_deadlock_detector1.cpp delete mode 100644 lib/sanitizer_common/sanitizer_deadlock_detector2.cc create mode 100644 lib/sanitizer_common/sanitizer_deadlock_detector2.cpp delete mode 100644 lib/sanitizer_common/sanitizer_errno.cc create mode 100644 lib/sanitizer_common/sanitizer_errno.cpp delete mode 100644 lib/sanitizer_common/sanitizer_file.cc create mode 100644 lib/sanitizer_common/sanitizer_file.cpp delete mode 100644 lib/sanitizer_common/sanitizer_flag_parser.cc create mode 100644 lib/sanitizer_common/sanitizer_flag_parser.cpp delete mode 100644 lib/sanitizer_common/sanitizer_flags.cc create mode 100644 lib/sanitizer_common/sanitizer_flags.cpp delete mode 100644 lib/sanitizer_common/sanitizer_fuchsia.cc create mode 100644 lib/sanitizer_common/sanitizer_fuchsia.cpp create mode 100644 lib/sanitizer_common/sanitizer_glibc_version.h delete mode 100644 lib/sanitizer_common/sanitizer_libc.cc create mode 100644 lib/sanitizer_common/sanitizer_libc.cpp delete mode 100644 lib/sanitizer_common/sanitizer_libignore.cc create mode 100644 lib/sanitizer_common/sanitizer_libignore.cpp delete mode 100644 lib/sanitizer_common/sanitizer_linux.cc create mode 100644 lib/sanitizer_common/sanitizer_linux.cpp delete mode 100644 lib/sanitizer_common/sanitizer_linux_libcdep.cc create mode 100644 lib/sanitizer_common/sanitizer_linux_libcdep.cpp delete mode 100644 lib/sanitizer_common/sanitizer_linux_s390.cc create mode 100644 lib/sanitizer_common/sanitizer_linux_s390.cpp delete mode 100644 lib/sanitizer_common/sanitizer_mac.cc create mode 100644 lib/sanitizer_common/sanitizer_mac.cpp delete mode 100644 lib/sanitizer_common/sanitizer_mac_libcdep.cc create mode 100644 lib/sanitizer_common/sanitizer_mac_libcdep.cpp delete mode 100644 lib/sanitizer_common/sanitizer_netbsd.cc create mode 100644 lib/sanitizer_common/sanitizer_netbsd.cpp delete mode 100644 lib/sanitizer_common/sanitizer_openbsd.cc create mode 100644 lib/sanitizer_common/sanitizer_openbsd.cpp delete mode 100644 lib/sanitizer_common/sanitizer_persistent_allocator.cc create mode 100644 lib/sanitizer_common/sanitizer_persistent_allocator.cpp delete mode 100644 lib/sanitizer_common/sanitizer_platform_limits_freebsd.cc create mode 100644 lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp delete mode 100644 lib/sanitizer_common/sanitizer_platform_limits_linux.cc create mode 100644 lib/sanitizer_common/sanitizer_platform_limits_linux.cpp delete mode 100644 lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc create mode 100644 lib/sanitizer_common/sanitizer_platform_limits_netbsd.cpp delete mode 100644 lib/sanitizer_common/sanitizer_platform_limits_openbsd.cc create mode 100644 lib/sanitizer_common/sanitizer_platform_limits_openbsd.cpp delete mode 100644 lib/sanitizer_common/sanitizer_platform_limits_posix.cc create mode 100644 lib/sanitizer_common/sanitizer_platform_limits_posix.cpp delete mode 100644 lib/sanitizer_common/sanitizer_platform_limits_solaris.cc create mode 100644 lib/sanitizer_common/sanitizer_platform_limits_solaris.cpp delete mode 100644 lib/sanitizer_common/sanitizer_posix.cc create mode 100644 lib/sanitizer_common/sanitizer_posix.cpp delete mode 100644 lib/sanitizer_common/sanitizer_posix_libcdep.cc create mode 100644 lib/sanitizer_common/sanitizer_posix_libcdep.cpp delete mode 100644 lib/sanitizer_common/sanitizer_printf.cc create mode 100644 lib/sanitizer_common/sanitizer_printf.cpp delete mode 100644 lib/sanitizer_common/sanitizer_procmaps_bsd.cc create mode 100644 lib/sanitizer_common/sanitizer_procmaps_bsd.cpp delete mode 100644 lib/sanitizer_common/sanitizer_procmaps_common.cc create mode 100644 lib/sanitizer_common/sanitizer_procmaps_common.cpp delete mode 100644 lib/sanitizer_common/sanitizer_procmaps_linux.cc create mode 100644 lib/sanitizer_common/sanitizer_procmaps_linux.cpp delete mode 100644 lib/sanitizer_common/sanitizer_procmaps_mac.cc create mode 100644 lib/sanitizer_common/sanitizer_procmaps_mac.cpp delete mode 100644 lib/sanitizer_common/sanitizer_procmaps_solaris.cc create mode 100644 lib/sanitizer_common/sanitizer_procmaps_solaris.cpp delete mode 100644 lib/sanitizer_common/sanitizer_rtems.cc create mode 100644 lib/sanitizer_common/sanitizer_rtems.cpp delete mode 100644 lib/sanitizer_common/sanitizer_solaris.cc create mode 100644 lib/sanitizer_common/sanitizer_solaris.cpp delete mode 100644 lib/sanitizer_common/sanitizer_stackdepot.cc create mode 100644 lib/sanitizer_common/sanitizer_stackdepot.cpp delete mode 100644 lib/sanitizer_common/sanitizer_stacktrace.cc create mode 100644 lib/sanitizer_common/sanitizer_stacktrace.cpp delete mode 100644 lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc create mode 100644 lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp delete mode 100644 lib/sanitizer_common/sanitizer_stacktrace_printer.cc create mode 100644 lib/sanitizer_common/sanitizer_stacktrace_printer.cpp delete mode 100644 lib/sanitizer_common/sanitizer_stacktrace_sparc.cc create mode 100644 lib/sanitizer_common/sanitizer_stacktrace_sparc.cpp delete mode 100644 lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc create mode 100644 lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp delete mode 100644 lib/sanitizer_common/sanitizer_stoptheworld_mac.cc create mode 100644 lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp delete mode 100644 lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cc create mode 100644 lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp delete mode 100644 lib/sanitizer_common/sanitizer_suppressions.cc create mode 100644 lib/sanitizer_common/sanitizer_suppressions.cpp delete mode 100644 lib/sanitizer_common/sanitizer_symbolizer.cc create mode 100644 lib/sanitizer_common/sanitizer_symbolizer.cpp delete mode 100644 lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc create mode 100644 lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cpp delete mode 100644 lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc create mode 100644 lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp delete mode 100644 lib/sanitizer_common/sanitizer_symbolizer_mac.cc create mode 100644 lib/sanitizer_common/sanitizer_symbolizer_mac.cpp delete mode 100644 lib/sanitizer_common/sanitizer_symbolizer_markup.cc create mode 100644 lib/sanitizer_common/sanitizer_symbolizer_markup.cpp delete mode 100644 lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc create mode 100644 lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp delete mode 100644 lib/sanitizer_common/sanitizer_symbolizer_report.cc create mode 100644 lib/sanitizer_common/sanitizer_symbolizer_report.cpp delete mode 100644 lib/sanitizer_common/sanitizer_symbolizer_win.cc create mode 100644 lib/sanitizer_common/sanitizer_symbolizer_win.cpp delete mode 100644 lib/sanitizer_common/sanitizer_termination.cc create mode 100644 lib/sanitizer_common/sanitizer_termination.cpp delete mode 100644 lib/sanitizer_common/sanitizer_thread_registry.cc create mode 100644 lib/sanitizer_common/sanitizer_thread_registry.cpp delete mode 100644 lib/sanitizer_common/sanitizer_tls_get_addr.cc create mode 100644 lib/sanitizer_common/sanitizer_tls_get_addr.cpp delete mode 100644 lib/sanitizer_common/sanitizer_type_traits.cc create mode 100644 lib/sanitizer_common/sanitizer_type_traits.cpp delete mode 100644 lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc create mode 100644 lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cpp delete mode 100644 lib/sanitizer_common/sanitizer_unwind_win.cc create mode 100644 lib/sanitizer_common/sanitizer_unwind_win.cpp delete mode 100644 lib/sanitizer_common/sanitizer_win.cc create mode 100644 lib/sanitizer_common/sanitizer_win.cpp delete mode 100644 lib/sanitizer_common/sanitizer_win_dll_thunk.cc create mode 100644 lib/sanitizer_common/sanitizer_win_dll_thunk.cpp delete mode 100644 lib/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cc create mode 100644 lib/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cpp delete mode 100644 lib/sanitizer_common/sanitizer_win_weak_interception.cc create mode 100644 lib/sanitizer_common/sanitizer_win_weak_interception.cpp delete mode 100644 lib/sanitizer_common/symbolizer/sanitizer_symbolize.cc create mode 100644 lib/sanitizer_common/symbolizer/sanitizer_symbolize.cpp delete mode 100644 lib/sanitizer_common/symbolizer/sanitizer_wrappers.cc create mode 100644 lib/sanitizer_common/symbolizer/sanitizer_wrappers.cpp (limited to 'lib/sanitizer_common') diff --git a/lib/sanitizer_common/sancov_flags.cc b/lib/sanitizer_common/sancov_flags.cc deleted file mode 100644 index ec6c14b1e2e4..000000000000 --- a/lib/sanitizer_common/sancov_flags.cc +++ /dev/null @@ -1,58 +0,0 @@ -//===-- sancov_flags.cc -----------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Sanitizer Coverage runtime flags. -// -//===----------------------------------------------------------------------===// - -#include "sancov_flags.h" -#include "sanitizer_flag_parser.h" -#include "sanitizer_platform.h" - -SANITIZER_INTERFACE_WEAK_DEF(const char*, __sancov_default_options, void) { - return ""; -} - -using namespace __sanitizer; - -namespace __sancov { - -SancovFlags sancov_flags_dont_use_directly; // use via flags(); - -void SancovFlags::SetDefaults() { -#define SANCOV_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; -#include "sancov_flags.inc" -#undef SANCOV_FLAG -} - -static void RegisterSancovFlags(FlagParser *parser, SancovFlags *f) { -#define SANCOV_FLAG(Type, Name, DefaultValue, Description) \ - RegisterFlag(parser, #Name, Description, &f->Name); -#include "sancov_flags.inc" -#undef SANCOV_FLAG -} - -static const char *MaybeCallSancovDefaultOptions() { - return (&__sancov_default_options) ? __sancov_default_options() : ""; -} - -void InitializeSancovFlags() { - SancovFlags *f = sancov_flags(); - f->SetDefaults(); - - FlagParser parser; - RegisterSancovFlags(&parser, f); - - parser.ParseString(MaybeCallSancovDefaultOptions()); - parser.ParseStringFromEnv("SANCOV_OPTIONS"); - - ReportUnrecognizedFlags(); - if (f->help) parser.PrintFlagDescriptions(); -} - -} // namespace __sancov diff --git a/lib/sanitizer_common/sancov_flags.cpp b/lib/sanitizer_common/sancov_flags.cpp new file mode 100644 index 000000000000..ed46e88acdfc --- /dev/null +++ b/lib/sanitizer_common/sancov_flags.cpp @@ -0,0 +1,58 @@ +//===-- sancov_flags.cpp ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Sanitizer Coverage runtime flags. +// +//===----------------------------------------------------------------------===// + +#include "sancov_flags.h" +#include "sanitizer_flag_parser.h" +#include "sanitizer_platform.h" + +SANITIZER_INTERFACE_WEAK_DEF(const char*, __sancov_default_options, void) { + return ""; +} + +using namespace __sanitizer; + +namespace __sancov { + +SancovFlags sancov_flags_dont_use_directly; // use via flags(); + +void SancovFlags::SetDefaults() { +#define SANCOV_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "sancov_flags.inc" +#undef SANCOV_FLAG +} + +static void RegisterSancovFlags(FlagParser *parser, SancovFlags *f) { +#define SANCOV_FLAG(Type, Name, DefaultValue, Description) \ + RegisterFlag(parser, #Name, Description, &f->Name); +#include "sancov_flags.inc" +#undef SANCOV_FLAG +} + +static const char *MaybeCallSancovDefaultOptions() { + return (&__sancov_default_options) ? __sancov_default_options() : ""; +} + +void InitializeSancovFlags() { + SancovFlags *f = sancov_flags(); + f->SetDefaults(); + + FlagParser parser; + RegisterSancovFlags(&parser, f); + + parser.ParseString(MaybeCallSancovDefaultOptions()); + parser.ParseStringFromEnv("SANCOV_OPTIONS"); + + ReportUnrecognizedFlags(); + if (f->help) parser.PrintFlagDescriptions(); +} + +} // namespace __sancov diff --git a/lib/sanitizer_common/sanitizer_allocator.cc b/lib/sanitizer_common/sanitizer_allocator.cc deleted file mode 100644 index 1739bb66b657..000000000000 --- a/lib/sanitizer_common/sanitizer_allocator.cc +++ /dev/null @@ -1,267 +0,0 @@ -//===-- sanitizer_allocator.cc --------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. -// This allocator is used inside run-times. -//===----------------------------------------------------------------------===// - -#include "sanitizer_allocator.h" - -#include "sanitizer_allocator_checks.h" -#include "sanitizer_allocator_internal.h" -#include "sanitizer_atomic.h" -#include "sanitizer_common.h" - -namespace __sanitizer { - -// Default allocator names. -const char *PrimaryAllocatorName = "SizeClassAllocator"; -const char *SecondaryAllocatorName = "LargeMmapAllocator"; - -// ThreadSanitizer for Go uses libc malloc/free. -#if SANITIZER_GO || defined(SANITIZER_USE_MALLOC) -# if SANITIZER_LINUX && !SANITIZER_ANDROID -extern "C" void *__libc_malloc(uptr size); -# if !SANITIZER_GO -extern "C" void *__libc_memalign(uptr alignment, uptr size); -# endif -extern "C" void *__libc_realloc(void *ptr, uptr size); -extern "C" void __libc_free(void *ptr); -# else -# include -# define __libc_malloc malloc -# if !SANITIZER_GO -static void *__libc_memalign(uptr alignment, uptr size) { - void *p; - uptr error = posix_memalign(&p, alignment, size); - if (error) return nullptr; - return p; -} -# endif -# define __libc_realloc realloc -# define __libc_free free -# endif - -static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache, - uptr alignment) { - (void)cache; -#if !SANITIZER_GO - if (alignment == 0) - return __libc_malloc(size); - else - return __libc_memalign(alignment, size); -#else - // Windows does not provide __libc_memalign/posix_memalign. It provides - // __aligned_malloc, but the allocated blocks can't be passed to free, - // they need to be passed to __aligned_free. InternalAlloc interface does - // not account for such requirement. Alignemnt does not seem to be used - // anywhere in runtime, so just call __libc_malloc for now. - DCHECK_EQ(alignment, 0); - return __libc_malloc(size); -#endif -} - -static void *RawInternalRealloc(void *ptr, uptr size, - InternalAllocatorCache *cache) { - (void)cache; - return __libc_realloc(ptr, size); -} - -static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) { - (void)cache; - __libc_free(ptr); -} - -InternalAllocator *internal_allocator() { - return 0; -} - -#else // SANITIZER_GO || defined(SANITIZER_USE_MALLOC) - -static ALIGNED(64) char internal_alloc_placeholder[sizeof(InternalAllocator)]; -static atomic_uint8_t internal_allocator_initialized; -static StaticSpinMutex internal_alloc_init_mu; - -static InternalAllocatorCache internal_allocator_cache; -static StaticSpinMutex internal_allocator_cache_mu; - -InternalAllocator *internal_allocator() { - InternalAllocator *internal_allocator_instance = - reinterpret_cast(&internal_alloc_placeholder); - if (atomic_load(&internal_allocator_initialized, memory_order_acquire) == 0) { - SpinMutexLock l(&internal_alloc_init_mu); - if (atomic_load(&internal_allocator_initialized, memory_order_relaxed) == - 0) { - internal_allocator_instance->Init(kReleaseToOSIntervalNever); - atomic_store(&internal_allocator_initialized, 1, memory_order_release); - } - } - return internal_allocator_instance; -} - -static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache, - uptr alignment) { - if (alignment == 0) alignment = 8; - if (cache == 0) { - SpinMutexLock l(&internal_allocator_cache_mu); - return internal_allocator()->Allocate(&internal_allocator_cache, size, - alignment); - } - return internal_allocator()->Allocate(cache, size, alignment); -} - -static void *RawInternalRealloc(void *ptr, uptr size, - InternalAllocatorCache *cache) { - uptr alignment = 8; - if (cache == 0) { - SpinMutexLock l(&internal_allocator_cache_mu); - return internal_allocator()->Reallocate(&internal_allocator_cache, ptr, - size, alignment); - } - return internal_allocator()->Reallocate(cache, ptr, size, alignment); -} - -static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) { - if (!cache) { - SpinMutexLock l(&internal_allocator_cache_mu); - return internal_allocator()->Deallocate(&internal_allocator_cache, ptr); - } - internal_allocator()->Deallocate(cache, ptr); -} - -#endif // SANITIZER_GO || defined(SANITIZER_USE_MALLOC) - -const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull; - -static void NORETURN ReportInternalAllocatorOutOfMemory(uptr requested_size) { - SetAllocatorOutOfMemory(); - Report("FATAL: %s: internal allocator is out of memory trying to allocate " - "0x%zx bytes\n", SanitizerToolName, requested_size); - Die(); -} - -void *InternalAlloc(uptr size, InternalAllocatorCache *cache, uptr alignment) { - if (size + sizeof(u64) < size) - return nullptr; - void *p = RawInternalAlloc(size + sizeof(u64), cache, alignment); - if (UNLIKELY(!p)) - ReportInternalAllocatorOutOfMemory(size + sizeof(u64)); - ((u64*)p)[0] = kBlockMagic; - return (char*)p + sizeof(u64); -} - -void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) { - if (!addr) - return InternalAlloc(size, cache); - if (size + sizeof(u64) < size) - return nullptr; - addr = (char*)addr - sizeof(u64); - size = size + sizeof(u64); - CHECK_EQ(kBlockMagic, ((u64*)addr)[0]); - void *p = RawInternalRealloc(addr, size, cache); - if (UNLIKELY(!p)) - ReportInternalAllocatorOutOfMemory(size); - return (char*)p + sizeof(u64); -} - -void *InternalReallocArray(void *addr, uptr count, uptr size, - InternalAllocatorCache *cache) { - if (UNLIKELY(CheckForCallocOverflow(count, size))) { - Report( - "FATAL: %s: reallocarray parameters overflow: count * size (%zd * %zd) " - "cannot be represented in type size_t\n", - SanitizerToolName, count, size); - Die(); - } - return InternalRealloc(addr, count * size, cache); -} - -void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) { - if (UNLIKELY(CheckForCallocOverflow(count, size))) { - Report("FATAL: %s: calloc parameters overflow: count * size (%zd * %zd) " - "cannot be represented in type size_t\n", SanitizerToolName, count, - size); - Die(); - } - void *p = InternalAlloc(count * size, cache); - if (LIKELY(p)) - internal_memset(p, 0, count * size); - return p; -} - -void InternalFree(void *addr, InternalAllocatorCache *cache) { - if (!addr) - return; - addr = (char*)addr - sizeof(u64); - CHECK_EQ(kBlockMagic, ((u64*)addr)[0]); - ((u64*)addr)[0] = 0; - RawInternalFree(addr, cache); -} - -// LowLevelAllocator -constexpr uptr kLowLevelAllocatorDefaultAlignment = 8; -static uptr low_level_alloc_min_alignment = kLowLevelAllocatorDefaultAlignment; -static LowLevelAllocateCallback low_level_alloc_callback; - -void *LowLevelAllocator::Allocate(uptr size) { - // Align allocation size. - size = RoundUpTo(size, low_level_alloc_min_alignment); - if (allocated_end_ - allocated_current_ < (sptr)size) { - uptr size_to_allocate = Max(size, GetPageSizeCached()); - allocated_current_ = - (char*)MmapOrDie(size_to_allocate, __func__); - allocated_end_ = allocated_current_ + size_to_allocate; - if (low_level_alloc_callback) { - low_level_alloc_callback((uptr)allocated_current_, - size_to_allocate); - } - } - CHECK(allocated_end_ - allocated_current_ >= (sptr)size); - void *res = allocated_current_; - allocated_current_ += size; - return res; -} - -void SetLowLevelAllocateMinAlignment(uptr alignment) { - CHECK(IsPowerOfTwo(alignment)); - low_level_alloc_min_alignment = Max(alignment, low_level_alloc_min_alignment); -} - -void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) { - low_level_alloc_callback = callback; -} - -// Allocator's OOM and other errors handling support. - -static atomic_uint8_t allocator_out_of_memory = {0}; -static atomic_uint8_t allocator_may_return_null = {0}; - -bool IsAllocatorOutOfMemory() { - return atomic_load_relaxed(&allocator_out_of_memory); -} - -void SetAllocatorOutOfMemory() { - atomic_store_relaxed(&allocator_out_of_memory, 1); -} - -bool AllocatorMayReturnNull() { - return atomic_load(&allocator_may_return_null, memory_order_relaxed); -} - -void SetAllocatorMayReturnNull(bool may_return_null) { - atomic_store(&allocator_may_return_null, may_return_null, - memory_order_relaxed); -} - -void PrintHintAllocatorCannotReturnNull() { - Report("HINT: if you don't care about these errors you may set " - "allocator_may_return_null=1\n"); -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_allocator.cpp b/lib/sanitizer_common/sanitizer_allocator.cpp new file mode 100644 index 000000000000..8d07906cca03 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_allocator.cpp @@ -0,0 +1,267 @@ +//===-- sanitizer_allocator.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +// This allocator is used inside run-times. +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator.h" + +#include "sanitizer_allocator_checks.h" +#include "sanitizer_allocator_internal.h" +#include "sanitizer_atomic.h" +#include "sanitizer_common.h" + +namespace __sanitizer { + +// Default allocator names. +const char *PrimaryAllocatorName = "SizeClassAllocator"; +const char *SecondaryAllocatorName = "LargeMmapAllocator"; + +// ThreadSanitizer for Go uses libc malloc/free. +#if SANITIZER_GO || defined(SANITIZER_USE_MALLOC) +# if SANITIZER_LINUX && !SANITIZER_ANDROID +extern "C" void *__libc_malloc(uptr size); +# if !SANITIZER_GO +extern "C" void *__libc_memalign(uptr alignment, uptr size); +# endif +extern "C" void *__libc_realloc(void *ptr, uptr size); +extern "C" void __libc_free(void *ptr); +# else +# include +# define __libc_malloc malloc +# if !SANITIZER_GO +static void *__libc_memalign(uptr alignment, uptr size) { + void *p; + uptr error = posix_memalign(&p, alignment, size); + if (error) return nullptr; + return p; +} +# endif +# define __libc_realloc realloc +# define __libc_free free +# endif + +static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache, + uptr alignment) { + (void)cache; +#if !SANITIZER_GO + if (alignment == 0) + return __libc_malloc(size); + else + return __libc_memalign(alignment, size); +#else + // Windows does not provide __libc_memalign/posix_memalign. It provides + // __aligned_malloc, but the allocated blocks can't be passed to free, + // they need to be passed to __aligned_free. InternalAlloc interface does + // not account for such requirement. Alignemnt does not seem to be used + // anywhere in runtime, so just call __libc_malloc for now. + DCHECK_EQ(alignment, 0); + return __libc_malloc(size); +#endif +} + +static void *RawInternalRealloc(void *ptr, uptr size, + InternalAllocatorCache *cache) { + (void)cache; + return __libc_realloc(ptr, size); +} + +static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) { + (void)cache; + __libc_free(ptr); +} + +InternalAllocator *internal_allocator() { + return 0; +} + +#else // SANITIZER_GO || defined(SANITIZER_USE_MALLOC) + +static ALIGNED(64) char internal_alloc_placeholder[sizeof(InternalAllocator)]; +static atomic_uint8_t internal_allocator_initialized; +static StaticSpinMutex internal_alloc_init_mu; + +static InternalAllocatorCache internal_allocator_cache; +static StaticSpinMutex internal_allocator_cache_mu; + +InternalAllocator *internal_allocator() { + InternalAllocator *internal_allocator_instance = + reinterpret_cast(&internal_alloc_placeholder); + if (atomic_load(&internal_allocator_initialized, memory_order_acquire) == 0) { + SpinMutexLock l(&internal_alloc_init_mu); + if (atomic_load(&internal_allocator_initialized, memory_order_relaxed) == + 0) { + internal_allocator_instance->Init(kReleaseToOSIntervalNever); + atomic_store(&internal_allocator_initialized, 1, memory_order_release); + } + } + return internal_allocator_instance; +} + +static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache, + uptr alignment) { + if (alignment == 0) alignment = 8; + if (cache == 0) { + SpinMutexLock l(&internal_allocator_cache_mu); + return internal_allocator()->Allocate(&internal_allocator_cache, size, + alignment); + } + return internal_allocator()->Allocate(cache, size, alignment); +} + +static void *RawInternalRealloc(void *ptr, uptr size, + InternalAllocatorCache *cache) { + uptr alignment = 8; + if (cache == 0) { + SpinMutexLock l(&internal_allocator_cache_mu); + return internal_allocator()->Reallocate(&internal_allocator_cache, ptr, + size, alignment); + } + return internal_allocator()->Reallocate(cache, ptr, size, alignment); +} + +static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) { + if (!cache) { + SpinMutexLock l(&internal_allocator_cache_mu); + return internal_allocator()->Deallocate(&internal_allocator_cache, ptr); + } + internal_allocator()->Deallocate(cache, ptr); +} + +#endif // SANITIZER_GO || defined(SANITIZER_USE_MALLOC) + +const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull; + +static void NORETURN ReportInternalAllocatorOutOfMemory(uptr requested_size) { + SetAllocatorOutOfMemory(); + Report("FATAL: %s: internal allocator is out of memory trying to allocate " + "0x%zx bytes\n", SanitizerToolName, requested_size); + Die(); +} + +void *InternalAlloc(uptr size, InternalAllocatorCache *cache, uptr alignment) { + if (size + sizeof(u64) < size) + return nullptr; + void *p = RawInternalAlloc(size + sizeof(u64), cache, alignment); + if (UNLIKELY(!p)) + ReportInternalAllocatorOutOfMemory(size + sizeof(u64)); + ((u64*)p)[0] = kBlockMagic; + return (char*)p + sizeof(u64); +} + +void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) { + if (!addr) + return InternalAlloc(size, cache); + if (size + sizeof(u64) < size) + return nullptr; + addr = (char*)addr - sizeof(u64); + size = size + sizeof(u64); + CHECK_EQ(kBlockMagic, ((u64*)addr)[0]); + void *p = RawInternalRealloc(addr, size, cache); + if (UNLIKELY(!p)) + ReportInternalAllocatorOutOfMemory(size); + return (char*)p + sizeof(u64); +} + +void *InternalReallocArray(void *addr, uptr count, uptr size, + InternalAllocatorCache *cache) { + if (UNLIKELY(CheckForCallocOverflow(count, size))) { + Report( + "FATAL: %s: reallocarray parameters overflow: count * size (%zd * %zd) " + "cannot be represented in type size_t\n", + SanitizerToolName, count, size); + Die(); + } + return InternalRealloc(addr, count * size, cache); +} + +void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) { + if (UNLIKELY(CheckForCallocOverflow(count, size))) { + Report("FATAL: %s: calloc parameters overflow: count * size (%zd * %zd) " + "cannot be represented in type size_t\n", SanitizerToolName, count, + size); + Die(); + } + void *p = InternalAlloc(count * size, cache); + if (LIKELY(p)) + internal_memset(p, 0, count * size); + return p; +} + +void InternalFree(void *addr, InternalAllocatorCache *cache) { + if (!addr) + return; + addr = (char*)addr - sizeof(u64); + CHECK_EQ(kBlockMagic, ((u64*)addr)[0]); + ((u64*)addr)[0] = 0; + RawInternalFree(addr, cache); +} + +// LowLevelAllocator +constexpr uptr kLowLevelAllocatorDefaultAlignment = 8; +static uptr low_level_alloc_min_alignment = kLowLevelAllocatorDefaultAlignment; +static LowLevelAllocateCallback low_level_alloc_callback; + +void *LowLevelAllocator::Allocate(uptr size) { + // Align allocation size. + size = RoundUpTo(size, low_level_alloc_min_alignment); + if (allocated_end_ - allocated_current_ < (sptr)size) { + uptr size_to_allocate = Max(size, GetPageSizeCached()); + allocated_current_ = + (char*)MmapOrDie(size_to_allocate, __func__); + allocated_end_ = allocated_current_ + size_to_allocate; + if (low_level_alloc_callback) { + low_level_alloc_callback((uptr)allocated_current_, + size_to_allocate); + } + } + CHECK(allocated_end_ - allocated_current_ >= (sptr)size); + void *res = allocated_current_; + allocated_current_ += size; + return res; +} + +void SetLowLevelAllocateMinAlignment(uptr alignment) { + CHECK(IsPowerOfTwo(alignment)); + low_level_alloc_min_alignment = Max(alignment, low_level_alloc_min_alignment); +} + +void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) { + low_level_alloc_callback = callback; +} + +// Allocator's OOM and other errors handling support. + +static atomic_uint8_t allocator_out_of_memory = {0}; +static atomic_uint8_t allocator_may_return_null = {0}; + +bool IsAllocatorOutOfMemory() { + return atomic_load_relaxed(&allocator_out_of_memory); +} + +void SetAllocatorOutOfMemory() { + atomic_store_relaxed(&allocator_out_of_memory, 1); +} + +bool AllocatorMayReturnNull() { + return atomic_load(&allocator_may_return_null, memory_order_relaxed); +} + +void SetAllocatorMayReturnNull(bool may_return_null) { + atomic_store(&allocator_may_return_null, may_return_null, + memory_order_relaxed); +} + +void PrintHintAllocatorCannotReturnNull() { + Report("HINT: if you don't care about these errors you may set " + "allocator_may_return_null=1\n"); +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_allocator_checks.cc b/lib/sanitizer_common/sanitizer_allocator_checks.cc deleted file mode 100644 index bb56010f1074..000000000000 --- a/lib/sanitizer_common/sanitizer_allocator_checks.cc +++ /dev/null @@ -1,22 +0,0 @@ -//===-- sanitizer_allocator_checks.cc ---------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Various checks shared between ThreadSanitizer, MemorySanitizer, etc. memory -// allocators. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_errno.h" - -namespace __sanitizer { - -void SetErrnoToENOMEM() { - errno = errno_ENOMEM; -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_allocator_checks.cpp b/lib/sanitizer_common/sanitizer_allocator_checks.cpp new file mode 100644 index 000000000000..9d67f679b56c --- /dev/null +++ b/lib/sanitizer_common/sanitizer_allocator_checks.cpp @@ -0,0 +1,22 @@ +//===-- sanitizer_allocator_checks.cpp --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Various checks shared between ThreadSanitizer, MemorySanitizer, etc. memory +// allocators. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_errno.h" + +namespace __sanitizer { + +void SetErrnoToENOMEM() { + errno = errno_ENOMEM; +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_allocator_checks.h b/lib/sanitizer_common/sanitizer_allocator_checks.h index f436ce9ecdea..fc426f0e74f4 100644 --- a/lib/sanitizer_common/sanitizer_allocator_checks.h +++ b/lib/sanitizer_common/sanitizer_allocator_checks.h @@ -54,7 +54,7 @@ INLINE bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) { // and a multiple of sizeof(void *). INLINE bool CheckPosixMemalignAlignment(uptr alignment) { return alignment != 0 && IsPowerOfTwo(alignment) && - (alignment % sizeof(void *)) == 0; // NOLINT + (alignment % sizeof(void *)) == 0; } // Returns true if calloc(size, n) call overflows on size*n calculation. diff --git a/lib/sanitizer_common/sanitizer_allocator_report.cc b/lib/sanitizer_common/sanitizer_allocator_report.cc deleted file mode 100644 index dfc418166556..000000000000 --- a/lib/sanitizer_common/sanitizer_allocator_report.cc +++ /dev/null @@ -1,136 +0,0 @@ -//===-- sanitizer_allocator_report.cc ---------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Shared allocator error reporting for ThreadSanitizer, MemorySanitizer, etc. -/// -//===----------------------------------------------------------------------===// - -#include "sanitizer_allocator.h" -#include "sanitizer_allocator_report.h" -#include "sanitizer_common.h" -#include "sanitizer_report_decorator.h" - -namespace __sanitizer { - -class ScopedAllocatorErrorReport { - public: - ScopedAllocatorErrorReport(const char *error_summary_, - const StackTrace *stack_) - : error_summary(error_summary_), - stack(stack_) { - Printf("%s", d.Error()); - } - ~ScopedAllocatorErrorReport() { - Printf("%s", d.Default()); - stack->Print(); - PrintHintAllocatorCannotReturnNull(); - ReportErrorSummary(error_summary, stack); - } - - private: - ScopedErrorReportLock lock; - const char *error_summary; - const StackTrace* const stack; - const SanitizerCommonDecorator d; -}; - -void NORETURN ReportCallocOverflow(uptr count, uptr size, - const StackTrace *stack) { - { - ScopedAllocatorErrorReport report("calloc-overflow", stack); - Report("ERROR: %s: calloc parameters overflow: count * size (%zd * %zd) " - "cannot be represented in type size_t\n", SanitizerToolName, count, - size); - } - Die(); -} - -void NORETURN ReportReallocArrayOverflow(uptr count, uptr size, - const StackTrace *stack) { - { - ScopedAllocatorErrorReport report("reallocarray-overflow", stack); - Report( - "ERROR: %s: reallocarray parameters overflow: count * size (%zd * %zd) " - "cannot be represented in type size_t\n", - SanitizerToolName, count, size); - } - Die(); -} - -void NORETURN ReportPvallocOverflow(uptr size, const StackTrace *stack) { - { - ScopedAllocatorErrorReport report("pvalloc-overflow", stack); - Report("ERROR: %s: pvalloc parameters overflow: size 0x%zx rounded up to " - "system page size 0x%zx cannot be represented in type size_t\n", - SanitizerToolName, size, GetPageSizeCached()); - } - Die(); -} - -void NORETURN ReportInvalidAllocationAlignment(uptr alignment, - const StackTrace *stack) { - { - ScopedAllocatorErrorReport report("invalid-allocation-alignment", stack); - Report("ERROR: %s: invalid allocation alignment: %zd, alignment must be a " - "power of two\n", SanitizerToolName, alignment); - } - Die(); -} - -void NORETURN ReportInvalidAlignedAllocAlignment(uptr size, uptr alignment, - const StackTrace *stack) { - { - ScopedAllocatorErrorReport report("invalid-aligned-alloc-alignment", stack); -#if SANITIZER_POSIX - Report("ERROR: %s: invalid alignment requested in " - "aligned_alloc: %zd, alignment must be a power of two and the " - "requested size 0x%zx must be a multiple of alignment\n", - SanitizerToolName, alignment, size); -#else - Report("ERROR: %s: invalid alignment requested in aligned_alloc: %zd, " - "the requested size 0x%zx must be a multiple of alignment\n", - SanitizerToolName, alignment, size); -#endif - } - Die(); -} - -void NORETURN ReportInvalidPosixMemalignAlignment(uptr alignment, - const StackTrace *stack) { - { - ScopedAllocatorErrorReport report("invalid-posix-memalign-alignment", - stack); - Report("ERROR: %s: invalid alignment requested in " - "posix_memalign: %zd, alignment must be a power of two and a " - "multiple of sizeof(void*) == %zd\n", SanitizerToolName, alignment, - sizeof(void*)); // NOLINT - } - Die(); -} - -void NORETURN ReportAllocationSizeTooBig(uptr user_size, uptr max_size, - const StackTrace *stack) { - { - ScopedAllocatorErrorReport report("allocation-size-too-big", stack); - Report("ERROR: %s: requested allocation size 0x%zx exceeds maximum " - "supported size of 0x%zx\n", SanitizerToolName, user_size, max_size); - } - Die(); -} - -void NORETURN ReportOutOfMemory(uptr requested_size, const StackTrace *stack) { - { - ScopedAllocatorErrorReport report("out-of-memory", stack); - Report("ERROR: %s: allocator is out of memory trying to allocate 0x%zx " - "bytes\n", SanitizerToolName, requested_size); - } - Die(); -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_allocator_report.cpp b/lib/sanitizer_common/sanitizer_allocator_report.cpp new file mode 100644 index 000000000000..d74e08010d5d --- /dev/null +++ b/lib/sanitizer_common/sanitizer_allocator_report.cpp @@ -0,0 +1,137 @@ +//===-- sanitizer_allocator_report.cpp --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Shared allocator error reporting for ThreadSanitizer, MemorySanitizer, etc. +/// +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator.h" +#include "sanitizer_allocator_report.h" +#include "sanitizer_common.h" +#include "sanitizer_report_decorator.h" + +namespace __sanitizer { + +class ScopedAllocatorErrorReport { + public: + ScopedAllocatorErrorReport(const char *error_summary_, + const StackTrace *stack_) + : error_summary(error_summary_), + stack(stack_) { + Printf("%s", d.Error()); + } + ~ScopedAllocatorErrorReport() { + Printf("%s", d.Default()); + stack->Print(); + PrintHintAllocatorCannotReturnNull(); + ReportErrorSummary(error_summary, stack); + } + + private: + ScopedErrorReportLock lock; + const char *error_summary; + const StackTrace* const stack; + const SanitizerCommonDecorator d; +}; + +void NORETURN ReportCallocOverflow(uptr count, uptr size, + const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("calloc-overflow", stack); + Report("ERROR: %s: calloc parameters overflow: count * size (%zd * %zd) " + "cannot be represented in type size_t\n", SanitizerToolName, count, + size); + } + Die(); +} + +void NORETURN ReportReallocArrayOverflow(uptr count, uptr size, + const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("reallocarray-overflow", stack); + Report( + "ERROR: %s: reallocarray parameters overflow: count * size (%zd * %zd) " + "cannot be represented in type size_t\n", + SanitizerToolName, count, size); + } + Die(); +} + +void NORETURN ReportPvallocOverflow(uptr size, const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("pvalloc-overflow", stack); + Report("ERROR: %s: pvalloc parameters overflow: size 0x%zx rounded up to " + "system page size 0x%zx cannot be represented in type size_t\n", + SanitizerToolName, size, GetPageSizeCached()); + } + Die(); +} + +void NORETURN ReportInvalidAllocationAlignment(uptr alignment, + const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("invalid-allocation-alignment", stack); + Report("ERROR: %s: invalid allocation alignment: %zd, alignment must be a " + "power of two\n", SanitizerToolName, alignment); + } + Die(); +} + +void NORETURN ReportInvalidAlignedAllocAlignment(uptr size, uptr alignment, + const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("invalid-aligned-alloc-alignment", stack); +#if SANITIZER_POSIX + Report("ERROR: %s: invalid alignment requested in " + "aligned_alloc: %zd, alignment must be a power of two and the " + "requested size 0x%zx must be a multiple of alignment\n", + SanitizerToolName, alignment, size); +#else + Report("ERROR: %s: invalid alignment requested in aligned_alloc: %zd, " + "the requested size 0x%zx must be a multiple of alignment\n", + SanitizerToolName, alignment, size); +#endif + } + Die(); +} + +void NORETURN ReportInvalidPosixMemalignAlignment(uptr alignment, + const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("invalid-posix-memalign-alignment", + stack); + Report( + "ERROR: %s: invalid alignment requested in " + "posix_memalign: %zd, alignment must be a power of two and a " + "multiple of sizeof(void*) == %zd\n", + SanitizerToolName, alignment, sizeof(void *)); + } + Die(); +} + +void NORETURN ReportAllocationSizeTooBig(uptr user_size, uptr max_size, + const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("allocation-size-too-big", stack); + Report("ERROR: %s: requested allocation size 0x%zx exceeds maximum " + "supported size of 0x%zx\n", SanitizerToolName, user_size, max_size); + } + Die(); +} + +void NORETURN ReportOutOfMemory(uptr requested_size, const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("out-of-memory", stack); + Report("ERROR: %s: allocator is out of memory trying to allocate 0x%zx " + "bytes\n", SanitizerToolName, requested_size); + } + Die(); +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_asm.h b/lib/sanitizer_common/sanitizer_asm.h index 184d118d97d8..803af3285e18 100644 --- a/lib/sanitizer_common/sanitizer_asm.h +++ b/lib/sanitizer_common/sanitizer_asm.h @@ -60,7 +60,9 @@ #if defined(__ELF__) && (defined(__GNU__) || defined(__FreeBSD__) || \ defined(__Fuchsia__) || defined(__linux__)) -#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits // NOLINT +// clang-format off +#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits // NOLINT +// clang-format on #else #define NO_EXEC_STACK_DIRECTIVE #endif diff --git a/lib/sanitizer_common/sanitizer_atomic_msvc.h b/lib/sanitizer_common/sanitizer_atomic_msvc.h index a249657d6617..6a7c5465dcbb 100644 --- a/lib/sanitizer_common/sanitizer_atomic_msvc.h +++ b/lib/sanitizer_common/sanitizer_atomic_msvc.h @@ -20,44 +20,35 @@ extern "C" void _mm_mfence(); #pragma intrinsic(_mm_mfence) extern "C" void _mm_pause(); #pragma intrinsic(_mm_pause) -extern "C" char _InterlockedExchange8( // NOLINT - char volatile *Addend, char Value); // NOLINT +extern "C" char _InterlockedExchange8(char volatile *Addend, char Value); #pragma intrinsic(_InterlockedExchange8) -extern "C" short _InterlockedExchange16( // NOLINT - short volatile *Addend, short Value); // NOLINT +extern "C" short _InterlockedExchange16(short volatile *Addend, short Value); #pragma intrinsic(_InterlockedExchange16) -extern "C" long _InterlockedExchange( // NOLINT - long volatile *Addend, long Value); // NOLINT +extern "C" long _InterlockedExchange(long volatile *Addend, long Value); #pragma intrinsic(_InterlockedExchange) -extern "C" long _InterlockedExchangeAdd( // NOLINT - long volatile * Addend, long Value); // NOLINT +extern "C" long _InterlockedExchangeAdd(long volatile *Addend, long Value); #pragma intrinsic(_InterlockedExchangeAdd) -extern "C" char _InterlockedCompareExchange8( // NOLINT - char volatile *Destination, // NOLINT - char Exchange, char Comparand); // NOLINT +extern "C" char _InterlockedCompareExchange8(char volatile *Destination, + char Exchange, char Comparand); #pragma intrinsic(_InterlockedCompareExchange8) -extern "C" short _InterlockedCompareExchange16( // NOLINT - short volatile *Destination, // NOLINT - short Exchange, short Comparand); // NOLINT +extern "C" short _InterlockedCompareExchange16(short volatile *Destination, + short Exchange, short Comparand); #pragma intrinsic(_InterlockedCompareExchange16) -extern "C" -long long _InterlockedCompareExchange64( // NOLINT - long long volatile *Destination, // NOLINT - long long Exchange, long long Comparand); // NOLINT +extern "C" long long _InterlockedCompareExchange64( + long long volatile *Destination, long long Exchange, long long Comparand); #pragma intrinsic(_InterlockedCompareExchange64) extern "C" void *_InterlockedCompareExchangePointer( void *volatile *Destination, void *Exchange, void *Comparand); #pragma intrinsic(_InterlockedCompareExchangePointer) -extern "C" -long __cdecl _InterlockedCompareExchange( // NOLINT - long volatile *Destination, // NOLINT - long Exchange, long Comparand); // NOLINT +extern "C" long __cdecl _InterlockedCompareExchange(long volatile *Destination, + long Exchange, + long Comparand); #pragma intrinsic(_InterlockedCompareExchange) #ifdef _WIN64 -extern "C" long long _InterlockedExchangeAdd64( // NOLINT - long long volatile * Addend, long long Value); // NOLINT +extern "C" long long _InterlockedExchangeAdd64(long long volatile *Addend, + long long Value); #pragma intrinsic(_InterlockedExchangeAdd64) #endif @@ -115,8 +106,8 @@ INLINE u32 atomic_fetch_add(volatile atomic_uint32_t *a, u32 v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); - return (u32)_InterlockedExchangeAdd( - (volatile long*)&a->val_dont_use, (long)v); // NOLINT + return (u32)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use, + (long)v); } INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a, @@ -124,11 +115,11 @@ INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a, (void)mo; DCHECK(!((uptr)a % sizeof(*a))); #ifdef _WIN64 - return (uptr)_InterlockedExchangeAdd64( - (volatile long long*)&a->val_dont_use, (long long)v); // NOLINT + return (uptr)_InterlockedExchangeAdd64((volatile long long *)&a->val_dont_use, + (long long)v); #else - return (uptr)_InterlockedExchangeAdd( - (volatile long*)&a->val_dont_use, (long)v); // NOLINT + return (uptr)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use, + (long)v); #endif } @@ -136,8 +127,8 @@ INLINE u32 atomic_fetch_sub(volatile atomic_uint32_t *a, u32 v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); - return (u32)_InterlockedExchangeAdd( - (volatile long*)&a->val_dont_use, -(long)v); // NOLINT + return (u32)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use, + -(long)v); } INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a, @@ -145,11 +136,11 @@ INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a, (void)mo; DCHECK(!((uptr)a % sizeof(*a))); #ifdef _WIN64 - return (uptr)_InterlockedExchangeAdd64( - (volatile long long*)&a->val_dont_use, -(long long)v); // NOLINT + return (uptr)_InterlockedExchangeAdd64((volatile long long *)&a->val_dont_use, + -(long long)v); #else - return (uptr)_InterlockedExchangeAdd( - (volatile long*)&a->val_dont_use, -(long)v); // NOLINT + return (uptr)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use, + -(long)v); #endif } diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc deleted file mode 100644 index 80fb8f60fc0b..000000000000 --- a/lib/sanitizer_common/sanitizer_common.cc +++ /dev/null @@ -1,346 +0,0 @@ -//===-- sanitizer_common.cc -----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. -//===----------------------------------------------------------------------===// - -#include "sanitizer_common.h" -#include "sanitizer_allocator_interface.h" -#include "sanitizer_allocator_internal.h" -#include "sanitizer_atomic.h" -#include "sanitizer_flags.h" -#include "sanitizer_libc.h" -#include "sanitizer_placement_new.h" - -namespace __sanitizer { - -const char *SanitizerToolName = "SanitizerTool"; - -atomic_uint32_t current_verbosity; -uptr PageSizeCached; -u32 NumberOfCPUsCached; - -// PID of the tracer task in StopTheWorld. It shares the address space with the -// main process, but has a different PID and thus requires special handling. -uptr stoptheworld_tracer_pid = 0; -// Cached pid of parent process - if the parent process dies, we want to keep -// writing to the same log file. -uptr stoptheworld_tracer_ppid = 0; - -void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type, - const char *mmap_type, error_t err, - bool raw_report) { - static int recursion_count; - if (SANITIZER_RTEMS || raw_report || recursion_count) { - // If we are on RTEMS or raw report is requested or we went into recursion, - // just die. The Report() and CHECK calls below may call mmap recursively - // and fail. - RawWrite("ERROR: Failed to mmap\n"); - Die(); - } - recursion_count++; - Report("ERROR: %s failed to " - "%s 0x%zx (%zd) bytes of %s (error code: %d)\n", - SanitizerToolName, mmap_type, size, size, mem_type, err); -#if !SANITIZER_GO - DumpProcessMap(); -#endif - UNREACHABLE("unable to mmap"); -} - -typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); -typedef bool U32ComparisonFunction(const u32 &a, const u32 &b); - -const char *StripPathPrefix(const char *filepath, - const char *strip_path_prefix) { - if (!filepath) return nullptr; - if (!strip_path_prefix) return filepath; - const char *res = filepath; - if (const char *pos = internal_strstr(filepath, strip_path_prefix)) - res = pos + internal_strlen(strip_path_prefix); - if (res[0] == '.' && res[1] == '/') - res += 2; - return res; -} - -const char *StripModuleName(const char *module) { - if (!module) - return nullptr; - if (SANITIZER_WINDOWS) { - // On Windows, both slash and backslash are possible. - // Pick the one that goes last. - if (const char *bslash_pos = internal_strrchr(module, '\\')) - return StripModuleName(bslash_pos + 1); - } - if (const char *slash_pos = internal_strrchr(module, '/')) { - return slash_pos + 1; - } - return module; -} - -void ReportErrorSummary(const char *error_message, const char *alt_tool_name) { - if (!common_flags()->print_summary) - return; - InternalScopedString buff(kMaxSummaryLength); - buff.append("SUMMARY: %s: %s", - alt_tool_name ? alt_tool_name : SanitizerToolName, error_message); - __sanitizer_report_error_summary(buff.data()); -} - -// Removes the ANSI escape sequences from the input string (in-place). -void RemoveANSIEscapeSequencesFromString(char *str) { - if (!str) - return; - - // We are going to remove the escape sequences in place. - char *s = str; - char *z = str; - while (*s != '\0') { - CHECK_GE(s, z); - // Skip over ANSI escape sequences with pointer 's'. - if (*s == '\033' && *(s + 1) == '[') { - s = internal_strchrnul(s, 'm'); - if (*s == '\0') { - break; - } - s++; - continue; - } - // 's' now points at a character we want to keep. Copy over the buffer - // content if the escape sequence has been perviously skipped andadvance - // both pointers. - if (s != z) - *z = *s; - - // If we have not seen an escape sequence, just advance both pointers. - z++; - s++; - } - - // Null terminate the string. - *z = '\0'; -} - -void LoadedModule::set(const char *module_name, uptr base_address) { - clear(); - full_name_ = internal_strdup(module_name); - base_address_ = base_address; -} - -void LoadedModule::set(const char *module_name, uptr base_address, - ModuleArch arch, u8 uuid[kModuleUUIDSize], - bool instrumented) { - set(module_name, base_address); - arch_ = arch; - internal_memcpy(uuid_, uuid, sizeof(uuid_)); - instrumented_ = instrumented; -} - -void LoadedModule::clear() { - InternalFree(full_name_); - base_address_ = 0; - max_executable_address_ = 0; - full_name_ = nullptr; - arch_ = kModuleArchUnknown; - internal_memset(uuid_, 0, kModuleUUIDSize); - instrumented_ = false; - while (!ranges_.empty()) { - AddressRange *r = ranges_.front(); - ranges_.pop_front(); - InternalFree(r); - } -} - -void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable, - bool writable, const char *name) { - void *mem = InternalAlloc(sizeof(AddressRange)); - AddressRange *r = - new(mem) AddressRange(beg, end, executable, writable, name); - ranges_.push_back(r); - if (executable && end > max_executable_address_) - max_executable_address_ = end; -} - -bool LoadedModule::containsAddress(uptr address) const { - for (const AddressRange &r : ranges()) { - if (r.beg <= address && address < r.end) - return true; - } - return false; -} - -static atomic_uintptr_t g_total_mmaped; - -void IncreaseTotalMmap(uptr size) { - if (!common_flags()->mmap_limit_mb) return; - uptr total_mmaped = - atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size; - // Since for now mmap_limit_mb is not a user-facing flag, just kill - // a program. Use RAW_CHECK to avoid extra mmaps in reporting. - RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb); -} - -void DecreaseTotalMmap(uptr size) { - if (!common_flags()->mmap_limit_mb) return; - atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed); -} - -bool TemplateMatch(const char *templ, const char *str) { - if ((!str) || str[0] == 0) - return false; - bool start = false; - if (templ && templ[0] == '^') { - start = true; - templ++; - } - bool asterisk = false; - while (templ && templ[0]) { - if (templ[0] == '*') { - templ++; - start = false; - asterisk = true; - continue; - } - if (templ[0] == '$') - return str[0] == 0 || asterisk; - if (str[0] == 0) - return false; - char *tpos = (char*)internal_strchr(templ, '*'); - char *tpos1 = (char*)internal_strchr(templ, '$'); - if ((!tpos) || (tpos1 && tpos1 < tpos)) - tpos = tpos1; - if (tpos) - tpos[0] = 0; - const char *str0 = str; - const char *spos = internal_strstr(str, templ); - str = spos + internal_strlen(templ); - templ = tpos; - if (tpos) - tpos[0] = tpos == tpos1 ? '$' : '*'; - if (!spos) - return false; - if (start && spos != str0) - return false; - start = false; - asterisk = false; - } - return true; -} - -static char binary_name_cache_str[kMaxPathLength]; -static char process_name_cache_str[kMaxPathLength]; - -const char *GetProcessName() { - return process_name_cache_str; -} - -static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) { - ReadLongProcessName(buf, buf_len); - char *s = const_cast(StripModuleName(buf)); - uptr len = internal_strlen(s); - if (s != buf) { - internal_memmove(buf, s, len); - buf[len] = '\0'; - } - return len; -} - -void UpdateProcessName() { - ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); -} - -// Call once to make sure that binary_name_cache_str is initialized -void CacheBinaryName() { - if (binary_name_cache_str[0] != '\0') - return; - ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str)); - ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); -} - -uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) { - CacheBinaryName(); - uptr name_len = internal_strlen(binary_name_cache_str); - name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1; - if (buf_len == 0) - return 0; - internal_memcpy(buf, binary_name_cache_str, name_len); - buf[name_len] = '\0'; - return name_len; -} - -void PrintCmdline() { - char **argv = GetArgv(); - if (!argv) return; - Printf("\nCommand: "); - for (uptr i = 0; argv[i]; ++i) - Printf("%s ", argv[i]); - Printf("\n\n"); -} - -// Malloc hooks. -static const int kMaxMallocFreeHooks = 5; -struct MallocFreeHook { - void (*malloc_hook)(const void *, uptr); - void (*free_hook)(const void *); -}; - -static MallocFreeHook MFHooks[kMaxMallocFreeHooks]; - -void RunMallocHooks(const void *ptr, uptr size) { - for (int i = 0; i < kMaxMallocFreeHooks; i++) { - auto hook = MFHooks[i].malloc_hook; - if (!hook) return; - hook(ptr, size); - } -} - -void RunFreeHooks(const void *ptr) { - for (int i = 0; i < kMaxMallocFreeHooks; i++) { - auto hook = MFHooks[i].free_hook; - if (!hook) return; - hook(ptr); - } -} - -static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr), - void (*free_hook)(const void *)) { - if (!malloc_hook || !free_hook) return 0; - for (int i = 0; i < kMaxMallocFreeHooks; i++) { - if (MFHooks[i].malloc_hook == nullptr) { - MFHooks[i].malloc_hook = malloc_hook; - MFHooks[i].free_hook = free_hook; - return i + 1; - } - } - return 0; -} - -} // namespace __sanitizer - -using namespace __sanitizer; // NOLINT - -extern "C" { -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary, - const char *error_summary) { - Printf("%s\n", error_summary); -} - -SANITIZER_INTERFACE_ATTRIBUTE -int __sanitizer_acquire_crash_state() { - static atomic_uint8_t in_crash_state = {}; - return !atomic_exchange(&in_crash_state, 1, memory_order_relaxed); -} - -SANITIZER_INTERFACE_ATTRIBUTE -int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *, - uptr), - void (*free_hook)(const void *)) { - return InstallMallocFreeHooks(malloc_hook, free_hook); -} -} // extern "C" diff --git a/lib/sanitizer_common/sanitizer_common.cpp b/lib/sanitizer_common/sanitizer_common.cpp new file mode 100644 index 000000000000..f5f9f49d8cff --- /dev/null +++ b/lib/sanitizer_common/sanitizer_common.cpp @@ -0,0 +1,346 @@ +//===-- sanitizer_common.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common.h" +#include "sanitizer_allocator_interface.h" +#include "sanitizer_allocator_internal.h" +#include "sanitizer_atomic.h" +#include "sanitizer_flags.h" +#include "sanitizer_libc.h" +#include "sanitizer_placement_new.h" + +namespace __sanitizer { + +const char *SanitizerToolName = "SanitizerTool"; + +atomic_uint32_t current_verbosity; +uptr PageSizeCached; +u32 NumberOfCPUsCached; + +// PID of the tracer task in StopTheWorld. It shares the address space with the +// main process, but has a different PID and thus requires special handling. +uptr stoptheworld_tracer_pid = 0; +// Cached pid of parent process - if the parent process dies, we want to keep +// writing to the same log file. +uptr stoptheworld_tracer_ppid = 0; + +void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type, + const char *mmap_type, error_t err, + bool raw_report) { + static int recursion_count; + if (SANITIZER_RTEMS || raw_report || recursion_count) { + // If we are on RTEMS or raw report is requested or we went into recursion, + // just die. The Report() and CHECK calls below may call mmap recursively + // and fail. + RawWrite("ERROR: Failed to mmap\n"); + Die(); + } + recursion_count++; + Report("ERROR: %s failed to " + "%s 0x%zx (%zd) bytes of %s (error code: %d)\n", + SanitizerToolName, mmap_type, size, size, mem_type, err); +#if !SANITIZER_GO + DumpProcessMap(); +#endif + UNREACHABLE("unable to mmap"); +} + +typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); +typedef bool U32ComparisonFunction(const u32 &a, const u32 &b); + +const char *StripPathPrefix(const char *filepath, + const char *strip_path_prefix) { + if (!filepath) return nullptr; + if (!strip_path_prefix) return filepath; + const char *res = filepath; + if (const char *pos = internal_strstr(filepath, strip_path_prefix)) + res = pos + internal_strlen(strip_path_prefix); + if (res[0] == '.' && res[1] == '/') + res += 2; + return res; +} + +const char *StripModuleName(const char *module) { + if (!module) + return nullptr; + if (SANITIZER_WINDOWS) { + // On Windows, both slash and backslash are possible. + // Pick the one that goes last. + if (const char *bslash_pos = internal_strrchr(module, '\\')) + return StripModuleName(bslash_pos + 1); + } + if (const char *slash_pos = internal_strrchr(module, '/')) { + return slash_pos + 1; + } + return module; +} + +void ReportErrorSummary(const char *error_message, const char *alt_tool_name) { + if (!common_flags()->print_summary) + return; + InternalScopedString buff(kMaxSummaryLength); + buff.append("SUMMARY: %s: %s", + alt_tool_name ? alt_tool_name : SanitizerToolName, error_message); + __sanitizer_report_error_summary(buff.data()); +} + +// Removes the ANSI escape sequences from the input string (in-place). +void RemoveANSIEscapeSequencesFromString(char *str) { + if (!str) + return; + + // We are going to remove the escape sequences in place. + char *s = str; + char *z = str; + while (*s != '\0') { + CHECK_GE(s, z); + // Skip over ANSI escape sequences with pointer 's'. + if (*s == '\033' && *(s + 1) == '[') { + s = internal_strchrnul(s, 'm'); + if (*s == '\0') { + break; + } + s++; + continue; + } + // 's' now points at a character we want to keep. Copy over the buffer + // content if the escape sequence has been perviously skipped andadvance + // both pointers. + if (s != z) + *z = *s; + + // If we have not seen an escape sequence, just advance both pointers. + z++; + s++; + } + + // Null terminate the string. + *z = '\0'; +} + +void LoadedModule::set(const char *module_name, uptr base_address) { + clear(); + full_name_ = internal_strdup(module_name); + base_address_ = base_address; +} + +void LoadedModule::set(const char *module_name, uptr base_address, + ModuleArch arch, u8 uuid[kModuleUUIDSize], + bool instrumented) { + set(module_name, base_address); + arch_ = arch; + internal_memcpy(uuid_, uuid, sizeof(uuid_)); + instrumented_ = instrumented; +} + +void LoadedModule::clear() { + InternalFree(full_name_); + base_address_ = 0; + max_executable_address_ = 0; + full_name_ = nullptr; + arch_ = kModuleArchUnknown; + internal_memset(uuid_, 0, kModuleUUIDSize); + instrumented_ = false; + while (!ranges_.empty()) { + AddressRange *r = ranges_.front(); + ranges_.pop_front(); + InternalFree(r); + } +} + +void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable, + bool writable, const char *name) { + void *mem = InternalAlloc(sizeof(AddressRange)); + AddressRange *r = + new(mem) AddressRange(beg, end, executable, writable, name); + ranges_.push_back(r); + if (executable && end > max_executable_address_) + max_executable_address_ = end; +} + +bool LoadedModule::containsAddress(uptr address) const { + for (const AddressRange &r : ranges()) { + if (r.beg <= address && address < r.end) + return true; + } + return false; +} + +static atomic_uintptr_t g_total_mmaped; + +void IncreaseTotalMmap(uptr size) { + if (!common_flags()->mmap_limit_mb) return; + uptr total_mmaped = + atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size; + // Since for now mmap_limit_mb is not a user-facing flag, just kill + // a program. Use RAW_CHECK to avoid extra mmaps in reporting. + RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb); +} + +void DecreaseTotalMmap(uptr size) { + if (!common_flags()->mmap_limit_mb) return; + atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed); +} + +bool TemplateMatch(const char *templ, const char *str) { + if ((!str) || str[0] == 0) + return false; + bool start = false; + if (templ && templ[0] == '^') { + start = true; + templ++; + } + bool asterisk = false; + while (templ && templ[0]) { + if (templ[0] == '*') { + templ++; + start = false; + asterisk = true; + continue; + } + if (templ[0] == '$') + return str[0] == 0 || asterisk; + if (str[0] == 0) + return false; + char *tpos = (char*)internal_strchr(templ, '*'); + char *tpos1 = (char*)internal_strchr(templ, '$'); + if ((!tpos) || (tpos1 && tpos1 < tpos)) + tpos = tpos1; + if (tpos) + tpos[0] = 0; + const char *str0 = str; + const char *spos = internal_strstr(str, templ); + str = spos + internal_strlen(templ); + templ = tpos; + if (tpos) + tpos[0] = tpos == tpos1 ? '$' : '*'; + if (!spos) + return false; + if (start && spos != str0) + return false; + start = false; + asterisk = false; + } + return true; +} + +static char binary_name_cache_str[kMaxPathLength]; +static char process_name_cache_str[kMaxPathLength]; + +const char *GetProcessName() { + return process_name_cache_str; +} + +static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) { + ReadLongProcessName(buf, buf_len); + char *s = const_cast(StripModuleName(buf)); + uptr len = internal_strlen(s); + if (s != buf) { + internal_memmove(buf, s, len); + buf[len] = '\0'; + } + return len; +} + +void UpdateProcessName() { + ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); +} + +// Call once to make sure that binary_name_cache_str is initialized +void CacheBinaryName() { + if (binary_name_cache_str[0] != '\0') + return; + ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str)); + ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); +} + +uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) { + CacheBinaryName(); + uptr name_len = internal_strlen(binary_name_cache_str); + name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1; + if (buf_len == 0) + return 0; + internal_memcpy(buf, binary_name_cache_str, name_len); + buf[name_len] = '\0'; + return name_len; +} + +void PrintCmdline() { + char **argv = GetArgv(); + if (!argv) return; + Printf("\nCommand: "); + for (uptr i = 0; argv[i]; ++i) + Printf("%s ", argv[i]); + Printf("\n\n"); +} + +// Malloc hooks. +static const int kMaxMallocFreeHooks = 5; +struct MallocFreeHook { + void (*malloc_hook)(const void *, uptr); + void (*free_hook)(const void *); +}; + +static MallocFreeHook MFHooks[kMaxMallocFreeHooks]; + +void RunMallocHooks(const void *ptr, uptr size) { + for (int i = 0; i < kMaxMallocFreeHooks; i++) { + auto hook = MFHooks[i].malloc_hook; + if (!hook) return; + hook(ptr, size); + } +} + +void RunFreeHooks(const void *ptr) { + for (int i = 0; i < kMaxMallocFreeHooks; i++) { + auto hook = MFHooks[i].free_hook; + if (!hook) return; + hook(ptr); + } +} + +static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr), + void (*free_hook)(const void *)) { + if (!malloc_hook || !free_hook) return 0; + for (int i = 0; i < kMaxMallocFreeHooks; i++) { + if (MFHooks[i].malloc_hook == nullptr) { + MFHooks[i].malloc_hook = malloc_hook; + MFHooks[i].free_hook = free_hook; + return i + 1; + } + } + return 0; +} + +} // namespace __sanitizer + +using namespace __sanitizer; + +extern "C" { +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary, + const char *error_summary) { + Printf("%s\n", error_summary); +} + +SANITIZER_INTERFACE_ATTRIBUTE +int __sanitizer_acquire_crash_state() { + static atomic_uint8_t in_crash_state = {}; + return !atomic_exchange(&in_crash_state, 1, memory_order_relaxed); +} + +SANITIZER_INTERFACE_ATTRIBUTE +int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *, + uptr), + void (*free_hook)(const void *)) { + return InstallMallocFreeHooks(malloc_hook, free_hook); +} +} // extern "C" diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 1703899e32b5..87b8f02b5b73 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -100,6 +100,8 @@ void UnmapOrDie(void *addr, uptr size); void *MmapOrDieOnFatalError(uptr size, const char *mem_type); bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name = nullptr) WARN_UNUSED_RESULT; +bool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, + const char *name = nullptr) WARN_UNUSED_RESULT; void *MmapNoReserveOrDie(uptr size, const char *mem_type); void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name = nullptr); // Behaves just like MmapFixedOrDie, but tolerates out of memory condition, in @@ -131,7 +133,7 @@ void ReleaseMemoryPagesToOS(uptr beg, uptr end); void IncreaseTotalMmap(uptr size); void DecreaseTotalMmap(uptr size); uptr GetRSS(); -bool NoHugePagesInRegion(uptr addr, uptr length); +void SetShadowRegionHugePageMode(uptr addr, uptr length); bool DontDumpShadowMemory(uptr addr, uptr length); // Check if the built VMA size matches the runtime one. void CheckVMASize(); @@ -337,18 +339,18 @@ void ReportMmapWriteExec(int prot); // Math #if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__) extern "C" { -unsigned char _BitScanForward(unsigned long *index, unsigned long mask); // NOLINT -unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); // NOLINT +unsigned char _BitScanForward(unsigned long *index, unsigned long mask); +unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); #if defined(_WIN64) -unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask); // NOLINT -unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); // NOLINT +unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask); +unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); #endif } #endif INLINE uptr MostSignificantSetBitIndex(uptr x) { CHECK_NE(x, 0U); - unsigned long up; // NOLINT + unsigned long up; #if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) # ifdef _WIN64 up = SANITIZER_WORDSIZE - 1 - __builtin_clzll(x); @@ -365,7 +367,7 @@ INLINE uptr MostSignificantSetBitIndex(uptr x) { INLINE uptr LeastSignificantSetBitIndex(uptr x) { CHECK_NE(x, 0U); - unsigned long up; // NOLINT + unsigned long up; #if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) # ifdef _WIN64 up = __builtin_ctzll(x); @@ -669,7 +671,7 @@ bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, error_t *errno_p = nullptr); // When adding a new architecture, don't forget to also update -// script/asan_symbolize.py and sanitizer_symbolizer_libcdep.cc. +// script/asan_symbolize.py and sanitizer_symbolizer_libcdep.cpp. inline const char *ModuleArchToString(ModuleArch arch) { switch (arch) { case kModuleArchUnknown: @@ -879,6 +881,11 @@ struct SignalContext { bool is_memory_access; enum WriteFlag { UNKNOWN, READ, WRITE } write_flag; + // In some cases the kernel cannot provide the true faulting address; `addr` + // will be zero then. This field allows to distinguish between these cases + // and dereferences of null. + bool is_true_faulting_addr; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default // constructor SignalContext() = default; @@ -891,7 +898,8 @@ struct SignalContext { context(context), addr(GetAddress()), is_memory_access(IsMemoryAccess()), - write_flag(GetWriteFlag()) { + write_flag(GetWriteFlag()), + is_true_faulting_addr(IsTrueFaultingAddress()) { InitPcSpBp(); } @@ -912,6 +920,7 @@ struct SignalContext { uptr GetAddress() const; WriteFlag GetWriteFlag() const; bool IsMemoryAccess() const; + bool IsTrueFaultingAddress() const; }; void InitializePlatformEarly(); @@ -971,7 +980,7 @@ INLINE u32 GetNumberOfCPUsCached() { } // namespace __sanitizer inline void *operator new(__sanitizer::operator_new_size_type size, - __sanitizer::LowLevelAllocator &alloc) { + __sanitizer::LowLevelAllocator &alloc) { // NOLINT return alloc.Allocate(size); } diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 9f5a91ac99dc..50e3558b52e8 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -36,6 +36,7 @@ // COMMON_INTERCEPTOR_MMAP_IMPL // COMMON_INTERCEPTOR_COPY_STRING // COMMON_INTERCEPTOR_STRNDUP_IMPL +// COMMON_INTERCEPTOR_STRERROR //===----------------------------------------------------------------------===// #include "interception/interception.h" @@ -301,6 +302,10 @@ bool PlatformHasDifferentMemcpyAndMemmove(); return new_mem; #endif +#ifndef COMMON_INTERCEPTOR_STRERROR +#define COMMON_INTERCEPTOR_STRERROR() {} +#endif + struct FileMetadata { // For open_memstream(). char **addr; @@ -317,11 +322,11 @@ struct CommonInterceptorMetadata { }; }; +#if SI_POSIX typedef AddrHashMap MetadataHashMap; static MetadataHashMap *interceptor_metadata_map; -#if SI_POSIX UNUSED static void SetInterceptorMetadata(__sanitizer_FILE *addr, const FileMetadata &file) { MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr); @@ -1241,8 +1246,9 @@ INTERCEPTOR_WITH_SUFFIX(int, fputs, char *s, void *file) { // libc file streams can call user-supplied functions, see fopencookie. void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, fputs, s, file); - if (!SANITIZER_MAC || s) + if (!SANITIZER_MAC || s) { // `fputs(NULL, file)` is supported on Darwin. COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1); + } return REAL(fputs)(s, file); } #define INIT_FPUTS COMMON_INTERCEPT_FUNCTION(fputs) @@ -1255,8 +1261,9 @@ INTERCEPTOR(int, puts, char *s) { // libc file streams can call user-supplied functions, see fopencookie. void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, puts, s); - if (!SANITIZER_MAC || s) + if (!SANITIZER_MAC || s) { // `puts(NULL)` is supported on Darwin. COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1); + } return REAL(puts)(s); } #define INIT_PUTS COMMON_INTERCEPT_FUNCTION(puts) @@ -1265,9 +1272,8 @@ INTERCEPTOR(int, puts, char *s) { #endif #if SANITIZER_INTERCEPT_PRCTL -INTERCEPTOR(int, prctl, int option, unsigned long arg2, - unsigned long arg3, // NOLINT - unsigned long arg4, unsigned long arg5) { // NOLINT +INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5); static const int PR_SET_NAME = 15; @@ -1699,13 +1705,13 @@ INTERCEPTOR(int, __fprintf_chk, __sanitizer_FILE *stream, SIZE_T size, FORMAT_INTERCEPTOR_IMPL(__fprintf_chk, vfprintf, stream, format) #endif -INTERCEPTOR(int, sprintf, char *str, const char *format, ...) // NOLINT -FORMAT_INTERCEPTOR_IMPL(sprintf, vsprintf, str, format) // NOLINT +INTERCEPTOR(int, sprintf, char *str, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(sprintf, vsprintf, str, format) #if SANITIZER_INTERCEPT___PRINTF_CHK INTERCEPTOR(int, __sprintf_chk, char *str, int flag, SIZE_T size_to, - const char *format, ...) // NOLINT -FORMAT_INTERCEPTOR_IMPL(__sprintf_chk, vsprintf, str, format) // NOLINT + const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(__sprintf_chk, vsprintf, str, format) #endif INTERCEPTOR(int, snprintf, char *str, SIZE_T size, const char *format, ...) @@ -1713,8 +1719,8 @@ FORMAT_INTERCEPTOR_IMPL(snprintf, vsnprintf, str, size, format) #if SANITIZER_INTERCEPT___PRINTF_CHK INTERCEPTOR(int, __snprintf_chk, char *str, SIZE_T size, int flag, - SIZE_T size_to, const char *format, ...) // NOLINT -FORMAT_INTERCEPTOR_IMPL(__snprintf_chk, vsnprintf, str, size, format) // NOLINT + SIZE_T size_to, const char *format, ...) +FORMAT_INTERCEPTOR_IMPL(__snprintf_chk, vsnprintf, str, size, format) #endif INTERCEPTOR(int, asprintf, char **strp, const char *format, ...) @@ -3069,13 +3075,14 @@ INTERCEPTOR(int, sendmmsg, int fd, struct __sanitizer_mmsghdr *msgvec, COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); } int res = REAL(sendmmsg)(fd, msgvec, vlen, flags); - if (res >= 0 && msgvec) + if (res >= 0 && msgvec) { for (int i = 0; i < res; ++i) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &msgvec[i].msg_len, sizeof(msgvec[i].msg_len)); if (common_flags()->intercept_send) read_msghdr(ctx, &msgvec[i].msg_hdr, msgvec[i].msg_len); } + } return res; } #define INIT_SENDMMSG COMMON_INTERCEPT_FUNCTION(sendmmsg); @@ -3206,20 +3213,21 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) { __sanitizer_iovec local_iovec; if (data) { - if (request == ptrace_setregs) + if (request == ptrace_setregs) { COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_regs_struct_sz); - else if (request == ptrace_setfpregs) + } else if (request == ptrace_setfpregs) { COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpregs_struct_sz); - else if (request == ptrace_setfpxregs) + } else if (request == ptrace_setfpxregs) { COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz); - else if (request == ptrace_setvfpregs) + } else if (request == ptrace_setvfpregs) { COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_vfpregs_struct_sz); - else if (request == ptrace_setsiginfo) + } else if (request == ptrace_setsiginfo) { COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz); + // Some kernel might zero the iovec::iov_base in case of invalid // write access. In this case copy the invalid address for further // inspection. - else if (request == ptrace_setregset || request == ptrace_getregset) { + } else if (request == ptrace_setregset || request == ptrace_getregset) { __sanitizer_iovec *iovec = (__sanitizer_iovec*)data; COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec)); local_iovec = *iovec; @@ -3236,19 +3244,19 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) { if (!res && data) { // Note that PEEK* requests assign different meaning to the return value. // This function does not handle them (nor does it need to). - if (request == ptrace_getregs) + if (request == ptrace_getregs) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_regs_struct_sz); - else if (request == ptrace_getfpregs) + } else if (request == ptrace_getfpregs) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpregs_struct_sz); - else if (request == ptrace_getfpxregs) + } else if (request == ptrace_getfpxregs) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_struct_sz); - else if (request == ptrace_getvfpregs) + } else if (request == ptrace_getvfpregs) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_vfpregs_struct_sz); - else if (request == ptrace_getsiginfo) + } else if (request == ptrace_getsiginfo) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, siginfo_t_sz); - else if (request == ptrace_geteventmsg) + } else if (request == ptrace_geteventmsg) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(unsigned long)); - else if (request == ptrace_getregset) { + } else if (request == ptrace_getregset) { __sanitizer_iovec *iovec = (__sanitizer_iovec*)data; COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec, sizeof(*iovec)); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, local_iovec.iov_base, @@ -3674,6 +3682,7 @@ INTERCEPTOR(int, sched_getparam, int pid, void *param) { INTERCEPTOR(char *, strerror, int errnum) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, strerror, errnum); + COMMON_INTERCEPTOR_STRERROR(); char *res = REAL(strerror)(errnum); if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); return res; @@ -6714,7 +6723,7 @@ INTERCEPTOR(wchar_t *, wcscat, wchar_t *dst, const wchar_t *src) { COMMON_INTERCEPTOR_READ_RANGE(ctx, dst, (dst_size + 1) * sizeof(wchar_t)); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst + dst_size, (src_size + 1) * sizeof(wchar_t)); - return REAL(wcscat)(dst, src); // NOLINT + return REAL(wcscat)(dst, src); } INTERCEPTOR(wchar_t *, wcsncat, wchar_t *dst, const wchar_t *src, SIZE_T n) { @@ -6727,7 +6736,7 @@ INTERCEPTOR(wchar_t *, wcsncat, wchar_t *dst, const wchar_t *src, SIZE_T n) { COMMON_INTERCEPTOR_READ_RANGE(ctx, dst, (dst_size + 1) * sizeof(wchar_t)); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst + dst_size, (src_size + 1) * sizeof(wchar_t)); - return REAL(wcsncat)(dst, src, n); // NOLINT + return REAL(wcsncat)(dst, src, n); } #define INIT_WCSCAT \ COMMON_INTERCEPT_FUNCTION(wcscat); \ @@ -7841,10 +7850,11 @@ INTERCEPTOR(int, modctl, int operation, void *argp) { if (iov) COMMON_INTERCEPTOR_WRITE_RANGE( ctx, iov->iov_base, Min(iov_len, iov->iov_len)); - } else if (operation == modctl_exists) + } else if (operation == modctl_exists) { ret = REAL(modctl)(operation, argp); - else + } else { ret = REAL(modctl)(operation, argp); + } return ret; } @@ -9548,10 +9558,76 @@ INTERCEPTOR(void, sl_free, void *sl, int freeall) { #define INIT_SL_INIT #endif +#if SANITIZER_INTERCEPT_GETRANDOM +INTERCEPTOR(SSIZE_T, getrandom, void *buf, SIZE_T buflen, unsigned int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getrandom, buf, buflen, flags); + SSIZE_T n = REAL(getrandom)(buf, buflen, flags); + if (n > 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, n); + } + return n; +} +#define INIT_GETRANDOM COMMON_INTERCEPT_FUNCTION(getrandom) +#else +#define INIT_GETRANDOM +#endif + +#if SANITIZER_INTERCEPT_CRYPT +INTERCEPTOR(char *, crypt, char *key, char *salt) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, crypt, key, salt); + COMMON_INTERCEPTOR_READ_RANGE(ctx, key, internal_strlen(key) + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, salt, internal_strlen(salt) + 1); + char *res = REAL(crypt)(key, salt); + if (res != nullptr) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + return res; +} +#define INIT_CRYPT COMMON_INTERCEPT_FUNCTION(crypt); +#else +#define INIT_CRYPT +#endif + +#if SANITIZER_INTERCEPT_CRYPT_R +INTERCEPTOR(char *, crypt_r, char *key, char *salt, void *data) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, crypt_r, key, salt, data); + COMMON_INTERCEPTOR_READ_RANGE(ctx, key, internal_strlen(key) + 1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, salt, internal_strlen(salt) + 1); + char *res = REAL(crypt_r)(key, salt, data); + if (res != nullptr) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, + __sanitizer::struct_crypt_data_sz); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); + } + return res; +} +#define INIT_CRYPT_R COMMON_INTERCEPT_FUNCTION(crypt_r); +#else +#define INIT_CRYPT_R +#endif + +#if SANITIZER_INTERCEPT_GETENTROPY +INTERCEPTOR(int, getentropy, void *buf, SIZE_T buflen) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getentropy, buf, buflen); + int r = REAL(getentropy)(buf, buflen); + if (r == 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen); + } + return r; +} +#define INIT_GETENTROPY COMMON_INTERCEPT_FUNCTION(getentropy) +#else +#define INIT_GETENTROPY +#endif + static void InitializeCommonInterceptors() { +#if SI_POSIX static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1]; - interceptor_metadata_map = - new ((void *)&metadata_mem) MetadataHashMap(); // NOLINT + interceptor_metadata_map = new ((void *)&metadata_mem) MetadataHashMap(); +#endif INIT_MMAP; INIT_MMAP64; @@ -9844,6 +9920,10 @@ static void InitializeCommonInterceptors() { INIT_FDEVNAME; INIT_GETUSERSHELL; INIT_SL_INIT; + INIT_GETRANDOM; + INIT_CRYPT; + INIT_CRYPT_R; + INIT_GETENTROPY; INIT___PRINTF_CHK; } diff --git a/lib/sanitizer_common/sanitizer_common_interface.inc b/lib/sanitizer_common/sanitizer_common_interface.inc index c72554973b05..c78b6e10b689 100644 --- a/lib/sanitizer_common/sanitizer_common_interface.inc +++ b/lib/sanitizer_common/sanitizer_common_interface.inc @@ -14,6 +14,7 @@ INTERFACE_FUNCTION(__sanitizer_set_death_callback) INTERFACE_FUNCTION(__sanitizer_set_report_path) INTERFACE_FUNCTION(__sanitizer_set_report_fd) INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container) +INTERFACE_WEAK_FUNCTION(__sanitizer_on_print) INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary) INTERFACE_WEAK_FUNCTION(__sanitizer_sandbox_on_notify) // Sanitizer weak hooks diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc deleted file mode 100644 index 363eb4c146ce..000000000000 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ /dev/null @@ -1,139 +0,0 @@ -//===-- sanitizer_common_libcdep.cc ---------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. -//===----------------------------------------------------------------------===// - -#include "sanitizer_allocator_interface.h" -#include "sanitizer_common.h" -#include "sanitizer_flags.h" -#include "sanitizer_procmaps.h" - - -namespace __sanitizer { - -static void (*SoftRssLimitExceededCallback)(bool exceeded); -void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) { - CHECK_EQ(SoftRssLimitExceededCallback, nullptr); - SoftRssLimitExceededCallback = Callback; -} - -#if (SANITIZER_LINUX || SANITIZER_NETBSD) && !SANITIZER_GO -// Weak default implementation for when sanitizer_stackdepot is not linked in. -SANITIZER_WEAK_ATTRIBUTE StackDepotStats *StackDepotGetStats() { - return nullptr; -} - -void BackgroundThread(void *arg) { - const uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb; - const uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb; - const bool heap_profile = common_flags()->heap_profile; - uptr prev_reported_rss = 0; - uptr prev_reported_stack_depot_size = 0; - bool reached_soft_rss_limit = false; - uptr rss_during_last_reported_profile = 0; - while (true) { - SleepForMillis(100); - const uptr current_rss_mb = GetRSS() >> 20; - if (Verbosity()) { - // If RSS has grown 10% since last time, print some information. - if (prev_reported_rss * 11 / 10 < current_rss_mb) { - Printf("%s: RSS: %zdMb\n", SanitizerToolName, current_rss_mb); - prev_reported_rss = current_rss_mb; - } - // If stack depot has grown 10% since last time, print it too. - StackDepotStats *stack_depot_stats = StackDepotGetStats(); - if (stack_depot_stats) { - if (prev_reported_stack_depot_size * 11 / 10 < - stack_depot_stats->allocated) { - Printf("%s: StackDepot: %zd ids; %zdM allocated\n", - SanitizerToolName, - stack_depot_stats->n_uniq_ids, - stack_depot_stats->allocated >> 20); - prev_reported_stack_depot_size = stack_depot_stats->allocated; - } - } - } - // Check RSS against the limit. - if (hard_rss_limit_mb && hard_rss_limit_mb < current_rss_mb) { - Report("%s: hard rss limit exhausted (%zdMb vs %zdMb)\n", - SanitizerToolName, hard_rss_limit_mb, current_rss_mb); - DumpProcessMap(); - Die(); - } - if (soft_rss_limit_mb) { - if (soft_rss_limit_mb < current_rss_mb && !reached_soft_rss_limit) { - reached_soft_rss_limit = true; - Report("%s: soft rss limit exhausted (%zdMb vs %zdMb)\n", - SanitizerToolName, soft_rss_limit_mb, current_rss_mb); - if (SoftRssLimitExceededCallback) - SoftRssLimitExceededCallback(true); - } else if (soft_rss_limit_mb >= current_rss_mb && - reached_soft_rss_limit) { - reached_soft_rss_limit = false; - if (SoftRssLimitExceededCallback) - SoftRssLimitExceededCallback(false); - } - } - if (heap_profile && - current_rss_mb > rss_during_last_reported_profile * 1.1) { - Printf("\n\nHEAP PROFILE at RSS %zdMb\n", current_rss_mb); - __sanitizer_print_memory_profile(90, 20); - rss_during_last_reported_profile = current_rss_mb; - } - } -} -#endif - -void WriteToSyslog(const char *msg) { - InternalScopedString msg_copy(kErrorMessageBufferSize); - msg_copy.append("%s", msg); - char *p = msg_copy.data(); - char *q; - - // Print one line at a time. - // syslog, at least on Android, has an implicit message length limit. - while ((q = internal_strchr(p, '\n'))) { - *q = '\0'; - WriteOneLineToSyslog(p); - p = q + 1; - } - // Print remaining characters, if there are any. - // Note that this will add an extra newline at the end. - // FIXME: buffer extra output. This would need a thread-local buffer, which - // on Android requires plugging into the tools (ex. ASan's) Thread class. - if (*p) - WriteOneLineToSyslog(p); -} - -void MaybeStartBackgroudThread() { -#if (SANITIZER_LINUX || SANITIZER_NETBSD) && \ - !SANITIZER_GO // Need to implement/test on other platforms. - // Start the background thread if one of the rss limits is given. - if (!common_flags()->hard_rss_limit_mb && - !common_flags()->soft_rss_limit_mb && - !common_flags()->heap_profile) return; - if (!&real_pthread_create) return; // Can't spawn the thread anyway. - internal_start_thread(BackgroundThread, nullptr); -#endif -} - -static void (*sandboxing_callback)(); -void SetSandboxingCallback(void (*f)()) { - sandboxing_callback = f; -} - -} // namespace __sanitizer - -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify, - __sanitizer_sandbox_arguments *args) { - __sanitizer::PlatformPrepareForSandboxing(args); - if (__sanitizer::sandboxing_callback) - __sanitizer::sandboxing_callback(); -} diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cpp b/lib/sanitizer_common/sanitizer_common_libcdep.cpp new file mode 100644 index 000000000000..27d6a177760e --- /dev/null +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cpp @@ -0,0 +1,139 @@ +//===-- sanitizer_common_libcdep.cpp --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator_interface.h" +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_procmaps.h" + + +namespace __sanitizer { + +static void (*SoftRssLimitExceededCallback)(bool exceeded); +void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) { + CHECK_EQ(SoftRssLimitExceededCallback, nullptr); + SoftRssLimitExceededCallback = Callback; +} + +#if (SANITIZER_LINUX || SANITIZER_NETBSD) && !SANITIZER_GO +// Weak default implementation for when sanitizer_stackdepot is not linked in. +SANITIZER_WEAK_ATTRIBUTE StackDepotStats *StackDepotGetStats() { + return nullptr; +} + +void BackgroundThread(void *arg) { + const uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb; + const uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb; + const bool heap_profile = common_flags()->heap_profile; + uptr prev_reported_rss = 0; + uptr prev_reported_stack_depot_size = 0; + bool reached_soft_rss_limit = false; + uptr rss_during_last_reported_profile = 0; + while (true) { + SleepForMillis(100); + const uptr current_rss_mb = GetRSS() >> 20; + if (Verbosity()) { + // If RSS has grown 10% since last time, print some information. + if (prev_reported_rss * 11 / 10 < current_rss_mb) { + Printf("%s: RSS: %zdMb\n", SanitizerToolName, current_rss_mb); + prev_reported_rss = current_rss_mb; + } + // If stack depot has grown 10% since last time, print it too. + StackDepotStats *stack_depot_stats = StackDepotGetStats(); + if (stack_depot_stats) { + if (prev_reported_stack_depot_size * 11 / 10 < + stack_depot_stats->allocated) { + Printf("%s: StackDepot: %zd ids; %zdM allocated\n", + SanitizerToolName, + stack_depot_stats->n_uniq_ids, + stack_depot_stats->allocated >> 20); + prev_reported_stack_depot_size = stack_depot_stats->allocated; + } + } + } + // Check RSS against the limit. + if (hard_rss_limit_mb && hard_rss_limit_mb < current_rss_mb) { + Report("%s: hard rss limit exhausted (%zdMb vs %zdMb)\n", + SanitizerToolName, hard_rss_limit_mb, current_rss_mb); + DumpProcessMap(); + Die(); + } + if (soft_rss_limit_mb) { + if (soft_rss_limit_mb < current_rss_mb && !reached_soft_rss_limit) { + reached_soft_rss_limit = true; + Report("%s: soft rss limit exhausted (%zdMb vs %zdMb)\n", + SanitizerToolName, soft_rss_limit_mb, current_rss_mb); + if (SoftRssLimitExceededCallback) + SoftRssLimitExceededCallback(true); + } else if (soft_rss_limit_mb >= current_rss_mb && + reached_soft_rss_limit) { + reached_soft_rss_limit = false; + if (SoftRssLimitExceededCallback) + SoftRssLimitExceededCallback(false); + } + } + if (heap_profile && + current_rss_mb > rss_during_last_reported_profile * 1.1) { + Printf("\n\nHEAP PROFILE at RSS %zdMb\n", current_rss_mb); + __sanitizer_print_memory_profile(90, 20); + rss_during_last_reported_profile = current_rss_mb; + } + } +} +#endif + +void WriteToSyslog(const char *msg) { + InternalScopedString msg_copy(kErrorMessageBufferSize); + msg_copy.append("%s", msg); + char *p = msg_copy.data(); + char *q; + + // Print one line at a time. + // syslog, at least on Android, has an implicit message length limit. + while ((q = internal_strchr(p, '\n'))) { + *q = '\0'; + WriteOneLineToSyslog(p); + p = q + 1; + } + // Print remaining characters, if there are any. + // Note that this will add an extra newline at the end. + // FIXME: buffer extra output. This would need a thread-local buffer, which + // on Android requires plugging into the tools (ex. ASan's) Thread class. + if (*p) + WriteOneLineToSyslog(p); +} + +void MaybeStartBackgroudThread() { +#if (SANITIZER_LINUX || SANITIZER_NETBSD) && \ + !SANITIZER_GO // Need to implement/test on other platforms. + // Start the background thread if one of the rss limits is given. + if (!common_flags()->hard_rss_limit_mb && + !common_flags()->soft_rss_limit_mb && + !common_flags()->heap_profile) return; + if (!&real_pthread_create) return; // Can't spawn the thread anyway. + internal_start_thread(BackgroundThread, nullptr); +#endif +} + +static void (*sandboxing_callback)(); +void SetSandboxingCallback(void (*f)()) { + sandboxing_callback = f; +} + +} // namespace __sanitizer + +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify, + __sanitizer_sandbox_arguments *args) { + __sanitizer::PlatformPrepareForSandboxing(args); + if (__sanitizer::sandboxing_callback) + __sanitizer::sandboxing_callback(); +} diff --git a/lib/sanitizer_common/sanitizer_common_nolibc.cc b/lib/sanitizer_common/sanitizer_common_nolibc.cc deleted file mode 100644 index fdd858781216..000000000000 --- a/lib/sanitizer_common/sanitizer_common_nolibc.cc +++ /dev/null @@ -1,34 +0,0 @@ -//===-- sanitizer_common_nolibc.cc ----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file contains stubs for libc function to facilitate optional use of -// libc in no-libcdep sources. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#include "sanitizer_common.h" -#include "sanitizer_libc.h" - -namespace __sanitizer { - -// The Windows implementations of these functions use the win32 API directly, -// bypassing libc. -#if !SANITIZER_WINDOWS -#if SANITIZER_LINUX -void LogMessageOnPrintf(const char *str) {} -#endif -void WriteToSyslog(const char *buffer) {} -void Abort() { internal__exit(1); } -void SleepForSeconds(int seconds) { internal_sleep(seconds); } -#endif // !SANITIZER_WINDOWS - -#if !SANITIZER_WINDOWS && !SANITIZER_MAC -void ListOfModules::init() {} -#endif - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_common_nolibc.cpp b/lib/sanitizer_common/sanitizer_common_nolibc.cpp new file mode 100644 index 000000000000..3b278e017eb7 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_common_nolibc.cpp @@ -0,0 +1,34 @@ +//===-- sanitizer_common_nolibc.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains stubs for libc function to facilitate optional use of +// libc in no-libcdep sources. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#include "sanitizer_common.h" +#include "sanitizer_libc.h" + +namespace __sanitizer { + +// The Windows implementations of these functions use the win32 API directly, +// bypassing libc. +#if !SANITIZER_WINDOWS +#if SANITIZER_LINUX +void LogMessageOnPrintf(const char *str) {} +#endif +void WriteToSyslog(const char *buffer) {} +void Abort() { internal__exit(1); } +void SleepForSeconds(int seconds) { internal_sleep(seconds); } +#endif // !SANITIZER_WINDOWS + +#if !SANITIZER_WINDOWS && !SANITIZER_MAC +void ListOfModules::init() {} +#endif + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_common_syscalls.inc b/lib/sanitizer_common/sanitizer_common_syscalls.inc index 00bb2aeef111..31ff48cfd2cf 100644 --- a/lib/sanitizer_common/sanitizer_common_syscalls.inc +++ b/lib/sanitizer_common/sanitizer_common_syscalls.inc @@ -2873,6 +2873,18 @@ POST_SYSCALL(rt_sigaction)(long res, long signum, POST_WRITE(oldact, oldact_sz); } } + +PRE_SYSCALL(getrandom)(void *buf, uptr count, long flags) { + if (buf) { + PRE_WRITE(buf, count); + } +} + +POST_SYSCALL(getrandom)(long res, void *buf, uptr count, long flags) { + if (res > 0 && buf) { + POST_WRITE(buf, res); + } +} } // extern "C" #undef PRE_SYSCALL diff --git a/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc b/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc deleted file mode 100644 index 2c7180122148..000000000000 --- a/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc +++ /dev/null @@ -1,240 +0,0 @@ -//===-- sanitizer_coverage_fuchsia.cc -------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Sanitizer Coverage Controller for Trace PC Guard, Fuchsia-specific version. -// -// This Fuchsia-specific implementation uses the same basic scheme and the -// same simple '.sancov' file format as the generic implementation. The -// difference is that we just produce a single blob of output for the whole -// program, not a separate one per DSO. We do not sort the PC table and do -// not prune the zeros, so the resulting file is always as large as it -// would be to report 100% coverage. Implicit tracing information about -// the address ranges of DSOs allows offline tools to split the one big -// blob into separate files that the 'sancov' tool can understand. -// -// Unlike the traditional implementation that uses an atexit hook to write -// out data files at the end, the results on Fuchsia do not go into a file -// per se. The 'coverage_dir' option is ignored. Instead, they are stored -// directly into a shared memory object (a Zircon VMO). At exit, that VMO -// is handed over to a system service that's responsible for getting the -// data out to somewhere that it can be fed into the sancov tool (where and -// how is not our problem). - -#include "sanitizer_platform.h" -#if SANITIZER_FUCHSIA -#include "sanitizer_atomic.h" -#include "sanitizer_common.h" -#include "sanitizer_internal_defs.h" -#include "sanitizer_symbolizer_fuchsia.h" - -#include -#include -#include - -using namespace __sanitizer; // NOLINT - -namespace __sancov { -namespace { - -// TODO(mcgrathr): Move the constant into a header shared with other impls. -constexpr u64 Magic64 = 0xC0BFFFFFFFFFFF64ULL; -static_assert(SANITIZER_WORDSIZE == 64, "Fuchsia is always LP64"); - -constexpr const char kSancovSinkName[] = "sancov"; - -// Collects trace-pc guard coverage. -// This class relies on zero-initialization. -class TracePcGuardController final { - public: - // For each PC location being tracked, there is a u32 reserved in global - // data called the "guard". At startup, we assign each guard slot a - // unique index into the big results array. Later during runtime, the - // first call to TracePcGuard (below) will store the corresponding PC at - // that index in the array. (Each later call with the same guard slot is - // presumed to be from the same PC.) Then it clears the guard slot back - // to zero, which tells the compiler not to bother calling in again. At - // the end of the run, we have a big array where each element is either - // zero or is a tracked PC location that was hit in the trace. - - // This is called from global constructors. Each translation unit has a - // contiguous array of guard slots, and a constructor that calls here - // with the bounds of its array. Those constructors are allowed to call - // here more than once for the same array. Usually all of these - // constructors run in the initial thread, but it's possible that a - // dlopen call on a secondary thread will run constructors that get here. - void InitTracePcGuard(u32 *start, u32 *end) { - if (end > start && *start == 0 && common_flags()->coverage) { - // Complete the setup before filling in any guards with indices. - // This avoids the possibility of code called from Setup reentering - // TracePcGuard. - u32 idx = Setup(end - start); - for (u32 *p = start; p < end; ++p) { - *p = idx++; - } - } - } - - void TracePcGuard(u32 *guard, uptr pc) { - atomic_uint32_t *guard_ptr = reinterpret_cast(guard); - u32 idx = atomic_exchange(guard_ptr, 0, memory_order_relaxed); - if (idx > 0) array_[idx] = pc; - } - - void Dump() { - BlockingMutexLock locked(&setup_lock_); - if (array_) { - CHECK_NE(vmo_, ZX_HANDLE_INVALID); - - // Publish the VMO to the system, where it can be collected and - // analyzed after this process exits. This always consumes the VMO - // handle. Any failure is just logged and not indicated to us. - __sanitizer_publish_data(kSancovSinkName, vmo_); - vmo_ = ZX_HANDLE_INVALID; - - // This will route to __sanitizer_log_write, which will ensure that - // information about shared libraries is written out. This message - // uses the `dumpfile` symbolizer markup element to highlight the - // dump. See the explanation for this in: - // https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md - Printf("SanitizerCoverage: " FORMAT_DUMPFILE " with up to %u PCs\n", - kSancovSinkName, vmo_name_, next_index_ - 1); - } - } - - private: - // We map in the largest possible view into the VMO: one word - // for every possible 32-bit index value. This avoids the need - // to change the mapping when increasing the size of the VMO. - // We can always spare the 32G of address space. - static constexpr size_t MappingSize = sizeof(uptr) << 32; - - BlockingMutex setup_lock_ = BlockingMutex(LINKER_INITIALIZED); - uptr *array_ = nullptr; - u32 next_index_ = 0; - zx_handle_t vmo_ = {}; - char vmo_name_[ZX_MAX_NAME_LEN] = {}; - - size_t DataSize() const { return next_index_ * sizeof(uintptr_t); } - - u32 Setup(u32 num_guards) { - BlockingMutexLock locked(&setup_lock_); - DCHECK(common_flags()->coverage); - - if (next_index_ == 0) { - CHECK_EQ(vmo_, ZX_HANDLE_INVALID); - CHECK_EQ(array_, nullptr); - - // The first sample goes at [1] to reserve [0] for the magic number. - next_index_ = 1 + num_guards; - - zx_status_t status = _zx_vmo_create(DataSize(), ZX_VMO_RESIZABLE, &vmo_); - CHECK_EQ(status, ZX_OK); - - // Give the VMO a name including our process KOID so it's easy to spot. - internal_snprintf(vmo_name_, sizeof(vmo_name_), "%s.%zu", kSancovSinkName, - internal_getpid()); - _zx_object_set_property(vmo_, ZX_PROP_NAME, vmo_name_, - internal_strlen(vmo_name_)); - - // Map the largest possible view we might need into the VMO. Later - // we might need to increase the VMO's size before we can use larger - // indices, but we'll never move the mapping address so we don't have - // any multi-thread synchronization issues with that. - uintptr_t mapping; - status = - _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, - 0, vmo_, 0, MappingSize, &mapping); - CHECK_EQ(status, ZX_OK); - - // Hereafter other threads are free to start storing into - // elements [1, next_index_) of the big array. - array_ = reinterpret_cast(mapping); - - // Store the magic number. - // Hereafter, the VMO serves as the contents of the '.sancov' file. - array_[0] = Magic64; - - return 1; - } else { - // The VMO is already mapped in, but it's not big enough to use the - // new indices. So increase the size to cover the new maximum index. - - CHECK_NE(vmo_, ZX_HANDLE_INVALID); - CHECK_NE(array_, nullptr); - - uint32_t first_index = next_index_; - next_index_ += num_guards; - - zx_status_t status = _zx_vmo_set_size(vmo_, DataSize()); - CHECK_EQ(status, ZX_OK); - - return first_index; - } - } -}; - -static TracePcGuardController pc_guard_controller; - -} // namespace -} // namespace __sancov - -namespace __sanitizer { -void InitializeCoverage(bool enabled, const char *dir) { - CHECK_EQ(enabled, common_flags()->coverage); - CHECK_EQ(dir, common_flags()->coverage_dir); - - static bool coverage_enabled = false; - if (!coverage_enabled) { - coverage_enabled = enabled; - Atexit(__sanitizer_cov_dump); - AddDieCallback(__sanitizer_cov_dump); - } -} -} // namespace __sanitizer - -extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( // NOLINT - const uptr *pcs, uptr len) { - UNIMPLEMENTED(); -} - -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *guard) { - if (!*guard) return; - __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1); -} - -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, - u32 *start, u32 *end) { - if (start == end || *start) return; - __sancov::pc_guard_controller.InitTracePcGuard(start, end); -} - -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() { - __sancov::pc_guard_controller.Dump(); -} -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { - __sanitizer_dump_trace_pc_guard_coverage(); -} -// Default empty implementations (weak). Users should redefine them. -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} -} // extern "C" - -#endif // !SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp b/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp new file mode 100644 index 000000000000..f18cee66b843 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp @@ -0,0 +1,240 @@ +//===-- sanitizer_coverage_fuchsia.cpp ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Sanitizer Coverage Controller for Trace PC Guard, Fuchsia-specific version. +// +// This Fuchsia-specific implementation uses the same basic scheme and the +// same simple '.sancov' file format as the generic implementation. The +// difference is that we just produce a single blob of output for the whole +// program, not a separate one per DSO. We do not sort the PC table and do +// not prune the zeros, so the resulting file is always as large as it +// would be to report 100% coverage. Implicit tracing information about +// the address ranges of DSOs allows offline tools to split the one big +// blob into separate files that the 'sancov' tool can understand. +// +// Unlike the traditional implementation that uses an atexit hook to write +// out data files at the end, the results on Fuchsia do not go into a file +// per se. The 'coverage_dir' option is ignored. Instead, they are stored +// directly into a shared memory object (a Zircon VMO). At exit, that VMO +// is handed over to a system service that's responsible for getting the +// data out to somewhere that it can be fed into the sancov tool (where and +// how is not our problem). + +#include "sanitizer_platform.h" +#if SANITIZER_FUCHSIA +#include "sanitizer_atomic.h" +#include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_symbolizer_fuchsia.h" + +#include +#include +#include + +using namespace __sanitizer; + +namespace __sancov { +namespace { + +// TODO(mcgrathr): Move the constant into a header shared with other impls. +constexpr u64 Magic64 = 0xC0BFFFFFFFFFFF64ULL; +static_assert(SANITIZER_WORDSIZE == 64, "Fuchsia is always LP64"); + +constexpr const char kSancovSinkName[] = "sancov"; + +// Collects trace-pc guard coverage. +// This class relies on zero-initialization. +class TracePcGuardController final { + public: + // For each PC location being tracked, there is a u32 reserved in global + // data called the "guard". At startup, we assign each guard slot a + // unique index into the big results array. Later during runtime, the + // first call to TracePcGuard (below) will store the corresponding PC at + // that index in the array. (Each later call with the same guard slot is + // presumed to be from the same PC.) Then it clears the guard slot back + // to zero, which tells the compiler not to bother calling in again. At + // the end of the run, we have a big array where each element is either + // zero or is a tracked PC location that was hit in the trace. + + // This is called from global constructors. Each translation unit has a + // contiguous array of guard slots, and a constructor that calls here + // with the bounds of its array. Those constructors are allowed to call + // here more than once for the same array. Usually all of these + // constructors run in the initial thread, but it's possible that a + // dlopen call on a secondary thread will run constructors that get here. + void InitTracePcGuard(u32 *start, u32 *end) { + if (end > start && *start == 0 && common_flags()->coverage) { + // Complete the setup before filling in any guards with indices. + // This avoids the possibility of code called from Setup reentering + // TracePcGuard. + u32 idx = Setup(end - start); + for (u32 *p = start; p < end; ++p) { + *p = idx++; + } + } + } + + void TracePcGuard(u32 *guard, uptr pc) { + atomic_uint32_t *guard_ptr = reinterpret_cast(guard); + u32 idx = atomic_exchange(guard_ptr, 0, memory_order_relaxed); + if (idx > 0) array_[idx] = pc; + } + + void Dump() { + BlockingMutexLock locked(&setup_lock_); + if (array_) { + CHECK_NE(vmo_, ZX_HANDLE_INVALID); + + // Publish the VMO to the system, where it can be collected and + // analyzed after this process exits. This always consumes the VMO + // handle. Any failure is just logged and not indicated to us. + __sanitizer_publish_data(kSancovSinkName, vmo_); + vmo_ = ZX_HANDLE_INVALID; + + // This will route to __sanitizer_log_write, which will ensure that + // information about shared libraries is written out. This message + // uses the `dumpfile` symbolizer markup element to highlight the + // dump. See the explanation for this in: + // https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md + Printf("SanitizerCoverage: " FORMAT_DUMPFILE " with up to %u PCs\n", + kSancovSinkName, vmo_name_, next_index_ - 1); + } + } + + private: + // We map in the largest possible view into the VMO: one word + // for every possible 32-bit index value. This avoids the need + // to change the mapping when increasing the size of the VMO. + // We can always spare the 32G of address space. + static constexpr size_t MappingSize = sizeof(uptr) << 32; + + BlockingMutex setup_lock_ = BlockingMutex(LINKER_INITIALIZED); + uptr *array_ = nullptr; + u32 next_index_ = 0; + zx_handle_t vmo_ = {}; + char vmo_name_[ZX_MAX_NAME_LEN] = {}; + + size_t DataSize() const { return next_index_ * sizeof(uintptr_t); } + + u32 Setup(u32 num_guards) { + BlockingMutexLock locked(&setup_lock_); + DCHECK(common_flags()->coverage); + + if (next_index_ == 0) { + CHECK_EQ(vmo_, ZX_HANDLE_INVALID); + CHECK_EQ(array_, nullptr); + + // The first sample goes at [1] to reserve [0] for the magic number. + next_index_ = 1 + num_guards; + + zx_status_t status = _zx_vmo_create(DataSize(), ZX_VMO_RESIZABLE, &vmo_); + CHECK_EQ(status, ZX_OK); + + // Give the VMO a name including our process KOID so it's easy to spot. + internal_snprintf(vmo_name_, sizeof(vmo_name_), "%s.%zu", kSancovSinkName, + internal_getpid()); + _zx_object_set_property(vmo_, ZX_PROP_NAME, vmo_name_, + internal_strlen(vmo_name_)); + + // Map the largest possible view we might need into the VMO. Later + // we might need to increase the VMO's size before we can use larger + // indices, but we'll never move the mapping address so we don't have + // any multi-thread synchronization issues with that. + uintptr_t mapping; + status = + _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, + 0, vmo_, 0, MappingSize, &mapping); + CHECK_EQ(status, ZX_OK); + + // Hereafter other threads are free to start storing into + // elements [1, next_index_) of the big array. + array_ = reinterpret_cast(mapping); + + // Store the magic number. + // Hereafter, the VMO serves as the contents of the '.sancov' file. + array_[0] = Magic64; + + return 1; + } else { + // The VMO is already mapped in, but it's not big enough to use the + // new indices. So increase the size to cover the new maximum index. + + CHECK_NE(vmo_, ZX_HANDLE_INVALID); + CHECK_NE(array_, nullptr); + + uint32_t first_index = next_index_; + next_index_ += num_guards; + + zx_status_t status = _zx_vmo_set_size(vmo_, DataSize()); + CHECK_EQ(status, ZX_OK); + + return first_index; + } + } +}; + +static TracePcGuardController pc_guard_controller; + +} // namespace +} // namespace __sancov + +namespace __sanitizer { +void InitializeCoverage(bool enabled, const char *dir) { + CHECK_EQ(enabled, common_flags()->coverage); + CHECK_EQ(dir, common_flags()->coverage_dir); + + static bool coverage_enabled = false; + if (!coverage_enabled) { + coverage_enabled = enabled; + Atexit(__sanitizer_cov_dump); + AddDieCallback(__sanitizer_cov_dump); + } +} +} // namespace __sanitizer + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage(const uptr *pcs, + uptr len) { + UNIMPLEMENTED(); +} + +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *guard) { + if (!*guard) return; + __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1); +} + +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, + u32 *start, u32 *end) { + if (start == end || *start) return; + __sancov::pc_guard_controller.InitTracePcGuard(start, end); +} + +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() { + __sancov::pc_guard_controller.Dump(); +} +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { + __sanitizer_dump_trace_pc_guard_coverage(); +} +// Default empty implementations (weak). Users should redefine them. +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} +} // extern "C" + +#endif // !SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc deleted file mode 100644 index 9dbf2eb52978..000000000000 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ /dev/null @@ -1,218 +0,0 @@ -//===-- sanitizer_coverage_libcdep_new.cc ---------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// Sanitizer Coverage Controller for Trace PC Guard. - -#include "sanitizer_platform.h" - -#if !SANITIZER_FUCHSIA -#include "sancov_flags.h" -#include "sanitizer_allocator_internal.h" -#include "sanitizer_atomic.h" -#include "sanitizer_common.h" -#include "sanitizer_file.h" - -using namespace __sanitizer; - -using AddressRange = LoadedModule::AddressRange; - -namespace __sancov { -namespace { - -static const u64 Magic64 = 0xC0BFFFFFFFFFFF64ULL; -static const u64 Magic32 = 0xC0BFFFFFFFFFFF32ULL; -static const u64 Magic = SANITIZER_WORDSIZE == 64 ? Magic64 : Magic32; - -static fd_t OpenFile(const char* path) { - error_t err; - fd_t fd = OpenFile(path, WrOnly, &err); - if (fd == kInvalidFd) - Report("SanitizerCoverage: failed to open %s for writing (reason: %d)\n", - path, err); - return fd; -} - -static void GetCoverageFilename(char* path, const char* name, - const char* extension) { - CHECK(name); - internal_snprintf(path, kMaxPathLength, "%s/%s.%zd.%s", - common_flags()->coverage_dir, name, internal_getpid(), - extension); -} - -static void WriteModuleCoverage(char* file_path, const char* module_name, - const uptr* pcs, uptr len) { - GetCoverageFilename(file_path, StripModuleName(module_name), "sancov"); - fd_t fd = OpenFile(file_path); - WriteToFile(fd, &Magic, sizeof(Magic)); - WriteToFile(fd, pcs, len * sizeof(*pcs)); - CloseFile(fd); - Printf("SanitizerCoverage: %s: %zd PCs written\n", file_path, len); -} - -static void SanitizerDumpCoverage(const uptr* unsorted_pcs, uptr len) { - if (!len) return; - - char* file_path = static_cast(InternalAlloc(kMaxPathLength)); - char* module_name = static_cast(InternalAlloc(kMaxPathLength)); - uptr* pcs = static_cast(InternalAlloc(len * sizeof(uptr))); - - internal_memcpy(pcs, unsorted_pcs, len * sizeof(uptr)); - Sort(pcs, len); - - bool module_found = false; - uptr last_base = 0; - uptr module_start_idx = 0; - - for (uptr i = 0; i < len; ++i) { - const uptr pc = pcs[i]; - if (!pc) continue; - - if (!__sanitizer_get_module_and_offset_for_pc(pc, nullptr, 0, &pcs[i])) { - Printf("ERROR: unknown pc 0x%x (may happen if dlclose is used)\n", pc); - continue; - } - uptr module_base = pc - pcs[i]; - - if (module_base != last_base || !module_found) { - if (module_found) { - WriteModuleCoverage(file_path, module_name, &pcs[module_start_idx], - i - module_start_idx); - } - - last_base = module_base; - module_start_idx = i; - module_found = true; - __sanitizer_get_module_and_offset_for_pc(pc, module_name, kMaxPathLength, - &pcs[i]); - } - } - - if (module_found) { - WriteModuleCoverage(file_path, module_name, &pcs[module_start_idx], - len - module_start_idx); - } - - InternalFree(file_path); - InternalFree(module_name); - InternalFree(pcs); -} - -// Collects trace-pc guard coverage. -// This class relies on zero-initialization. -class TracePcGuardController { - public: - void Initialize() { - CHECK(!initialized); - - initialized = true; - InitializeSancovFlags(); - - pc_vector.Initialize(0); - } - - void InitTracePcGuard(u32* start, u32* end) { - if (!initialized) Initialize(); - CHECK(!*start); - CHECK_NE(start, end); - - u32 i = pc_vector.size(); - for (u32* p = start; p < end; p++) *p = ++i; - pc_vector.resize(i); - } - - void TracePcGuard(u32* guard, uptr pc) { - u32 idx = *guard; - if (!idx) return; - // we start indices from 1. - atomic_uintptr_t* pc_ptr = - reinterpret_cast(&pc_vector[idx - 1]); - if (atomic_load(pc_ptr, memory_order_relaxed) == 0) - atomic_store(pc_ptr, pc, memory_order_relaxed); - } - - void Reset() { - internal_memset(&pc_vector[0], 0, sizeof(pc_vector[0]) * pc_vector.size()); - } - - void Dump() { - if (!initialized || !common_flags()->coverage) return; - __sanitizer_dump_coverage(pc_vector.data(), pc_vector.size()); - } - - private: - bool initialized; - InternalMmapVectorNoCtor pc_vector; -}; - -static TracePcGuardController pc_guard_controller; - -} // namespace -} // namespace __sancov - -namespace __sanitizer { -void InitializeCoverage(bool enabled, const char *dir) { - static bool coverage_enabled = false; - if (coverage_enabled) - return; // May happen if two sanitizer enable coverage in the same process. - coverage_enabled = enabled; - Atexit(__sanitizer_cov_dump); - AddDieCallback(__sanitizer_cov_dump); -} -} // namespace __sanitizer - -extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( // NOLINT - const uptr* pcs, uptr len) { - return __sancov::SanitizerDumpCoverage(pcs, len); -} - -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32* guard) { - if (!*guard) return; - __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1); -} - -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, - u32* start, u32* end) { - if (start == end || *start) return; - __sancov::pc_guard_controller.InitTracePcGuard(start, end); -} - -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() { - __sancov::pc_guard_controller.Dump(); -} -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { - __sanitizer_dump_trace_pc_guard_coverage(); -} -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_reset() { - __sancov::pc_guard_controller.Reset(); -} -// Default empty implementations (weak). Users should redefine them. -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {} -} // extern "C" -// Weak definition for code instrumented with -fsanitize-coverage=stack-depth -// and later linked with code containing a strong definition. -// E.g., -fsanitize=fuzzer-no-link -SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE -SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE uptr __sancov_lowest_stack; - -#endif // !SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp new file mode 100644 index 000000000000..6a75792f9262 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp @@ -0,0 +1,218 @@ +//===-- sanitizer_coverage_libcdep_new.cpp --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// Sanitizer Coverage Controller for Trace PC Guard. + +#include "sanitizer_platform.h" + +#if !SANITIZER_FUCHSIA +#include "sancov_flags.h" +#include "sanitizer_allocator_internal.h" +#include "sanitizer_atomic.h" +#include "sanitizer_common.h" +#include "sanitizer_file.h" + +using namespace __sanitizer; + +using AddressRange = LoadedModule::AddressRange; + +namespace __sancov { +namespace { + +static const u64 Magic64 = 0xC0BFFFFFFFFFFF64ULL; +static const u64 Magic32 = 0xC0BFFFFFFFFFFF32ULL; +static const u64 Magic = SANITIZER_WORDSIZE == 64 ? Magic64 : Magic32; + +static fd_t OpenFile(const char* path) { + error_t err; + fd_t fd = OpenFile(path, WrOnly, &err); + if (fd == kInvalidFd) + Report("SanitizerCoverage: failed to open %s for writing (reason: %d)\n", + path, err); + return fd; +} + +static void GetCoverageFilename(char* path, const char* name, + const char* extension) { + CHECK(name); + internal_snprintf(path, kMaxPathLength, "%s/%s.%zd.%s", + common_flags()->coverage_dir, name, internal_getpid(), + extension); +} + +static void WriteModuleCoverage(char* file_path, const char* module_name, + const uptr* pcs, uptr len) { + GetCoverageFilename(file_path, StripModuleName(module_name), "sancov"); + fd_t fd = OpenFile(file_path); + WriteToFile(fd, &Magic, sizeof(Magic)); + WriteToFile(fd, pcs, len * sizeof(*pcs)); + CloseFile(fd); + Printf("SanitizerCoverage: %s: %zd PCs written\n", file_path, len); +} + +static void SanitizerDumpCoverage(const uptr* unsorted_pcs, uptr len) { + if (!len) return; + + char* file_path = static_cast(InternalAlloc(kMaxPathLength)); + char* module_name = static_cast(InternalAlloc(kMaxPathLength)); + uptr* pcs = static_cast(InternalAlloc(len * sizeof(uptr))); + + internal_memcpy(pcs, unsorted_pcs, len * sizeof(uptr)); + Sort(pcs, len); + + bool module_found = false; + uptr last_base = 0; + uptr module_start_idx = 0; + + for (uptr i = 0; i < len; ++i) { + const uptr pc = pcs[i]; + if (!pc) continue; + + if (!__sanitizer_get_module_and_offset_for_pc(pc, nullptr, 0, &pcs[i])) { + Printf("ERROR: unknown pc 0x%x (may happen if dlclose is used)\n", pc); + continue; + } + uptr module_base = pc - pcs[i]; + + if (module_base != last_base || !module_found) { + if (module_found) { + WriteModuleCoverage(file_path, module_name, &pcs[module_start_idx], + i - module_start_idx); + } + + last_base = module_base; + module_start_idx = i; + module_found = true; + __sanitizer_get_module_and_offset_for_pc(pc, module_name, kMaxPathLength, + &pcs[i]); + } + } + + if (module_found) { + WriteModuleCoverage(file_path, module_name, &pcs[module_start_idx], + len - module_start_idx); + } + + InternalFree(file_path); + InternalFree(module_name); + InternalFree(pcs); +} + +// Collects trace-pc guard coverage. +// This class relies on zero-initialization. +class TracePcGuardController { + public: + void Initialize() { + CHECK(!initialized); + + initialized = true; + InitializeSancovFlags(); + + pc_vector.Initialize(0); + } + + void InitTracePcGuard(u32* start, u32* end) { + if (!initialized) Initialize(); + CHECK(!*start); + CHECK_NE(start, end); + + u32 i = pc_vector.size(); + for (u32* p = start; p < end; p++) *p = ++i; + pc_vector.resize(i); + } + + void TracePcGuard(u32* guard, uptr pc) { + u32 idx = *guard; + if (!idx) return; + // we start indices from 1. + atomic_uintptr_t* pc_ptr = + reinterpret_cast(&pc_vector[idx - 1]); + if (atomic_load(pc_ptr, memory_order_relaxed) == 0) + atomic_store(pc_ptr, pc, memory_order_relaxed); + } + + void Reset() { + internal_memset(&pc_vector[0], 0, sizeof(pc_vector[0]) * pc_vector.size()); + } + + void Dump() { + if (!initialized || !common_flags()->coverage) return; + __sanitizer_dump_coverage(pc_vector.data(), pc_vector.size()); + } + + private: + bool initialized; + InternalMmapVectorNoCtor pc_vector; +}; + +static TracePcGuardController pc_guard_controller; + +} // namespace +} // namespace __sancov + +namespace __sanitizer { +void InitializeCoverage(bool enabled, const char *dir) { + static bool coverage_enabled = false; + if (coverage_enabled) + return; // May happen if two sanitizer enable coverage in the same process. + coverage_enabled = enabled; + Atexit(__sanitizer_cov_dump); + AddDieCallback(__sanitizer_cov_dump); +} +} // namespace __sanitizer + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage(const uptr* pcs, + uptr len) { + return __sancov::SanitizerDumpCoverage(pcs, len); +} + +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32* guard) { + if (!*guard) return; + __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1); +} + +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, + u32* start, u32* end) { + if (start == end || *start) return; + __sancov::pc_guard_controller.InitTracePcGuard(start, end); +} + +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() { + __sancov::pc_guard_controller.Dump(); +} +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { + __sanitizer_dump_trace_pc_guard_coverage(); +} +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_reset() { + __sancov::pc_guard_controller.Reset(); +} +// Default empty implementations (weak). Users should redefine them. +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {} +} // extern "C" +// Weak definition for code instrumented with -fsanitize-coverage=stack-depth +// and later linked with code containing a strong definition. +// E.g., -fsanitize=fuzzer-no-link +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE uptr __sancov_lowest_stack; + +#endif // !SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_coverage_win_dll_thunk.cc b/lib/sanitizer_common/sanitizer_coverage_win_dll_thunk.cc deleted file mode 100644 index 1f0f69dc43eb..000000000000 --- a/lib/sanitizer_common/sanitizer_coverage_win_dll_thunk.cc +++ /dev/null @@ -1,20 +0,0 @@ -//===-- sanitizer_coverage_win_dll_thunk.cc -------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines a family of thunks that should be statically linked into -// the DLLs that have instrumentation in order to delegate the calls to the -// shared runtime that lives in the main binary. -// See https://github.com/google/sanitizers/issues/209 for the details. -//===----------------------------------------------------------------------===// -#ifdef SANITIZER_DLL_THUNK -#include "sanitizer_win_dll_thunk.h" -// Sanitizer Coverage interface functions. -#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) -#include "sanitizer_coverage_interface.inc" -#endif // SANITIZER_DLL_THUNK diff --git a/lib/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp b/lib/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp new file mode 100644 index 000000000000..d0bf8a455643 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp @@ -0,0 +1,20 @@ +//===-- sanitizer_coverage_win_dll_thunk.cpp ------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a family of thunks that should be statically linked into +// the DLLs that have instrumentation in order to delegate the calls to the +// shared runtime that lives in the main binary. +// See https://github.com/google/sanitizers/issues/209 for the details. +//===----------------------------------------------------------------------===// +#ifdef SANITIZER_DLL_THUNK +#include "sanitizer_win_dll_thunk.h" +// Sanitizer Coverage interface functions. +#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name) +#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) +#include "sanitizer_coverage_interface.inc" +#endif // SANITIZER_DLL_THUNK diff --git a/lib/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cc b/lib/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cc deleted file mode 100644 index 2a4199756f3b..000000000000 --- a/lib/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cc +++ /dev/null @@ -1,26 +0,0 @@ -//===-- sanitizer_coverage_win_dynamic_runtime_thunk.cc -------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines things that need to be present in the application modules -// to interact with Sanitizer Coverage, when it is included in a dll. -// -//===----------------------------------------------------------------------===// -#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK -#define SANITIZER_IMPORT_INTERFACE 1 -#include "sanitizer_win_defs.h" -// Define weak alias for all weak functions imported from sanitizer coverage. -#define INTERFACE_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name) -#include "sanitizer_coverage_interface.inc" -#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK - -namespace __sanitizer { -// Add one, otherwise unused, external symbol to this object file so that the -// Visual C++ linker includes it and reads the .drective section. -void ForceWholeArchiveIncludeForSanCov() {} -} diff --git a/lib/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cpp b/lib/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cpp new file mode 100644 index 000000000000..0bdf0c5aed41 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cpp @@ -0,0 +1,26 @@ +//===-- sanitizer_coverage_win_dynamic_runtime_thunk.cpp ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines things that need to be present in the application modules +// to interact with Sanitizer Coverage, when it is included in a dll. +// +//===----------------------------------------------------------------------===// +#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK +#define SANITIZER_IMPORT_INTERFACE 1 +#include "sanitizer_win_defs.h" +// Define weak alias for all weak functions imported from sanitizer coverage. +#define INTERFACE_FUNCTION(Name) +#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name) +#include "sanitizer_coverage_interface.inc" +#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK + +namespace __sanitizer { +// Add one, otherwise unused, external symbol to this object file so that the +// Visual C++ linker includes it and reads the .drective section. +void ForceWholeArchiveIncludeForSanCov() {} +} diff --git a/lib/sanitizer_common/sanitizer_coverage_win_sections.cc b/lib/sanitizer_common/sanitizer_coverage_win_sections.cc deleted file mode 100644 index 403d46c8c4f1..000000000000 --- a/lib/sanitizer_common/sanitizer_coverage_win_sections.cc +++ /dev/null @@ -1,67 +0,0 @@ -//===-- sanitizer_coverage_win_sections.cc --------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines delimiters for Sanitizer Coverage's section. It contains -// Windows specific tricks to coax the linker into giving us the start and stop -// addresses of a section, as ELF linkers can do, to get the size of certain -// arrays. According to https://msdn.microsoft.com/en-us/library/7977wcck.aspx -// sections with the same name before "$" are sorted alphabetically by the -// string that comes after "$" and merged into one section. We take advantage -// of this by putting data we want the size of into the middle (M) of a section, -// by using the letter "M" after "$". We get the start of this data (ie: -// __start_section_name) by making the start variable come at the start of the -// section (using the letter A after "$"). We do the same to get the end of the -// data by using the letter "Z" after "$" to make the end variable come after -// the data. Note that because of our technique the address of the start -// variable is actually the address of data that comes before our middle -// section. We also need to prevent the linker from adding any padding. Each -// technique we use for this is explained in the comments below. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_WINDOWS -#include - -extern "C" { -// Use uint64_t so the linker won't need to add any padding if it tries to word -// align the start of the 8-bit counters array. The array will always start 8 -// bytes after __start_sancov_cntrs. -#pragma section(".SCOV$CA", read, write) // NOLINT -__declspec(allocate(".SCOV$CA")) uint64_t __start___sancov_cntrs = 0; - -// Even though we said not to align __stop__sancov_cntrs (using the "align" -// declspec), MSVC's linker may try to align the section, .SCOV$CZ, containing -// it. This can cause a mismatch between the number of PCs and counters since -// each PCTable element is 8 bytes (unlike counters which are 1 byte) so no -// padding would be added to align .SCOVP$Z, However, if .SCOV$CZ section is 1 -// byte, the linker won't try to align it on an 8-byte boundary, so use a -// uint8_t for __stop_sancov_cntrs. -#pragma section(".SCOV$CZ", read, write) // NOLINT -__declspec(allocate(".SCOV$CZ")) __declspec(align(1)) uint8_t - __stop___sancov_cntrs = 0; - -#pragma section(".SCOV$GA", read, write) // NOLINT -__declspec(allocate(".SCOV$GA")) uint64_t __start___sancov_guards = 0; -#pragma section(".SCOV$GZ", read, write) // NOLINT -__declspec(allocate(".SCOV$GZ")) __declspec(align(1)) uint8_t - __stop___sancov_guards = 0; - -// The guard array and counter array should both be merged into the .data -// section to reduce the number of PE sections. However, because PCTable is -// constant it should be merged with the .rdata section. -#pragma comment(linker, "/MERGE:.SCOV=.data") - -#pragma section(".SCOVP$A", read) // NOLINT -__declspec(allocate(".SCOVP$A")) uint64_t __start___sancov_pcs = 0; -#pragma section(".SCOVP$Z", read) // NOLINT -__declspec(allocate(".SCOVP$Z")) __declspec(align(1)) uint8_t - __stop___sancov_pcs = 0; - -#pragma comment(linker, "/MERGE:.SCOVP=.rdata") -} -#endif // SANITIZER_WINDOWS diff --git a/lib/sanitizer_common/sanitizer_coverage_win_sections.cpp b/lib/sanitizer_common/sanitizer_coverage_win_sections.cpp new file mode 100644 index 000000000000..e7d6563393cf --- /dev/null +++ b/lib/sanitizer_common/sanitizer_coverage_win_sections.cpp @@ -0,0 +1,67 @@ +//===-- sanitizer_coverage_win_sections.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines delimiters for Sanitizer Coverage's section. It contains +// Windows specific tricks to coax the linker into giving us the start and stop +// addresses of a section, as ELF linkers can do, to get the size of certain +// arrays. According to https://msdn.microsoft.com/en-us/library/7977wcck.aspx +// sections with the same name before "$" are sorted alphabetically by the +// string that comes after "$" and merged into one section. We take advantage +// of this by putting data we want the size of into the middle (M) of a section, +// by using the letter "M" after "$". We get the start of this data (ie: +// __start_section_name) by making the start variable come at the start of the +// section (using the letter A after "$"). We do the same to get the end of the +// data by using the letter "Z" after "$" to make the end variable come after +// the data. Note that because of our technique the address of the start +// variable is actually the address of data that comes before our middle +// section. We also need to prevent the linker from adding any padding. Each +// technique we use for this is explained in the comments below. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS +#include + +extern "C" { +// Use uint64_t so the linker won't need to add any padding if it tries to word +// align the start of the 8-bit counters array. The array will always start 8 +// bytes after __start_sancov_cntrs. +#pragma section(".SCOV$CA", read, write) +__declspec(allocate(".SCOV$CA")) uint64_t __start___sancov_cntrs = 0; + +// Even though we said not to align __stop__sancov_cntrs (using the "align" +// declspec), MSVC's linker may try to align the section, .SCOV$CZ, containing +// it. This can cause a mismatch between the number of PCs and counters since +// each PCTable element is 8 bytes (unlike counters which are 1 byte) so no +// padding would be added to align .SCOVP$Z, However, if .SCOV$CZ section is 1 +// byte, the linker won't try to align it on an 8-byte boundary, so use a +// uint8_t for __stop_sancov_cntrs. +#pragma section(".SCOV$CZ", read, write) +__declspec(allocate(".SCOV$CZ")) __declspec(align(1)) uint8_t + __stop___sancov_cntrs = 0; + +#pragma section(".SCOV$GA", read, write) +__declspec(allocate(".SCOV$GA")) uint64_t __start___sancov_guards = 0; +#pragma section(".SCOV$GZ", read, write) +__declspec(allocate(".SCOV$GZ")) __declspec(align(1)) uint8_t + __stop___sancov_guards = 0; + +// The guard array and counter array should both be merged into the .data +// section to reduce the number of PE sections. However, because PCTable is +// constant it should be merged with the .rdata section. +#pragma comment(linker, "/MERGE:.SCOV=.data") + +#pragma section(".SCOVP$A", read) +__declspec(allocate(".SCOVP$A")) uint64_t __start___sancov_pcs = 0; +#pragma section(".SCOVP$Z", read) +__declspec(allocate(".SCOVP$Z")) __declspec(align(1)) uint8_t + __stop___sancov_pcs = 0; + +#pragma comment(linker, "/MERGE:.SCOVP=.rdata") +} +#endif // SANITIZER_WINDOWS diff --git a/lib/sanitizer_common/sanitizer_coverage_win_weak_interception.cc b/lib/sanitizer_common/sanitizer_coverage_win_weak_interception.cc deleted file mode 100644 index 1fd10d5b83a1..000000000000 --- a/lib/sanitizer_common/sanitizer_coverage_win_weak_interception.cc +++ /dev/null @@ -1,23 +0,0 @@ -//===-- sanitizer_coverage_win_weak_interception.cc -----------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// This module should be included in Sanitizer Coverage when it implemented as a -// shared library on Windows (dll), in order to delegate the calls of weak -// functions to the implementation in the main executable when a strong -// definition is provided. -//===----------------------------------------------------------------------===// -#ifdef SANITIZER_DYNAMIC -#include "sanitizer_win_weak_interception.h" -#include "sanitizer_interface_internal.h" -#include "sancov_flags.h" -// Check if strong definitions for weak functions are present in the main -// executable. If that is the case, override dll functions to point to strong -// implementations. -#define INTERFACE_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) -#include "sanitizer_coverage_interface.inc" -#endif // SANITIZER_DYNAMIC diff --git a/lib/sanitizer_common/sanitizer_coverage_win_weak_interception.cpp b/lib/sanitizer_common/sanitizer_coverage_win_weak_interception.cpp new file mode 100644 index 000000000000..55263981705f --- /dev/null +++ b/lib/sanitizer_common/sanitizer_coverage_win_weak_interception.cpp @@ -0,0 +1,23 @@ +//===-- sanitizer_coverage_win_weak_interception.cpp ----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// This module should be included in Sanitizer Coverage when it implemented as a +// shared library on Windows (dll), in order to delegate the calls of weak +// functions to the implementation in the main executable when a strong +// definition is provided. +//===----------------------------------------------------------------------===// +#ifdef SANITIZER_DYNAMIC +#include "sanitizer_win_weak_interception.h" +#include "sanitizer_interface_internal.h" +#include "sancov_flags.h" +// Check if strong definitions for weak functions are present in the main +// executable. If that is the case, override dll functions to point to strong +// implementations. +#define INTERFACE_FUNCTION(Name) +#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) +#include "sanitizer_coverage_interface.inc" +#endif // SANITIZER_DYNAMIC diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector1.cc b/lib/sanitizer_common/sanitizer_deadlock_detector1.cc deleted file mode 100644 index a151a190c180..000000000000 --- a/lib/sanitizer_common/sanitizer_deadlock_detector1.cc +++ /dev/null @@ -1,194 +0,0 @@ -//===-- sanitizer_deadlock_detector1.cc -----------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Deadlock detector implementation based on NxN adjacency bit matrix. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_deadlock_detector_interface.h" -#include "sanitizer_deadlock_detector.h" -#include "sanitizer_allocator_internal.h" -#include "sanitizer_placement_new.h" -#include "sanitizer_mutex.h" - -#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1 - -namespace __sanitizer { - -typedef TwoLevelBitVector<> DDBV; // DeadlockDetector's bit vector. - -struct DDPhysicalThread { -}; - -struct DDLogicalThread { - u64 ctx; - DeadlockDetectorTLS dd; - DDReport rep; - bool report_pending; -}; - -struct DD : public DDetector { - SpinMutex mtx; - DeadlockDetector dd; - DDFlags flags; - - explicit DD(const DDFlags *flags); - - DDPhysicalThread *CreatePhysicalThread() override; - void DestroyPhysicalThread(DDPhysicalThread *pt) override; - - DDLogicalThread *CreateLogicalThread(u64 ctx) override; - void DestroyLogicalThread(DDLogicalThread *lt) override; - - void MutexInit(DDCallback *cb, DDMutex *m) override; - void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) override; - void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, - bool trylock) override; - void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) override; - void MutexDestroy(DDCallback *cb, DDMutex *m) override; - - DDReport *GetReport(DDCallback *cb) override; - - void MutexEnsureID(DDLogicalThread *lt, DDMutex *m); - void ReportDeadlock(DDCallback *cb, DDMutex *m); -}; - -DDetector *DDetector::Create(const DDFlags *flags) { - (void)flags; - void *mem = MmapOrDie(sizeof(DD), "deadlock detector"); - return new(mem) DD(flags); -} - -DD::DD(const DDFlags *flags) - : flags(*flags) { - dd.clear(); -} - -DDPhysicalThread* DD::CreatePhysicalThread() { - return nullptr; -} - -void DD::DestroyPhysicalThread(DDPhysicalThread *pt) { -} - -DDLogicalThread* DD::CreateLogicalThread(u64 ctx) { - DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc(sizeof(*lt)); - lt->ctx = ctx; - lt->dd.clear(); - lt->report_pending = false; - return lt; -} - -void DD::DestroyLogicalThread(DDLogicalThread *lt) { - lt->~DDLogicalThread(); - InternalFree(lt); -} - -void DD::MutexInit(DDCallback *cb, DDMutex *m) { - m->id = 0; - m->stk = cb->Unwind(); -} - -void DD::MutexEnsureID(DDLogicalThread *lt, DDMutex *m) { - if (!dd.nodeBelongsToCurrentEpoch(m->id)) - m->id = dd.newNode(reinterpret_cast(m)); - dd.ensureCurrentEpoch(<->dd); -} - -void DD::MutexBeforeLock(DDCallback *cb, - DDMutex *m, bool wlock) { - DDLogicalThread *lt = cb->lt; - if (lt->dd.empty()) return; // This will be the first lock held by lt. - if (dd.hasAllEdges(<->dd, m->id)) return; // We already have all edges. - SpinMutexLock lk(&mtx); - MutexEnsureID(lt, m); - if (dd.isHeld(<->dd, m->id)) - return; // FIXME: allow this only for recursive locks. - if (dd.onLockBefore(<->dd, m->id)) { - // Actually add this edge now so that we have all the stack traces. - dd.addEdges(<->dd, m->id, cb->Unwind(), cb->UniqueTid()); - ReportDeadlock(cb, m); - } -} - -void DD::ReportDeadlock(DDCallback *cb, DDMutex *m) { - DDLogicalThread *lt = cb->lt; - uptr path[20]; - uptr len = dd.findPathToLock(<->dd, m->id, path, ARRAY_SIZE(path)); - if (len == 0U) { - // A cycle of 20+ locks? Well, that's a bit odd... - Printf("WARNING: too long mutex cycle found\n"); - return; - } - CHECK_EQ(m->id, path[0]); - lt->report_pending = true; - len = Min(len, DDReport::kMaxLoopSize); - DDReport *rep = <->rep; - rep->n = len; - for (uptr i = 0; i < len; i++) { - uptr from = path[i]; - uptr to = path[(i + 1) % len]; - DDMutex *m0 = (DDMutex*)dd.getData(from); - DDMutex *m1 = (DDMutex*)dd.getData(to); - - u32 stk_from = -1U, stk_to = -1U; - int unique_tid = 0; - dd.findEdge(from, to, &stk_from, &stk_to, &unique_tid); - // Printf("Edge: %zd=>%zd: %u/%u T%d\n", from, to, stk_from, stk_to, - // unique_tid); - rep->loop[i].thr_ctx = unique_tid; - rep->loop[i].mtx_ctx0 = m0->ctx; - rep->loop[i].mtx_ctx1 = m1->ctx; - rep->loop[i].stk[0] = stk_to; - rep->loop[i].stk[1] = stk_from; - } -} - -void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock) { - DDLogicalThread *lt = cb->lt; - u32 stk = 0; - if (flags.second_deadlock_stack) - stk = cb->Unwind(); - // Printf("T%p MutexLock: %zx stk %u\n", lt, m->id, stk); - if (dd.onFirstLock(<->dd, m->id, stk)) - return; - if (dd.onLockFast(<->dd, m->id, stk)) - return; - - SpinMutexLock lk(&mtx); - MutexEnsureID(lt, m); - if (wlock) // Only a recursive rlock may be held. - CHECK(!dd.isHeld(<->dd, m->id)); - if (!trylock) - dd.addEdges(<->dd, m->id, stk ? stk : cb->Unwind(), cb->UniqueTid()); - dd.onLockAfter(<->dd, m->id, stk); -} - -void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) { - // Printf("T%p MutexUnLock: %zx\n", cb->lt, m->id); - dd.onUnlock(&cb->lt->dd, m->id); -} - -void DD::MutexDestroy(DDCallback *cb, - DDMutex *m) { - if (!m->id) return; - SpinMutexLock lk(&mtx); - if (dd.nodeBelongsToCurrentEpoch(m->id)) - dd.removeNode(m->id); - m->id = 0; -} - -DDReport *DD::GetReport(DDCallback *cb) { - if (!cb->lt->report_pending) - return nullptr; - cb->lt->report_pending = false; - return &cb->lt->rep; -} - -} // namespace __sanitizer -#endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1 diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector1.cpp b/lib/sanitizer_common/sanitizer_deadlock_detector1.cpp new file mode 100644 index 000000000000..d4a325bea4b2 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_deadlock_detector1.cpp @@ -0,0 +1,194 @@ +//===-- sanitizer_deadlock_detector1.cpp ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Deadlock detector implementation based on NxN adjacency bit matrix. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_deadlock_detector_interface.h" +#include "sanitizer_deadlock_detector.h" +#include "sanitizer_allocator_internal.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_mutex.h" + +#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1 + +namespace __sanitizer { + +typedef TwoLevelBitVector<> DDBV; // DeadlockDetector's bit vector. + +struct DDPhysicalThread { +}; + +struct DDLogicalThread { + u64 ctx; + DeadlockDetectorTLS dd; + DDReport rep; + bool report_pending; +}; + +struct DD : public DDetector { + SpinMutex mtx; + DeadlockDetector dd; + DDFlags flags; + + explicit DD(const DDFlags *flags); + + DDPhysicalThread *CreatePhysicalThread() override; + void DestroyPhysicalThread(DDPhysicalThread *pt) override; + + DDLogicalThread *CreateLogicalThread(u64 ctx) override; + void DestroyLogicalThread(DDLogicalThread *lt) override; + + void MutexInit(DDCallback *cb, DDMutex *m) override; + void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) override; + void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, + bool trylock) override; + void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) override; + void MutexDestroy(DDCallback *cb, DDMutex *m) override; + + DDReport *GetReport(DDCallback *cb) override; + + void MutexEnsureID(DDLogicalThread *lt, DDMutex *m); + void ReportDeadlock(DDCallback *cb, DDMutex *m); +}; + +DDetector *DDetector::Create(const DDFlags *flags) { + (void)flags; + void *mem = MmapOrDie(sizeof(DD), "deadlock detector"); + return new(mem) DD(flags); +} + +DD::DD(const DDFlags *flags) + : flags(*flags) { + dd.clear(); +} + +DDPhysicalThread* DD::CreatePhysicalThread() { + return nullptr; +} + +void DD::DestroyPhysicalThread(DDPhysicalThread *pt) { +} + +DDLogicalThread* DD::CreateLogicalThread(u64 ctx) { + DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc(sizeof(*lt)); + lt->ctx = ctx; + lt->dd.clear(); + lt->report_pending = false; + return lt; +} + +void DD::DestroyLogicalThread(DDLogicalThread *lt) { + lt->~DDLogicalThread(); + InternalFree(lt); +} + +void DD::MutexInit(DDCallback *cb, DDMutex *m) { + m->id = 0; + m->stk = cb->Unwind(); +} + +void DD::MutexEnsureID(DDLogicalThread *lt, DDMutex *m) { + if (!dd.nodeBelongsToCurrentEpoch(m->id)) + m->id = dd.newNode(reinterpret_cast(m)); + dd.ensureCurrentEpoch(<->dd); +} + +void DD::MutexBeforeLock(DDCallback *cb, + DDMutex *m, bool wlock) { + DDLogicalThread *lt = cb->lt; + if (lt->dd.empty()) return; // This will be the first lock held by lt. + if (dd.hasAllEdges(<->dd, m->id)) return; // We already have all edges. + SpinMutexLock lk(&mtx); + MutexEnsureID(lt, m); + if (dd.isHeld(<->dd, m->id)) + return; // FIXME: allow this only for recursive locks. + if (dd.onLockBefore(<->dd, m->id)) { + // Actually add this edge now so that we have all the stack traces. + dd.addEdges(<->dd, m->id, cb->Unwind(), cb->UniqueTid()); + ReportDeadlock(cb, m); + } +} + +void DD::ReportDeadlock(DDCallback *cb, DDMutex *m) { + DDLogicalThread *lt = cb->lt; + uptr path[20]; + uptr len = dd.findPathToLock(<->dd, m->id, path, ARRAY_SIZE(path)); + if (len == 0U) { + // A cycle of 20+ locks? Well, that's a bit odd... + Printf("WARNING: too long mutex cycle found\n"); + return; + } + CHECK_EQ(m->id, path[0]); + lt->report_pending = true; + len = Min(len, DDReport::kMaxLoopSize); + DDReport *rep = <->rep; + rep->n = len; + for (uptr i = 0; i < len; i++) { + uptr from = path[i]; + uptr to = path[(i + 1) % len]; + DDMutex *m0 = (DDMutex*)dd.getData(from); + DDMutex *m1 = (DDMutex*)dd.getData(to); + + u32 stk_from = -1U, stk_to = -1U; + int unique_tid = 0; + dd.findEdge(from, to, &stk_from, &stk_to, &unique_tid); + // Printf("Edge: %zd=>%zd: %u/%u T%d\n", from, to, stk_from, stk_to, + // unique_tid); + rep->loop[i].thr_ctx = unique_tid; + rep->loop[i].mtx_ctx0 = m0->ctx; + rep->loop[i].mtx_ctx1 = m1->ctx; + rep->loop[i].stk[0] = stk_to; + rep->loop[i].stk[1] = stk_from; + } +} + +void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock) { + DDLogicalThread *lt = cb->lt; + u32 stk = 0; + if (flags.second_deadlock_stack) + stk = cb->Unwind(); + // Printf("T%p MutexLock: %zx stk %u\n", lt, m->id, stk); + if (dd.onFirstLock(<->dd, m->id, stk)) + return; + if (dd.onLockFast(<->dd, m->id, stk)) + return; + + SpinMutexLock lk(&mtx); + MutexEnsureID(lt, m); + if (wlock) // Only a recursive rlock may be held. + CHECK(!dd.isHeld(<->dd, m->id)); + if (!trylock) + dd.addEdges(<->dd, m->id, stk ? stk : cb->Unwind(), cb->UniqueTid()); + dd.onLockAfter(<->dd, m->id, stk); +} + +void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) { + // Printf("T%p MutexUnLock: %zx\n", cb->lt, m->id); + dd.onUnlock(&cb->lt->dd, m->id); +} + +void DD::MutexDestroy(DDCallback *cb, + DDMutex *m) { + if (!m->id) return; + SpinMutexLock lk(&mtx); + if (dd.nodeBelongsToCurrentEpoch(m->id)) + dd.removeNode(m->id); + m->id = 0; +} + +DDReport *DD::GetReport(DDCallback *cb) { + if (!cb->lt->report_pending) + return nullptr; + cb->lt->report_pending = false; + return &cb->lt->rep; +} + +} // namespace __sanitizer +#endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1 diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector2.cc b/lib/sanitizer_common/sanitizer_deadlock_detector2.cc deleted file mode 100644 index ed9ea26d3902..000000000000 --- a/lib/sanitizer_common/sanitizer_deadlock_detector2.cc +++ /dev/null @@ -1,423 +0,0 @@ -//===-- sanitizer_deadlock_detector2.cc -----------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Deadlock detector implementation based on adjacency lists. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_deadlock_detector_interface.h" -#include "sanitizer_common.h" -#include "sanitizer_allocator_internal.h" -#include "sanitizer_placement_new.h" -#include "sanitizer_mutex.h" - -#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 2 - -namespace __sanitizer { - -const int kMaxNesting = 64; -const u32 kNoId = -1; -const u32 kEndId = -2; -const int kMaxLink = 8; -const int kL1Size = 1024; -const int kL2Size = 1024; -const int kMaxMutex = kL1Size * kL2Size; - -struct Id { - u32 id; - u32 seq; - - explicit Id(u32 id = 0, u32 seq = 0) - : id(id) - , seq(seq) { - } -}; - -struct Link { - u32 id; - u32 seq; - u32 tid; - u32 stk0; - u32 stk1; - - explicit Link(u32 id = 0, u32 seq = 0, u32 tid = 0, u32 s0 = 0, u32 s1 = 0) - : id(id) - , seq(seq) - , tid(tid) - , stk0(s0) - , stk1(s1) { - } -}; - -struct DDPhysicalThread { - DDReport rep; - bool report_pending; - bool visited[kMaxMutex]; - Link pending[kMaxMutex]; - Link path[kMaxMutex]; -}; - -struct ThreadMutex { - u32 id; - u32 stk; -}; - -struct DDLogicalThread { - u64 ctx; - ThreadMutex locked[kMaxNesting]; - int nlocked; -}; - -struct Mutex { - StaticSpinMutex mtx; - u32 seq; - int nlink; - Link link[kMaxLink]; -}; - -struct DD : public DDetector { - explicit DD(const DDFlags *flags); - - DDPhysicalThread* CreatePhysicalThread(); - void DestroyPhysicalThread(DDPhysicalThread *pt); - - DDLogicalThread* CreateLogicalThread(u64 ctx); - void DestroyLogicalThread(DDLogicalThread *lt); - - void MutexInit(DDCallback *cb, DDMutex *m); - void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock); - void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, - bool trylock); - void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock); - void MutexDestroy(DDCallback *cb, DDMutex *m); - - DDReport *GetReport(DDCallback *cb); - - void CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt, DDMutex *mtx); - void Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath); - u32 allocateId(DDCallback *cb); - Mutex *getMutex(u32 id); - u32 getMutexId(Mutex *m); - - DDFlags flags; - - Mutex* mutex[kL1Size]; - - SpinMutex mtx; - InternalMmapVector free_id; - int id_gen = 0; -}; - -DDetector *DDetector::Create(const DDFlags *flags) { - (void)flags; - void *mem = MmapOrDie(sizeof(DD), "deadlock detector"); - return new(mem) DD(flags); -} - -DD::DD(const DDFlags *flags) : flags(*flags) { free_id.reserve(1024); } - -DDPhysicalThread* DD::CreatePhysicalThread() { - DDPhysicalThread *pt = (DDPhysicalThread*)MmapOrDie(sizeof(DDPhysicalThread), - "deadlock detector (physical thread)"); - return pt; -} - -void DD::DestroyPhysicalThread(DDPhysicalThread *pt) { - pt->~DDPhysicalThread(); - UnmapOrDie(pt, sizeof(DDPhysicalThread)); -} - -DDLogicalThread* DD::CreateLogicalThread(u64 ctx) { - DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc( - sizeof(DDLogicalThread)); - lt->ctx = ctx; - lt->nlocked = 0; - return lt; -} - -void DD::DestroyLogicalThread(DDLogicalThread *lt) { - lt->~DDLogicalThread(); - InternalFree(lt); -} - -void DD::MutexInit(DDCallback *cb, DDMutex *m) { - VPrintf(2, "#%llu: DD::MutexInit(%p)\n", cb->lt->ctx, m); - m->id = kNoId; - m->recursion = 0; - atomic_store(&m->owner, 0, memory_order_relaxed); -} - -Mutex *DD::getMutex(u32 id) { - return &mutex[id / kL2Size][id % kL2Size]; -} - -u32 DD::getMutexId(Mutex *m) { - for (int i = 0; i < kL1Size; i++) { - Mutex *tab = mutex[i]; - if (tab == 0) - break; - if (m >= tab && m < tab + kL2Size) - return i * kL2Size + (m - tab); - } - return -1; -} - -u32 DD::allocateId(DDCallback *cb) { - u32 id = -1; - SpinMutexLock l(&mtx); - if (free_id.size() > 0) { - id = free_id.back(); - free_id.pop_back(); - } else { - CHECK_LT(id_gen, kMaxMutex); - if ((id_gen % kL2Size) == 0) { - mutex[id_gen / kL2Size] = (Mutex*)MmapOrDie(kL2Size * sizeof(Mutex), - "deadlock detector (mutex table)"); - } - id = id_gen++; - } - CHECK_LE(id, kMaxMutex); - VPrintf(3, "#%llu: DD::allocateId assign id %d\n", cb->lt->ctx, id); - return id; -} - -void DD::MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) { - VPrintf(2, "#%llu: DD::MutexBeforeLock(%p, wlock=%d) nlocked=%d\n", - cb->lt->ctx, m, wlock, cb->lt->nlocked); - DDPhysicalThread *pt = cb->pt; - DDLogicalThread *lt = cb->lt; - - uptr owner = atomic_load(&m->owner, memory_order_relaxed); - if (owner == (uptr)cb->lt) { - VPrintf(3, "#%llu: DD::MutexBeforeLock recursive\n", - cb->lt->ctx); - return; - } - - CHECK_LE(lt->nlocked, kMaxNesting); - - // FIXME(dvyukov): don't allocate id if lt->nlocked == 0? - if (m->id == kNoId) - m->id = allocateId(cb); - - ThreadMutex *tm = <->locked[lt->nlocked++]; - tm->id = m->id; - if (flags.second_deadlock_stack) - tm->stk = cb->Unwind(); - if (lt->nlocked == 1) { - VPrintf(3, "#%llu: DD::MutexBeforeLock first mutex\n", - cb->lt->ctx); - return; - } - - bool added = false; - Mutex *mtx = getMutex(m->id); - for (int i = 0; i < lt->nlocked - 1; i++) { - u32 id1 = lt->locked[i].id; - u32 stk1 = lt->locked[i].stk; - Mutex *mtx1 = getMutex(id1); - SpinMutexLock l(&mtx1->mtx); - if (mtx1->nlink == kMaxLink) { - // FIXME(dvyukov): check stale links - continue; - } - int li = 0; - for (; li < mtx1->nlink; li++) { - Link *link = &mtx1->link[li]; - if (link->id == m->id) { - if (link->seq != mtx->seq) { - link->seq = mtx->seq; - link->tid = lt->ctx; - link->stk0 = stk1; - link->stk1 = cb->Unwind(); - added = true; - VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n", - cb->lt->ctx, getMutexId(mtx1), m->id); - } - break; - } - } - if (li == mtx1->nlink) { - // FIXME(dvyukov): check stale links - Link *link = &mtx1->link[mtx1->nlink++]; - link->id = m->id; - link->seq = mtx->seq; - link->tid = lt->ctx; - link->stk0 = stk1; - link->stk1 = cb->Unwind(); - added = true; - VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n", - cb->lt->ctx, getMutexId(mtx1), m->id); - } - } - - if (!added || mtx->nlink == 0) { - VPrintf(3, "#%llu: DD::MutexBeforeLock don't check\n", - cb->lt->ctx); - return; - } - - CycleCheck(pt, lt, m); -} - -void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, - bool trylock) { - VPrintf(2, "#%llu: DD::MutexAfterLock(%p, wlock=%d, try=%d) nlocked=%d\n", - cb->lt->ctx, m, wlock, trylock, cb->lt->nlocked); - DDLogicalThread *lt = cb->lt; - - uptr owner = atomic_load(&m->owner, memory_order_relaxed); - if (owner == (uptr)cb->lt) { - VPrintf(3, "#%llu: DD::MutexAfterLock recursive\n", cb->lt->ctx); - CHECK(wlock); - m->recursion++; - return; - } - CHECK_EQ(owner, 0); - if (wlock) { - VPrintf(3, "#%llu: DD::MutexAfterLock set owner\n", cb->lt->ctx); - CHECK_EQ(m->recursion, 0); - m->recursion = 1; - atomic_store(&m->owner, (uptr)cb->lt, memory_order_relaxed); - } - - if (!trylock) - return; - - CHECK_LE(lt->nlocked, kMaxNesting); - if (m->id == kNoId) - m->id = allocateId(cb); - ThreadMutex *tm = <->locked[lt->nlocked++]; - tm->id = m->id; - if (flags.second_deadlock_stack) - tm->stk = cb->Unwind(); -} - -void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) { - VPrintf(2, "#%llu: DD::MutexBeforeUnlock(%p, wlock=%d) nlocked=%d\n", - cb->lt->ctx, m, wlock, cb->lt->nlocked); - DDLogicalThread *lt = cb->lt; - - uptr owner = atomic_load(&m->owner, memory_order_relaxed); - if (owner == (uptr)cb->lt) { - VPrintf(3, "#%llu: DD::MutexBeforeUnlock recursive\n", cb->lt->ctx); - if (--m->recursion > 0) - return; - VPrintf(3, "#%llu: DD::MutexBeforeUnlock reset owner\n", cb->lt->ctx); - atomic_store(&m->owner, 0, memory_order_relaxed); - } - CHECK_NE(m->id, kNoId); - int last = lt->nlocked - 1; - for (int i = last; i >= 0; i--) { - if (cb->lt->locked[i].id == m->id) { - lt->locked[i] = lt->locked[last]; - lt->nlocked--; - break; - } - } -} - -void DD::MutexDestroy(DDCallback *cb, DDMutex *m) { - VPrintf(2, "#%llu: DD::MutexDestroy(%p)\n", - cb->lt->ctx, m); - DDLogicalThread *lt = cb->lt; - - if (m->id == kNoId) - return; - - // Remove the mutex from lt->locked if there. - int last = lt->nlocked - 1; - for (int i = last; i >= 0; i--) { - if (lt->locked[i].id == m->id) { - lt->locked[i] = lt->locked[last]; - lt->nlocked--; - break; - } - } - - // Clear and invalidate the mutex descriptor. - { - Mutex *mtx = getMutex(m->id); - SpinMutexLock l(&mtx->mtx); - mtx->seq++; - mtx->nlink = 0; - } - - // Return id to cache. - { - SpinMutexLock l(&mtx); - free_id.push_back(m->id); - } -} - -void DD::CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt, - DDMutex *m) { - internal_memset(pt->visited, 0, sizeof(pt->visited)); - int npath = 0; - int npending = 0; - { - Mutex *mtx = getMutex(m->id); - SpinMutexLock l(&mtx->mtx); - for (int li = 0; li < mtx->nlink; li++) - pt->pending[npending++] = mtx->link[li]; - } - while (npending > 0) { - Link link = pt->pending[--npending]; - if (link.id == kEndId) { - npath--; - continue; - } - if (pt->visited[link.id]) - continue; - Mutex *mtx1 = getMutex(link.id); - SpinMutexLock l(&mtx1->mtx); - if (mtx1->seq != link.seq) - continue; - pt->visited[link.id] = true; - if (mtx1->nlink == 0) - continue; - pt->path[npath++] = link; - pt->pending[npending++] = Link(kEndId); - if (link.id == m->id) - return Report(pt, lt, npath); // Bingo! - for (int li = 0; li < mtx1->nlink; li++) { - Link *link1 = &mtx1->link[li]; - // Mutex *mtx2 = getMutex(link->id); - // FIXME(dvyukov): fast seq check - // FIXME(dvyukov): fast nlink != 0 check - // FIXME(dvyukov): fast pending check? - // FIXME(dvyukov): npending can be larger than kMaxMutex - pt->pending[npending++] = *link1; - } - } -} - -void DD::Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath) { - DDReport *rep = &pt->rep; - rep->n = npath; - for (int i = 0; i < npath; i++) { - Link *link = &pt->path[i]; - Link *link0 = &pt->path[i ? i - 1 : npath - 1]; - rep->loop[i].thr_ctx = link->tid; - rep->loop[i].mtx_ctx0 = link0->id; - rep->loop[i].mtx_ctx1 = link->id; - rep->loop[i].stk[0] = flags.second_deadlock_stack ? link->stk0 : 0; - rep->loop[i].stk[1] = link->stk1; - } - pt->report_pending = true; -} - -DDReport *DD::GetReport(DDCallback *cb) { - if (!cb->pt->report_pending) - return 0; - cb->pt->report_pending = false; - return &cb->pt->rep; -} - -} // namespace __sanitizer -#endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 2 diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector2.cpp b/lib/sanitizer_common/sanitizer_deadlock_detector2.cpp new file mode 100644 index 000000000000..4026739d4e51 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_deadlock_detector2.cpp @@ -0,0 +1,423 @@ +//===-- sanitizer_deadlock_detector2.cpp ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Deadlock detector implementation based on adjacency lists. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_deadlock_detector_interface.h" +#include "sanitizer_common.h" +#include "sanitizer_allocator_internal.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_mutex.h" + +#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 2 + +namespace __sanitizer { + +const int kMaxNesting = 64; +const u32 kNoId = -1; +const u32 kEndId = -2; +const int kMaxLink = 8; +const int kL1Size = 1024; +const int kL2Size = 1024; +const int kMaxMutex = kL1Size * kL2Size; + +struct Id { + u32 id; + u32 seq; + + explicit Id(u32 id = 0, u32 seq = 0) + : id(id) + , seq(seq) { + } +}; + +struct Link { + u32 id; + u32 seq; + u32 tid; + u32 stk0; + u32 stk1; + + explicit Link(u32 id = 0, u32 seq = 0, u32 tid = 0, u32 s0 = 0, u32 s1 = 0) + : id(id) + , seq(seq) + , tid(tid) + , stk0(s0) + , stk1(s1) { + } +}; + +struct DDPhysicalThread { + DDReport rep; + bool report_pending; + bool visited[kMaxMutex]; + Link pending[kMaxMutex]; + Link path[kMaxMutex]; +}; + +struct ThreadMutex { + u32 id; + u32 stk; +}; + +struct DDLogicalThread { + u64 ctx; + ThreadMutex locked[kMaxNesting]; + int nlocked; +}; + +struct Mutex { + StaticSpinMutex mtx; + u32 seq; + int nlink; + Link link[kMaxLink]; +}; + +struct DD : public DDetector { + explicit DD(const DDFlags *flags); + + DDPhysicalThread* CreatePhysicalThread(); + void DestroyPhysicalThread(DDPhysicalThread *pt); + + DDLogicalThread* CreateLogicalThread(u64 ctx); + void DestroyLogicalThread(DDLogicalThread *lt); + + void MutexInit(DDCallback *cb, DDMutex *m); + void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock); + void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, + bool trylock); + void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock); + void MutexDestroy(DDCallback *cb, DDMutex *m); + + DDReport *GetReport(DDCallback *cb); + + void CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt, DDMutex *mtx); + void Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath); + u32 allocateId(DDCallback *cb); + Mutex *getMutex(u32 id); + u32 getMutexId(Mutex *m); + + DDFlags flags; + + Mutex* mutex[kL1Size]; + + SpinMutex mtx; + InternalMmapVector free_id; + int id_gen = 0; +}; + +DDetector *DDetector::Create(const DDFlags *flags) { + (void)flags; + void *mem = MmapOrDie(sizeof(DD), "deadlock detector"); + return new(mem) DD(flags); +} + +DD::DD(const DDFlags *flags) : flags(*flags) { free_id.reserve(1024); } + +DDPhysicalThread* DD::CreatePhysicalThread() { + DDPhysicalThread *pt = (DDPhysicalThread*)MmapOrDie(sizeof(DDPhysicalThread), + "deadlock detector (physical thread)"); + return pt; +} + +void DD::DestroyPhysicalThread(DDPhysicalThread *pt) { + pt->~DDPhysicalThread(); + UnmapOrDie(pt, sizeof(DDPhysicalThread)); +} + +DDLogicalThread* DD::CreateLogicalThread(u64 ctx) { + DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc( + sizeof(DDLogicalThread)); + lt->ctx = ctx; + lt->nlocked = 0; + return lt; +} + +void DD::DestroyLogicalThread(DDLogicalThread *lt) { + lt->~DDLogicalThread(); + InternalFree(lt); +} + +void DD::MutexInit(DDCallback *cb, DDMutex *m) { + VPrintf(2, "#%llu: DD::MutexInit(%p)\n", cb->lt->ctx, m); + m->id = kNoId; + m->recursion = 0; + atomic_store(&m->owner, 0, memory_order_relaxed); +} + +Mutex *DD::getMutex(u32 id) { + return &mutex[id / kL2Size][id % kL2Size]; +} + +u32 DD::getMutexId(Mutex *m) { + for (int i = 0; i < kL1Size; i++) { + Mutex *tab = mutex[i]; + if (tab == 0) + break; + if (m >= tab && m < tab + kL2Size) + return i * kL2Size + (m - tab); + } + return -1; +} + +u32 DD::allocateId(DDCallback *cb) { + u32 id = -1; + SpinMutexLock l(&mtx); + if (free_id.size() > 0) { + id = free_id.back(); + free_id.pop_back(); + } else { + CHECK_LT(id_gen, kMaxMutex); + if ((id_gen % kL2Size) == 0) { + mutex[id_gen / kL2Size] = (Mutex*)MmapOrDie(kL2Size * sizeof(Mutex), + "deadlock detector (mutex table)"); + } + id = id_gen++; + } + CHECK_LE(id, kMaxMutex); + VPrintf(3, "#%llu: DD::allocateId assign id %d\n", cb->lt->ctx, id); + return id; +} + +void DD::MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) { + VPrintf(2, "#%llu: DD::MutexBeforeLock(%p, wlock=%d) nlocked=%d\n", + cb->lt->ctx, m, wlock, cb->lt->nlocked); + DDPhysicalThread *pt = cb->pt; + DDLogicalThread *lt = cb->lt; + + uptr owner = atomic_load(&m->owner, memory_order_relaxed); + if (owner == (uptr)cb->lt) { + VPrintf(3, "#%llu: DD::MutexBeforeLock recursive\n", + cb->lt->ctx); + return; + } + + CHECK_LE(lt->nlocked, kMaxNesting); + + // FIXME(dvyukov): don't allocate id if lt->nlocked == 0? + if (m->id == kNoId) + m->id = allocateId(cb); + + ThreadMutex *tm = <->locked[lt->nlocked++]; + tm->id = m->id; + if (flags.second_deadlock_stack) + tm->stk = cb->Unwind(); + if (lt->nlocked == 1) { + VPrintf(3, "#%llu: DD::MutexBeforeLock first mutex\n", + cb->lt->ctx); + return; + } + + bool added = false; + Mutex *mtx = getMutex(m->id); + for (int i = 0; i < lt->nlocked - 1; i++) { + u32 id1 = lt->locked[i].id; + u32 stk1 = lt->locked[i].stk; + Mutex *mtx1 = getMutex(id1); + SpinMutexLock l(&mtx1->mtx); + if (mtx1->nlink == kMaxLink) { + // FIXME(dvyukov): check stale links + continue; + } + int li = 0; + for (; li < mtx1->nlink; li++) { + Link *link = &mtx1->link[li]; + if (link->id == m->id) { + if (link->seq != mtx->seq) { + link->seq = mtx->seq; + link->tid = lt->ctx; + link->stk0 = stk1; + link->stk1 = cb->Unwind(); + added = true; + VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n", + cb->lt->ctx, getMutexId(mtx1), m->id); + } + break; + } + } + if (li == mtx1->nlink) { + // FIXME(dvyukov): check stale links + Link *link = &mtx1->link[mtx1->nlink++]; + link->id = m->id; + link->seq = mtx->seq; + link->tid = lt->ctx; + link->stk0 = stk1; + link->stk1 = cb->Unwind(); + added = true; + VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n", + cb->lt->ctx, getMutexId(mtx1), m->id); + } + } + + if (!added || mtx->nlink == 0) { + VPrintf(3, "#%llu: DD::MutexBeforeLock don't check\n", + cb->lt->ctx); + return; + } + + CycleCheck(pt, lt, m); +} + +void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, + bool trylock) { + VPrintf(2, "#%llu: DD::MutexAfterLock(%p, wlock=%d, try=%d) nlocked=%d\n", + cb->lt->ctx, m, wlock, trylock, cb->lt->nlocked); + DDLogicalThread *lt = cb->lt; + + uptr owner = atomic_load(&m->owner, memory_order_relaxed); + if (owner == (uptr)cb->lt) { + VPrintf(3, "#%llu: DD::MutexAfterLock recursive\n", cb->lt->ctx); + CHECK(wlock); + m->recursion++; + return; + } + CHECK_EQ(owner, 0); + if (wlock) { + VPrintf(3, "#%llu: DD::MutexAfterLock set owner\n", cb->lt->ctx); + CHECK_EQ(m->recursion, 0); + m->recursion = 1; + atomic_store(&m->owner, (uptr)cb->lt, memory_order_relaxed); + } + + if (!trylock) + return; + + CHECK_LE(lt->nlocked, kMaxNesting); + if (m->id == kNoId) + m->id = allocateId(cb); + ThreadMutex *tm = <->locked[lt->nlocked++]; + tm->id = m->id; + if (flags.second_deadlock_stack) + tm->stk = cb->Unwind(); +} + +void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) { + VPrintf(2, "#%llu: DD::MutexBeforeUnlock(%p, wlock=%d) nlocked=%d\n", + cb->lt->ctx, m, wlock, cb->lt->nlocked); + DDLogicalThread *lt = cb->lt; + + uptr owner = atomic_load(&m->owner, memory_order_relaxed); + if (owner == (uptr)cb->lt) { + VPrintf(3, "#%llu: DD::MutexBeforeUnlock recursive\n", cb->lt->ctx); + if (--m->recursion > 0) + return; + VPrintf(3, "#%llu: DD::MutexBeforeUnlock reset owner\n", cb->lt->ctx); + atomic_store(&m->owner, 0, memory_order_relaxed); + } + CHECK_NE(m->id, kNoId); + int last = lt->nlocked - 1; + for (int i = last; i >= 0; i--) { + if (cb->lt->locked[i].id == m->id) { + lt->locked[i] = lt->locked[last]; + lt->nlocked--; + break; + } + } +} + +void DD::MutexDestroy(DDCallback *cb, DDMutex *m) { + VPrintf(2, "#%llu: DD::MutexDestroy(%p)\n", + cb->lt->ctx, m); + DDLogicalThread *lt = cb->lt; + + if (m->id == kNoId) + return; + + // Remove the mutex from lt->locked if there. + int last = lt->nlocked - 1; + for (int i = last; i >= 0; i--) { + if (lt->locked[i].id == m->id) { + lt->locked[i] = lt->locked[last]; + lt->nlocked--; + break; + } + } + + // Clear and invalidate the mutex descriptor. + { + Mutex *mtx = getMutex(m->id); + SpinMutexLock l(&mtx->mtx); + mtx->seq++; + mtx->nlink = 0; + } + + // Return id to cache. + { + SpinMutexLock l(&mtx); + free_id.push_back(m->id); + } +} + +void DD::CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt, + DDMutex *m) { + internal_memset(pt->visited, 0, sizeof(pt->visited)); + int npath = 0; + int npending = 0; + { + Mutex *mtx = getMutex(m->id); + SpinMutexLock l(&mtx->mtx); + for (int li = 0; li < mtx->nlink; li++) + pt->pending[npending++] = mtx->link[li]; + } + while (npending > 0) { + Link link = pt->pending[--npending]; + if (link.id == kEndId) { + npath--; + continue; + } + if (pt->visited[link.id]) + continue; + Mutex *mtx1 = getMutex(link.id); + SpinMutexLock l(&mtx1->mtx); + if (mtx1->seq != link.seq) + continue; + pt->visited[link.id] = true; + if (mtx1->nlink == 0) + continue; + pt->path[npath++] = link; + pt->pending[npending++] = Link(kEndId); + if (link.id == m->id) + return Report(pt, lt, npath); // Bingo! + for (int li = 0; li < mtx1->nlink; li++) { + Link *link1 = &mtx1->link[li]; + // Mutex *mtx2 = getMutex(link->id); + // FIXME(dvyukov): fast seq check + // FIXME(dvyukov): fast nlink != 0 check + // FIXME(dvyukov): fast pending check? + // FIXME(dvyukov): npending can be larger than kMaxMutex + pt->pending[npending++] = *link1; + } + } +} + +void DD::Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath) { + DDReport *rep = &pt->rep; + rep->n = npath; + for (int i = 0; i < npath; i++) { + Link *link = &pt->path[i]; + Link *link0 = &pt->path[i ? i - 1 : npath - 1]; + rep->loop[i].thr_ctx = link->tid; + rep->loop[i].mtx_ctx0 = link0->id; + rep->loop[i].mtx_ctx1 = link->id; + rep->loop[i].stk[0] = flags.second_deadlock_stack ? link->stk0 : 0; + rep->loop[i].stk[1] = link->stk1; + } + pt->report_pending = true; +} + +DDReport *DD::GetReport(DDCallback *cb) { + if (!cb->pt->report_pending) + return 0; + cb->pt->report_pending = false; + return &cb->pt->rep; +} + +} // namespace __sanitizer +#endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 2 diff --git a/lib/sanitizer_common/sanitizer_errno.cc b/lib/sanitizer_common/sanitizer_errno.cc deleted file mode 100644 index 1600de566393..000000000000 --- a/lib/sanitizer_common/sanitizer_errno.cc +++ /dev/null @@ -1,34 +0,0 @@ -//===-- sanitizer_errno.cc --------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between sanitizers run-time libraries. -// -// Defines errno to avoid including errno.h and its dependencies into other -// files (e.g. interceptors are not supposed to include any system headers). -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_errno_codes.h" -#include "sanitizer_internal_defs.h" - -#include - -namespace __sanitizer { - -COMPILER_CHECK(errno_ENOMEM == ENOMEM); -COMPILER_CHECK(errno_EBUSY == EBUSY); -COMPILER_CHECK(errno_EINVAL == EINVAL); - -// EOWNERDEAD is not present in some older platforms. -#if defined(EOWNERDEAD) -extern const int errno_EOWNERDEAD = EOWNERDEAD; -#else -extern const int errno_EOWNERDEAD = -1; -#endif - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_errno.cpp b/lib/sanitizer_common/sanitizer_errno.cpp new file mode 100644 index 000000000000..cbadf4d924a7 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_errno.cpp @@ -0,0 +1,34 @@ +//===-- sanitizer_errno.cpp -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizers run-time libraries. +// +// Defines errno to avoid including errno.h and its dependencies into other +// files (e.g. interceptors are not supposed to include any system headers). +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_errno_codes.h" +#include "sanitizer_internal_defs.h" + +#include + +namespace __sanitizer { + +COMPILER_CHECK(errno_ENOMEM == ENOMEM); +COMPILER_CHECK(errno_EBUSY == EBUSY); +COMPILER_CHECK(errno_EINVAL == EINVAL); + +// EOWNERDEAD is not present in some older platforms. +#if defined(EOWNERDEAD) +extern const int errno_EOWNERDEAD = EOWNERDEAD; +#else +extern const int errno_EOWNERDEAD = -1; +#endif + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_file.cc b/lib/sanitizer_common/sanitizer_file.cc deleted file mode 100644 index 3cb4974bdab2..000000000000 --- a/lib/sanitizer_common/sanitizer_file.cc +++ /dev/null @@ -1,215 +0,0 @@ -//===-- sanitizer_file.cc ------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===---------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. It defines filesystem-related interfaces. This -// is separate from sanitizer_common.cc so that it's simpler to disable -// all the filesystem support code for a port that doesn't use it. -// -//===---------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if !SANITIZER_FUCHSIA - -#include "sanitizer_common.h" -#include "sanitizer_file.h" - -namespace __sanitizer { - -void CatastrophicErrorWrite(const char *buffer, uptr length) { - WriteToFile(kStderrFd, buffer, length); -} - -StaticSpinMutex report_file_mu; -ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; - -void RawWrite(const char *buffer) { - report_file.Write(buffer, internal_strlen(buffer)); -} - -void ReportFile::ReopenIfNecessary() { - mu->CheckLocked(); - if (fd == kStdoutFd || fd == kStderrFd) return; - - uptr pid = internal_getpid(); - // If in tracer, use the parent's file. - if (pid == stoptheworld_tracer_pid) - pid = stoptheworld_tracer_ppid; - if (fd != kInvalidFd) { - // If the report file is already opened by the current process, - // do nothing. Otherwise the report file was opened by the parent - // process, close it now. - if (fd_pid == pid) - return; - else - CloseFile(fd); - } - - const char *exe_name = GetProcessName(); - if (common_flags()->log_exe_name && exe_name) { - internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, - exe_name, pid); - } else { - internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); - } - fd = OpenFile(full_path, WrOnly); - if (fd == kInvalidFd) { - const char *ErrorMsgPrefix = "ERROR: Can't open file: "; - WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); - WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); - Die(); - } - fd_pid = pid; -} - -void ReportFile::SetReportPath(const char *path) { - if (!path) - return; - uptr len = internal_strlen(path); - if (len > sizeof(path_prefix) - 100) { - Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", - path[0], path[1], path[2], path[3], - path[4], path[5], path[6], path[7]); - Die(); - } - - SpinMutexLock l(mu); - if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) - CloseFile(fd); - fd = kInvalidFd; - if (internal_strcmp(path, "stdout") == 0) { - fd = kStdoutFd; - } else if (internal_strcmp(path, "stderr") == 0) { - fd = kStderrFd; - } else { - internal_snprintf(path_prefix, kMaxPathLength, "%s", path); - } -} - -bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, - uptr *read_len, uptr max_len, error_t *errno_p) { - *buff = nullptr; - *buff_size = 0; - *read_len = 0; - if (!max_len) - return true; - uptr PageSize = GetPageSizeCached(); - uptr kMinFileLen = Min(PageSize, max_len); - - // The files we usually open are not seekable, so try different buffer sizes. - for (uptr size = kMinFileLen;; size = Min(size * 2, max_len)) { - UnmapOrDie(*buff, *buff_size); - *buff = (char*)MmapOrDie(size, __func__); - *buff_size = size; - fd_t fd = OpenFile(file_name, RdOnly, errno_p); - if (fd == kInvalidFd) { - UnmapOrDie(*buff, *buff_size); - return false; - } - *read_len = 0; - // Read up to one page at a time. - bool reached_eof = false; - while (*read_len < size) { - uptr just_read; - if (!ReadFromFile(fd, *buff + *read_len, size - *read_len, &just_read, - errno_p)) { - UnmapOrDie(*buff, *buff_size); - CloseFile(fd); - return false; - } - *read_len += just_read; - if (just_read == 0 || *read_len == max_len) { - reached_eof = true; - break; - } - } - CloseFile(fd); - if (reached_eof) // We've read the whole file. - break; - } - return true; -} - -bool ReadFileToVector(const char *file_name, - InternalMmapVectorNoCtor *buff, uptr max_len, - error_t *errno_p) { - buff->clear(); - if (!max_len) - return true; - uptr PageSize = GetPageSizeCached(); - fd_t fd = OpenFile(file_name, RdOnly, errno_p); - if (fd == kInvalidFd) - return false; - uptr read_len = 0; - while (read_len < max_len) { - if (read_len >= buff->size()) - buff->resize(Min(Max(PageSize, read_len * 2), max_len)); - CHECK_LT(read_len, buff->size()); - CHECK_LE(buff->size(), max_len); - uptr just_read; - if (!ReadFromFile(fd, buff->data() + read_len, buff->size() - read_len, - &just_read, errno_p)) { - CloseFile(fd); - return false; - } - read_len += just_read; - if (!just_read) - break; - } - CloseFile(fd); - buff->resize(read_len); - return true; -} - -static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; - -char *FindPathToBinary(const char *name) { - if (FileExists(name)) { - return internal_strdup(name); - } - - const char *path = GetEnv("PATH"); - if (!path) - return nullptr; - uptr name_len = internal_strlen(name); - InternalMmapVector buffer(kMaxPathLength); - const char *beg = path; - while (true) { - const char *end = internal_strchrnul(beg, kPathSeparator); - uptr prefix_len = end - beg; - if (prefix_len + name_len + 2 <= kMaxPathLength) { - internal_memcpy(buffer.data(), beg, prefix_len); - buffer[prefix_len] = '/'; - internal_memcpy(&buffer[prefix_len + 1], name, name_len); - buffer[prefix_len + 1 + name_len] = '\0'; - if (FileExists(buffer.data())) - return internal_strdup(buffer.data()); - } - if (*end == '\0') break; - beg = end + 1; - } - return nullptr; -} - -} // namespace __sanitizer - -using namespace __sanitizer; // NOLINT - -extern "C" { -void __sanitizer_set_report_path(const char *path) { - report_file.SetReportPath(path); -} - -void __sanitizer_set_report_fd(void *fd) { - report_file.fd = (fd_t)reinterpret_cast(fd); - report_file.fd_pid = internal_getpid(); -} -} // extern "C" - -#endif // !SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_file.cpp b/lib/sanitizer_common/sanitizer_file.cpp new file mode 100644 index 000000000000..79930d794250 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_file.cpp @@ -0,0 +1,215 @@ +//===-- sanitizer_file.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. It defines filesystem-related interfaces. This +// is separate from sanitizer_common.cpp so that it's simpler to disable +// all the filesystem support code for a port that doesn't use it. +// +//===---------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if !SANITIZER_FUCHSIA + +#include "sanitizer_common.h" +#include "sanitizer_file.h" + +namespace __sanitizer { + +void CatastrophicErrorWrite(const char *buffer, uptr length) { + WriteToFile(kStderrFd, buffer, length); +} + +StaticSpinMutex report_file_mu; +ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; + +void RawWrite(const char *buffer) { + report_file.Write(buffer, internal_strlen(buffer)); +} + +void ReportFile::ReopenIfNecessary() { + mu->CheckLocked(); + if (fd == kStdoutFd || fd == kStderrFd) return; + + uptr pid = internal_getpid(); + // If in tracer, use the parent's file. + if (pid == stoptheworld_tracer_pid) + pid = stoptheworld_tracer_ppid; + if (fd != kInvalidFd) { + // If the report file is already opened by the current process, + // do nothing. Otherwise the report file was opened by the parent + // process, close it now. + if (fd_pid == pid) + return; + else + CloseFile(fd); + } + + const char *exe_name = GetProcessName(); + if (common_flags()->log_exe_name && exe_name) { + internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, + exe_name, pid); + } else { + internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); + } + fd = OpenFile(full_path, WrOnly); + if (fd == kInvalidFd) { + const char *ErrorMsgPrefix = "ERROR: Can't open file: "; + WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); + WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); + Die(); + } + fd_pid = pid; +} + +void ReportFile::SetReportPath(const char *path) { + if (!path) + return; + uptr len = internal_strlen(path); + if (len > sizeof(path_prefix) - 100) { + Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", + path[0], path[1], path[2], path[3], + path[4], path[5], path[6], path[7]); + Die(); + } + + SpinMutexLock l(mu); + if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) + CloseFile(fd); + fd = kInvalidFd; + if (internal_strcmp(path, "stdout") == 0) { + fd = kStdoutFd; + } else if (internal_strcmp(path, "stderr") == 0) { + fd = kStderrFd; + } else { + internal_snprintf(path_prefix, kMaxPathLength, "%s", path); + } +} + +bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, + uptr *read_len, uptr max_len, error_t *errno_p) { + *buff = nullptr; + *buff_size = 0; + *read_len = 0; + if (!max_len) + return true; + uptr PageSize = GetPageSizeCached(); + uptr kMinFileLen = Min(PageSize, max_len); + + // The files we usually open are not seekable, so try different buffer sizes. + for (uptr size = kMinFileLen;; size = Min(size * 2, max_len)) { + UnmapOrDie(*buff, *buff_size); + *buff = (char*)MmapOrDie(size, __func__); + *buff_size = size; + fd_t fd = OpenFile(file_name, RdOnly, errno_p); + if (fd == kInvalidFd) { + UnmapOrDie(*buff, *buff_size); + return false; + } + *read_len = 0; + // Read up to one page at a time. + bool reached_eof = false; + while (*read_len < size) { + uptr just_read; + if (!ReadFromFile(fd, *buff + *read_len, size - *read_len, &just_read, + errno_p)) { + UnmapOrDie(*buff, *buff_size); + CloseFile(fd); + return false; + } + *read_len += just_read; + if (just_read == 0 || *read_len == max_len) { + reached_eof = true; + break; + } + } + CloseFile(fd); + if (reached_eof) // We've read the whole file. + break; + } + return true; +} + +bool ReadFileToVector(const char *file_name, + InternalMmapVectorNoCtor *buff, uptr max_len, + error_t *errno_p) { + buff->clear(); + if (!max_len) + return true; + uptr PageSize = GetPageSizeCached(); + fd_t fd = OpenFile(file_name, RdOnly, errno_p); + if (fd == kInvalidFd) + return false; + uptr read_len = 0; + while (read_len < max_len) { + if (read_len >= buff->size()) + buff->resize(Min(Max(PageSize, read_len * 2), max_len)); + CHECK_LT(read_len, buff->size()); + CHECK_LE(buff->size(), max_len); + uptr just_read; + if (!ReadFromFile(fd, buff->data() + read_len, buff->size() - read_len, + &just_read, errno_p)) { + CloseFile(fd); + return false; + } + read_len += just_read; + if (!just_read) + break; + } + CloseFile(fd); + buff->resize(read_len); + return true; +} + +static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; + +char *FindPathToBinary(const char *name) { + if (FileExists(name)) { + return internal_strdup(name); + } + + const char *path = GetEnv("PATH"); + if (!path) + return nullptr; + uptr name_len = internal_strlen(name); + InternalMmapVector buffer(kMaxPathLength); + const char *beg = path; + while (true) { + const char *end = internal_strchrnul(beg, kPathSeparator); + uptr prefix_len = end - beg; + if (prefix_len + name_len + 2 <= kMaxPathLength) { + internal_memcpy(buffer.data(), beg, prefix_len); + buffer[prefix_len] = '/'; + internal_memcpy(&buffer[prefix_len + 1], name, name_len); + buffer[prefix_len + 1 + name_len] = '\0'; + if (FileExists(buffer.data())) + return internal_strdup(buffer.data()); + } + if (*end == '\0') break; + beg = end + 1; + } + return nullptr; +} + +} // namespace __sanitizer + +using namespace __sanitizer; + +extern "C" { +void __sanitizer_set_report_path(const char *path) { + report_file.SetReportPath(path); +} + +void __sanitizer_set_report_fd(void *fd) { + report_file.fd = (fd_t)reinterpret_cast(fd); + report_file.fd_pid = internal_getpid(); +} +} // extern "C" + +#endif // !SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_flag_parser.cc b/lib/sanitizer_common/sanitizer_flag_parser.cc deleted file mode 100644 index e380d3b55e36..000000000000 --- a/lib/sanitizer_common/sanitizer_flag_parser.cc +++ /dev/null @@ -1,183 +0,0 @@ -//===-- sanitizer_flag_parser.cc ------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of ThreadSanitizer/AddressSanitizer runtime. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_flag_parser.h" - -#include "sanitizer_common.h" -#include "sanitizer_libc.h" -#include "sanitizer_flags.h" -#include "sanitizer_flag_parser.h" - -namespace __sanitizer { - -LowLevelAllocator FlagParser::Alloc; - -class UnknownFlags { - static const int kMaxUnknownFlags = 20; - const char *unknown_flags_[kMaxUnknownFlags]; - int n_unknown_flags_; - - public: - void Add(const char *name) { - CHECK_LT(n_unknown_flags_, kMaxUnknownFlags); - unknown_flags_[n_unknown_flags_++] = name; - } - - void Report() { - if (!n_unknown_flags_) return; - Printf("WARNING: found %d unrecognized flag(s):\n", n_unknown_flags_); - for (int i = 0; i < n_unknown_flags_; ++i) - Printf(" %s\n", unknown_flags_[i]); - n_unknown_flags_ = 0; - } -}; - -UnknownFlags unknown_flags; - -void ReportUnrecognizedFlags() { - unknown_flags.Report(); -} - -char *FlagParser::ll_strndup(const char *s, uptr n) { - uptr len = internal_strnlen(s, n); - char *s2 = (char*)Alloc.Allocate(len + 1); - internal_memcpy(s2, s, len); - s2[len] = 0; - return s2; -} - -void FlagParser::PrintFlagDescriptions() { - Printf("Available flags for %s:\n", SanitizerToolName); - for (int i = 0; i < n_flags_; ++i) - Printf("\t%s\n\t\t- %s\n", flags_[i].name, flags_[i].desc); -} - -void FlagParser::fatal_error(const char *err) { - Printf("%s: ERROR: %s\n", SanitizerToolName, err); - Die(); -} - -bool FlagParser::is_space(char c) { - return c == ' ' || c == ',' || c == ':' || c == '\n' || c == '\t' || - c == '\r'; -} - -void FlagParser::skip_whitespace() { - while (is_space(buf_[pos_])) ++pos_; -} - -void FlagParser::parse_flag(const char *env_option_name) { - uptr name_start = pos_; - while (buf_[pos_] != 0 && buf_[pos_] != '=' && !is_space(buf_[pos_])) ++pos_; - if (buf_[pos_] != '=') { - if (env_option_name) { - Printf("%s: ERROR: expected '=' in %s\n", SanitizerToolName, - env_option_name); - Die(); - } else - fatal_error("expected '='"); - } - char *name = ll_strndup(buf_ + name_start, pos_ - name_start); - - uptr value_start = ++pos_; - char *value; - if (buf_[pos_] == '\'' || buf_[pos_] == '"') { - char quote = buf_[pos_++]; - while (buf_[pos_] != 0 && buf_[pos_] != quote) ++pos_; - if (buf_[pos_] == 0) fatal_error("unterminated string"); - value = ll_strndup(buf_ + value_start + 1, pos_ - value_start - 1); - ++pos_; // consume the closing quote - } else { - while (buf_[pos_] != 0 && !is_space(buf_[pos_])) ++pos_; - if (buf_[pos_] != 0 && !is_space(buf_[pos_])) - fatal_error("expected separator or eol"); - value = ll_strndup(buf_ + value_start, pos_ - value_start); - } - - bool res = run_handler(name, value); - if (!res) fatal_error("Flag parsing failed."); -} - -void FlagParser::parse_flags(const char *env_option_name) { - while (true) { - skip_whitespace(); - if (buf_[pos_] == 0) break; - parse_flag(env_option_name); - } - - // Do a sanity check for certain flags. - if (common_flags_dont_use.malloc_context_size < 1) - common_flags_dont_use.malloc_context_size = 1; -} - -void FlagParser::ParseStringFromEnv(const char *env_name) { - const char *env = GetEnv(env_name); - VPrintf(1, "%s: %s\n", env_name, env ? env : ""); - ParseString(env, env_name); -} - -void FlagParser::ParseString(const char *s, const char *env_option_name) { - if (!s) return; - // Backup current parser state to allow nested ParseString() calls. - const char *old_buf_ = buf_; - uptr old_pos_ = pos_; - buf_ = s; - pos_ = 0; - - parse_flags(env_option_name); - - buf_ = old_buf_; - pos_ = old_pos_; -} - -bool FlagParser::ParseFile(const char *path, bool ignore_missing) { - static const uptr kMaxIncludeSize = 1 << 15; - char *data; - uptr data_mapped_size; - error_t err; - uptr len; - if (!ReadFileToBuffer(path, &data, &data_mapped_size, &len, - Max(kMaxIncludeSize, GetPageSizeCached()), &err)) { - if (ignore_missing) - return true; - Printf("Failed to read options from '%s': error %d\n", path, err); - return false; - } - ParseString(data, path); - UnmapOrDie(data, data_mapped_size); - return true; -} - -bool FlagParser::run_handler(const char *name, const char *value) { - for (int i = 0; i < n_flags_; ++i) { - if (internal_strcmp(name, flags_[i].name) == 0) - return flags_[i].handler->Parse(value); - } - // Unrecognized flag. This is not a fatal error, we may print a warning later. - unknown_flags.Add(name); - return true; -} - -void FlagParser::RegisterHandler(const char *name, FlagHandlerBase *handler, - const char *desc) { - CHECK_LT(n_flags_, kMaxFlags); - flags_[n_flags_].name = name; - flags_[n_flags_].desc = desc; - flags_[n_flags_].handler = handler; - ++n_flags_; -} - -FlagParser::FlagParser() : n_flags_(0), buf_(nullptr), pos_(0) { - flags_ = (Flag *)Alloc.Allocate(sizeof(Flag) * kMaxFlags); -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_flag_parser.cpp b/lib/sanitizer_common/sanitizer_flag_parser.cpp new file mode 100644 index 000000000000..1e2bc6652617 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_flag_parser.cpp @@ -0,0 +1,184 @@ +//===-- sanitizer_flag_parser.cpp -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer/AddressSanitizer runtime. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_flag_parser.h" + +#include "sanitizer_common.h" +#include "sanitizer_libc.h" +#include "sanitizer_flags.h" +#include "sanitizer_flag_parser.h" + +namespace __sanitizer { + +LowLevelAllocator FlagParser::Alloc; + +class UnknownFlags { + static const int kMaxUnknownFlags = 20; + const char *unknown_flags_[kMaxUnknownFlags]; + int n_unknown_flags_; + + public: + void Add(const char *name) { + CHECK_LT(n_unknown_flags_, kMaxUnknownFlags); + unknown_flags_[n_unknown_flags_++] = name; + } + + void Report() { + if (!n_unknown_flags_) return; + Printf("WARNING: found %d unrecognized flag(s):\n", n_unknown_flags_); + for (int i = 0; i < n_unknown_flags_; ++i) + Printf(" %s\n", unknown_flags_[i]); + n_unknown_flags_ = 0; + } +}; + +UnknownFlags unknown_flags; + +void ReportUnrecognizedFlags() { + unknown_flags.Report(); +} + +char *FlagParser::ll_strndup(const char *s, uptr n) { + uptr len = internal_strnlen(s, n); + char *s2 = (char*)Alloc.Allocate(len + 1); + internal_memcpy(s2, s, len); + s2[len] = 0; + return s2; +} + +void FlagParser::PrintFlagDescriptions() { + Printf("Available flags for %s:\n", SanitizerToolName); + for (int i = 0; i < n_flags_; ++i) + Printf("\t%s\n\t\t- %s\n", flags_[i].name, flags_[i].desc); +} + +void FlagParser::fatal_error(const char *err) { + Printf("%s: ERROR: %s\n", SanitizerToolName, err); + Die(); +} + +bool FlagParser::is_space(char c) { + return c == ' ' || c == ',' || c == ':' || c == '\n' || c == '\t' || + c == '\r'; +} + +void FlagParser::skip_whitespace() { + while (is_space(buf_[pos_])) ++pos_; +} + +void FlagParser::parse_flag(const char *env_option_name) { + uptr name_start = pos_; + while (buf_[pos_] != 0 && buf_[pos_] != '=' && !is_space(buf_[pos_])) ++pos_; + if (buf_[pos_] != '=') { + if (env_option_name) { + Printf("%s: ERROR: expected '=' in %s\n", SanitizerToolName, + env_option_name); + Die(); + } else { + fatal_error("expected '='"); + } + } + char *name = ll_strndup(buf_ + name_start, pos_ - name_start); + + uptr value_start = ++pos_; + char *value; + if (buf_[pos_] == '\'' || buf_[pos_] == '"') { + char quote = buf_[pos_++]; + while (buf_[pos_] != 0 && buf_[pos_] != quote) ++pos_; + if (buf_[pos_] == 0) fatal_error("unterminated string"); + value = ll_strndup(buf_ + value_start + 1, pos_ - value_start - 1); + ++pos_; // consume the closing quote + } else { + while (buf_[pos_] != 0 && !is_space(buf_[pos_])) ++pos_; + if (buf_[pos_] != 0 && !is_space(buf_[pos_])) + fatal_error("expected separator or eol"); + value = ll_strndup(buf_ + value_start, pos_ - value_start); + } + + bool res = run_handler(name, value); + if (!res) fatal_error("Flag parsing failed."); +} + +void FlagParser::parse_flags(const char *env_option_name) { + while (true) { + skip_whitespace(); + if (buf_[pos_] == 0) break; + parse_flag(env_option_name); + } + + // Do a sanity check for certain flags. + if (common_flags_dont_use.malloc_context_size < 1) + common_flags_dont_use.malloc_context_size = 1; +} + +void FlagParser::ParseStringFromEnv(const char *env_name) { + const char *env = GetEnv(env_name); + VPrintf(1, "%s: %s\n", env_name, env ? env : ""); + ParseString(env, env_name); +} + +void FlagParser::ParseString(const char *s, const char *env_option_name) { + if (!s) return; + // Backup current parser state to allow nested ParseString() calls. + const char *old_buf_ = buf_; + uptr old_pos_ = pos_; + buf_ = s; + pos_ = 0; + + parse_flags(env_option_name); + + buf_ = old_buf_; + pos_ = old_pos_; +} + +bool FlagParser::ParseFile(const char *path, bool ignore_missing) { + static const uptr kMaxIncludeSize = 1 << 15; + char *data; + uptr data_mapped_size; + error_t err; + uptr len; + if (!ReadFileToBuffer(path, &data, &data_mapped_size, &len, + Max(kMaxIncludeSize, GetPageSizeCached()), &err)) { + if (ignore_missing) + return true; + Printf("Failed to read options from '%s': error %d\n", path, err); + return false; + } + ParseString(data, path); + UnmapOrDie(data, data_mapped_size); + return true; +} + +bool FlagParser::run_handler(const char *name, const char *value) { + for (int i = 0; i < n_flags_; ++i) { + if (internal_strcmp(name, flags_[i].name) == 0) + return flags_[i].handler->Parse(value); + } + // Unrecognized flag. This is not a fatal error, we may print a warning later. + unknown_flags.Add(name); + return true; +} + +void FlagParser::RegisterHandler(const char *name, FlagHandlerBase *handler, + const char *desc) { + CHECK_LT(n_flags_, kMaxFlags); + flags_[n_flags_].name = name; + flags_[n_flags_].desc = desc; + flags_[n_flags_].handler = handler; + ++n_flags_; +} + +FlagParser::FlagParser() : n_flags_(0), buf_(nullptr), pos_(0) { + flags_ = (Flag *)Alloc.Allocate(sizeof(Flag) * kMaxFlags); +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_flag_parser.h b/lib/sanitizer_common/sanitizer_flag_parser.h index 8e12700bbe8c..c24ad25626ba 100644 --- a/lib/sanitizer_common/sanitizer_flag_parser.h +++ b/lib/sanitizer_common/sanitizer_flag_parser.h @@ -24,7 +24,7 @@ class FlagHandlerBase { virtual bool Parse(const char *value) { return false; } protected: - ~FlagHandlerBase() {}; + ~FlagHandlerBase() {} }; template @@ -144,7 +144,7 @@ class FlagParser { template static void RegisterFlag(FlagParser *parser, const char *name, const char *desc, T *var) { - FlagHandler *fh = new (FlagParser::Alloc) FlagHandler(var); // NOLINT + FlagHandler *fh = new (FlagParser::Alloc) FlagHandler(var); parser->RegisterHandler(name, fh, desc); } diff --git a/lib/sanitizer_common/sanitizer_flags.cc b/lib/sanitizer_common/sanitizer_flags.cc deleted file mode 100644 index c587b1884935..000000000000 --- a/lib/sanitizer_common/sanitizer_flags.cc +++ /dev/null @@ -1,121 +0,0 @@ -//===-- sanitizer_flags.cc ------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of ThreadSanitizer/AddressSanitizer runtime. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_flags.h" - -#include "sanitizer_common.h" -#include "sanitizer_libc.h" -#include "sanitizer_list.h" -#include "sanitizer_flag_parser.h" - -namespace __sanitizer { - -CommonFlags common_flags_dont_use; - -void CommonFlags::SetDefaults() { -#define COMMON_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; -#include "sanitizer_flags.inc" -#undef COMMON_FLAG -} - -void CommonFlags::CopyFrom(const CommonFlags &other) { - internal_memcpy(this, &other, sizeof(*this)); -} - -// Copy the string from "s" to "out", making the following substitutions: -// %b = binary basename -// %p = pid -void SubstituteForFlagValue(const char *s, char *out, uptr out_size) { - char *out_end = out + out_size; - while (*s && out < out_end - 1) { - if (s[0] != '%') { - *out++ = *s++; - continue; - } - switch (s[1]) { - case 'b': { - const char *base = GetProcessName(); - CHECK(base); - while (*base && out < out_end - 1) - *out++ = *base++; - s += 2; // skip "%b" - break; - } - case 'p': { - int pid = internal_getpid(); - char buf[32]; - char *buf_pos = buf + 32; - do { - *--buf_pos = (pid % 10) + '0'; - pid /= 10; - } while (pid); - while (buf_pos < buf + 32 && out < out_end - 1) - *out++ = *buf_pos++; - s += 2; // skip "%p" - break; - } - default: - *out++ = *s++; - break; - } - } - CHECK(out < out_end - 1); - *out = '\0'; -} - -class FlagHandlerInclude : public FlagHandlerBase { - FlagParser *parser_; - bool ignore_missing_; - - public: - explicit FlagHandlerInclude(FlagParser *parser, bool ignore_missing) - : parser_(parser), ignore_missing_(ignore_missing) {} - bool Parse(const char *value) final { - if (internal_strchr(value, '%')) { - char *buf = (char *)MmapOrDie(kMaxPathLength, "FlagHandlerInclude"); - SubstituteForFlagValue(value, buf, kMaxPathLength); - bool res = parser_->ParseFile(buf, ignore_missing_); - UnmapOrDie(buf, kMaxPathLength); - return res; - } - return parser_->ParseFile(value, ignore_missing_); - } -}; - -void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) { - FlagHandlerInclude *fh_include = new (FlagParser::Alloc) // NOLINT - FlagHandlerInclude(parser, /*ignore_missing*/ false); - parser->RegisterHandler("include", fh_include, - "read more options from the given file"); - FlagHandlerInclude *fh_include_if_exists = new (FlagParser::Alloc) // NOLINT - FlagHandlerInclude(parser, /*ignore_missing*/ true); - parser->RegisterHandler( - "include_if_exists", fh_include_if_exists, - "read more options from the given file (if it exists)"); -} - -void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) { -#define COMMON_FLAG(Type, Name, DefaultValue, Description) \ - RegisterFlag(parser, #Name, Description, &cf->Name); -#include "sanitizer_flags.inc" -#undef COMMON_FLAG - - RegisterIncludeFlags(parser, cf); -} - -void InitializeCommonFlags(CommonFlags *cf) { - // need to record coverage to generate coverage report. - cf->coverage |= cf->html_cov_report; - SetVerbosity(cf->verbosity); -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_flags.cpp b/lib/sanitizer_common/sanitizer_flags.cpp new file mode 100644 index 000000000000..66a0a5579ed3 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_flags.cpp @@ -0,0 +1,121 @@ +//===-- sanitizer_flags.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer/AddressSanitizer runtime. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_flags.h" + +#include "sanitizer_common.h" +#include "sanitizer_libc.h" +#include "sanitizer_list.h" +#include "sanitizer_flag_parser.h" + +namespace __sanitizer { + +CommonFlags common_flags_dont_use; + +void CommonFlags::SetDefaults() { +#define COMMON_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "sanitizer_flags.inc" +#undef COMMON_FLAG +} + +void CommonFlags::CopyFrom(const CommonFlags &other) { + internal_memcpy(this, &other, sizeof(*this)); +} + +// Copy the string from "s" to "out", making the following substitutions: +// %b = binary basename +// %p = pid +void SubstituteForFlagValue(const char *s, char *out, uptr out_size) { + char *out_end = out + out_size; + while (*s && out < out_end - 1) { + if (s[0] != '%') { + *out++ = *s++; + continue; + } + switch (s[1]) { + case 'b': { + const char *base = GetProcessName(); + CHECK(base); + while (*base && out < out_end - 1) + *out++ = *base++; + s += 2; // skip "%b" + break; + } + case 'p': { + int pid = internal_getpid(); + char buf[32]; + char *buf_pos = buf + 32; + do { + *--buf_pos = (pid % 10) + '0'; + pid /= 10; + } while (pid); + while (buf_pos < buf + 32 && out < out_end - 1) + *out++ = *buf_pos++; + s += 2; // skip "%p" + break; + } + default: + *out++ = *s++; + break; + } + } + CHECK(out < out_end - 1); + *out = '\0'; +} + +class FlagHandlerInclude : public FlagHandlerBase { + FlagParser *parser_; + bool ignore_missing_; + + public: + explicit FlagHandlerInclude(FlagParser *parser, bool ignore_missing) + : parser_(parser), ignore_missing_(ignore_missing) {} + bool Parse(const char *value) final { + if (internal_strchr(value, '%')) { + char *buf = (char *)MmapOrDie(kMaxPathLength, "FlagHandlerInclude"); + SubstituteForFlagValue(value, buf, kMaxPathLength); + bool res = parser_->ParseFile(buf, ignore_missing_); + UnmapOrDie(buf, kMaxPathLength); + return res; + } + return parser_->ParseFile(value, ignore_missing_); + } +}; + +void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) { + FlagHandlerInclude *fh_include = new (FlagParser::Alloc) + FlagHandlerInclude(parser, /*ignore_missing*/ false); + parser->RegisterHandler("include", fh_include, + "read more options from the given file"); + FlagHandlerInclude *fh_include_if_exists = new (FlagParser::Alloc) + FlagHandlerInclude(parser, /*ignore_missing*/ true); + parser->RegisterHandler( + "include_if_exists", fh_include_if_exists, + "read more options from the given file (if it exists)"); +} + +void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) { +#define COMMON_FLAG(Type, Name, DefaultValue, Description) \ + RegisterFlag(parser, #Name, Description, &cf->Name); +#include "sanitizer_flags.inc" +#undef COMMON_FLAG + + RegisterIncludeFlags(parser, cf); +} + +void InitializeCommonFlags(CommonFlags *cf) { + // need to record coverage to generate coverage report. + cf->coverage |= cf->html_cov_report; + SetVerbosity(cf->verbosity); +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc deleted file mode 100644 index 9c032fa8995c..000000000000 --- a/lib/sanitizer_common/sanitizer_fuchsia.cc +++ /dev/null @@ -1,527 +0,0 @@ -//===-- sanitizer_fuchsia.cc ----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and other sanitizer -// run-time libraries and implements Fuchsia-specific functions from -// sanitizer_common.h. -//===----------------------------------------------------------------------===// - -#include "sanitizer_fuchsia.h" -#if SANITIZER_FUCHSIA - -#include "sanitizer_common.h" -#include "sanitizer_libc.h" -#include "sanitizer_mutex.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace __sanitizer { - -void NORETURN internal__exit(int exitcode) { _zx_process_exit(exitcode); } - -uptr internal_sched_yield() { - zx_status_t status = _zx_nanosleep(0); - CHECK_EQ(status, ZX_OK); - return 0; // Why doesn't this return void? -} - -static void internal_nanosleep(zx_time_t ns) { - zx_status_t status = _zx_nanosleep(_zx_deadline_after(ns)); - CHECK_EQ(status, ZX_OK); -} - -unsigned int internal_sleep(unsigned int seconds) { - internal_nanosleep(ZX_SEC(seconds)); - return 0; -} - -u64 NanoTime() { - zx_time_t time; - zx_status_t status = _zx_clock_get(ZX_CLOCK_UTC, &time); - CHECK_EQ(status, ZX_OK); - return time; -} - -u64 MonotonicNanoTime() { return _zx_clock_get_monotonic(); } - -uptr internal_getpid() { - zx_info_handle_basic_t info; - zx_status_t status = - _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &info, - sizeof(info), NULL, NULL); - CHECK_EQ(status, ZX_OK); - uptr pid = static_cast(info.koid); - CHECK_EQ(pid, info.koid); - return pid; -} - -uptr GetThreadSelf() { return reinterpret_cast(thrd_current()); } - -tid_t GetTid() { return GetThreadSelf(); } - -void Abort() { abort(); } - -int Atexit(void (*function)(void)) { return atexit(function); } - -void SleepForSeconds(int seconds) { internal_sleep(seconds); } - -void SleepForMillis(int millis) { internal_nanosleep(ZX_MSEC(millis)); } - -void GetThreadStackTopAndBottom(bool, uptr *stack_top, uptr *stack_bottom) { - pthread_attr_t attr; - CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); - void *base; - size_t size; - CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0); - CHECK_EQ(pthread_attr_destroy(&attr), 0); - - *stack_bottom = reinterpret_cast(base); - *stack_top = *stack_bottom + size; -} - -void InitializePlatformEarly() {} -void MaybeReexec() {} -void CheckASLR() {} -void CheckMPROTECT() {} -void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} -void DisableCoreDumperIfNecessary() {} -void InstallDeadlySignalHandlers(SignalHandlerType handler) {} -void SetAlternateSignalStack() {} -void UnsetAlternateSignalStack() {} -void InitTlsSize() {} - -void PrintModuleMap() {} - -bool SignalContext::IsStackOverflow() const { return false; } -void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); } -const char *SignalContext::Describe() const { UNIMPLEMENTED(); } - -enum MutexState : int { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 }; - -BlockingMutex::BlockingMutex() { - // NOTE! It's important that this use internal_memset, because plain - // memset might be intercepted (e.g., actually be __asan_memset). - // Defining this so the compiler initializes each field, e.g.: - // BlockingMutex::BlockingMutex() : BlockingMutex(LINKER_INITIALIZED) {} - // might result in the compiler generating a call to memset, which would - // have the same problem. - internal_memset(this, 0, sizeof(*this)); -} - -void BlockingMutex::Lock() { - CHECK_EQ(owner_, 0); - atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); - if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked) - return; - while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) { - zx_status_t status = - _zx_futex_wait(reinterpret_cast(m), MtxSleeping, - ZX_HANDLE_INVALID, ZX_TIME_INFINITE); - if (status != ZX_ERR_BAD_STATE) // Normal race. - CHECK_EQ(status, ZX_OK); - } -} - -void BlockingMutex::Unlock() { - atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); - u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release); - CHECK_NE(v, MtxUnlocked); - if (v == MtxSleeping) { - zx_status_t status = _zx_futex_wake(reinterpret_cast(m), 1); - CHECK_EQ(status, ZX_OK); - } -} - -void BlockingMutex::CheckLocked() { - atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); - CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed)); -} - -uptr GetPageSize() { return PAGE_SIZE; } - -uptr GetMmapGranularity() { return PAGE_SIZE; } - -sanitizer_shadow_bounds_t ShadowBounds; - -uptr GetMaxUserVirtualAddress() { - ShadowBounds = __sanitizer_shadow_bounds(); - return ShadowBounds.memory_limit - 1; -} - -uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); } - -static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type, - bool raw_report, bool die_for_nomem) { - size = RoundUpTo(size, PAGE_SIZE); - - zx_handle_t vmo; - zx_status_t status = _zx_vmo_create(size, 0, &vmo); - if (status != ZX_OK) { - if (status != ZX_ERR_NO_MEMORY || die_for_nomem) - ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status, - raw_report); - return nullptr; - } - _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type, - internal_strlen(mem_type)); - - // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that? - uintptr_t addr; - status = - _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, - vmo, 0, size, &addr); - _zx_handle_close(vmo); - - if (status != ZX_OK) { - if (status != ZX_ERR_NO_MEMORY || die_for_nomem) - ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status, - raw_report); - return nullptr; - } - - IncreaseTotalMmap(size); - - return reinterpret_cast(addr); -} - -void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { - return DoAnonymousMmapOrDie(size, mem_type, raw_report, true); -} - -void *MmapNoReserveOrDie(uptr size, const char *mem_type) { - return MmapOrDie(size, mem_type); -} - -void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { - return DoAnonymousMmapOrDie(size, mem_type, false, false); -} - -uptr ReservedAddressRange::Init(uptr init_size, const char *name, - uptr fixed_addr) { - init_size = RoundUpTo(init_size, PAGE_SIZE); - DCHECK_EQ(os_handle_, ZX_HANDLE_INVALID); - uintptr_t base; - zx_handle_t vmar; - zx_status_t status = - _zx_vmar_allocate( - _zx_vmar_root_self(), - ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, - 0, init_size, &vmar, &base); - if (status != ZX_OK) - ReportMmapFailureAndDie(init_size, name, "zx_vmar_allocate", status); - base_ = reinterpret_cast(base); - size_ = init_size; - name_ = name; - os_handle_ = vmar; - - return reinterpret_cast(base_); -} - -static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size, - void *base, const char *name, bool die_for_nomem) { - uptr offset = fixed_addr - reinterpret_cast(base); - map_size = RoundUpTo(map_size, PAGE_SIZE); - zx_handle_t vmo; - zx_status_t status = _zx_vmo_create(map_size, 0, &vmo); - if (status != ZX_OK) { - if (status != ZX_ERR_NO_MEMORY || die_for_nomem) - ReportMmapFailureAndDie(map_size, name, "zx_vmo_create", status); - return 0; - } - _zx_object_set_property(vmo, ZX_PROP_NAME, name, internal_strlen(name)); - DCHECK_GE(base + size_, map_size + offset); - uintptr_t addr; - - status = - _zx_vmar_map(vmar, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC, - offset, vmo, 0, map_size, &addr); - _zx_handle_close(vmo); - if (status != ZX_OK) { - if (status != ZX_ERR_NO_MEMORY || die_for_nomem) { - ReportMmapFailureAndDie(map_size, name, "zx_vmar_map", status); - } - return 0; - } - IncreaseTotalMmap(map_size); - return addr; -} - -uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size, - const char *name) { - return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, - name_, false); -} - -uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr map_size, - const char *name) { - return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, - name_, true); -} - -void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar) { - if (!addr || !size) return; - size = RoundUpTo(size, PAGE_SIZE); - - zx_status_t status = - _zx_vmar_unmap(target_vmar, reinterpret_cast(addr), size); - if (status != ZX_OK) { - Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", - SanitizerToolName, size, size, addr); - CHECK("unable to unmap" && 0); - } - - DecreaseTotalMmap(size); -} - -void ReservedAddressRange::Unmap(uptr addr, uptr size) { - CHECK_LE(size, size_); - const zx_handle_t vmar = static_cast(os_handle_); - if (addr == reinterpret_cast(base_)) { - if (size == size_) { - // Destroying the vmar effectively unmaps the whole mapping. - _zx_vmar_destroy(vmar); - _zx_handle_close(vmar); - os_handle_ = static_cast(ZX_HANDLE_INVALID); - DecreaseTotalMmap(size); - return; - } - } else { - CHECK_EQ(addr + size, reinterpret_cast(base_) + size_); - } - // Partial unmapping does not affect the fact that the initial range is still - // reserved, and the resulting unmapped memory can't be reused. - UnmapOrDieVmar(reinterpret_cast(addr), size, vmar); -} - -// This should never be called. -void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { - UNIMPLEMENTED(); -} - -void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, - const char *mem_type) { - CHECK_GE(size, PAGE_SIZE); - CHECK(IsPowerOfTwo(size)); - CHECK(IsPowerOfTwo(alignment)); - - zx_handle_t vmo; - zx_status_t status = _zx_vmo_create(size, 0, &vmo); - if (status != ZX_OK) { - if (status != ZX_ERR_NO_MEMORY) - ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status, false); - return nullptr; - } - _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type, - internal_strlen(mem_type)); - - // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that? - - // Map a larger size to get a chunk of address space big enough that - // it surely contains an aligned region of the requested size. Then - // overwrite the aligned middle portion with a mapping from the - // beginning of the VMO, and unmap the excess before and after. - size_t map_size = size + alignment; - uintptr_t addr; - status = - _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, - vmo, 0, map_size, &addr); - if (status == ZX_OK) { - uintptr_t map_addr = addr; - uintptr_t map_end = map_addr + map_size; - addr = RoundUpTo(map_addr, alignment); - uintptr_t end = addr + size; - if (addr != map_addr) { - zx_info_vmar_t info; - status = _zx_object_get_info(_zx_vmar_root_self(), ZX_INFO_VMAR, &info, - sizeof(info), NULL, NULL); - if (status == ZX_OK) { - uintptr_t new_addr; - status = _zx_vmar_map( - _zx_vmar_root_self(), - ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC_OVERWRITE, - addr - info.base, vmo, 0, size, &new_addr); - if (status == ZX_OK) CHECK_EQ(new_addr, addr); - } - } - if (status == ZX_OK && addr != map_addr) - status = _zx_vmar_unmap(_zx_vmar_root_self(), map_addr, addr - map_addr); - if (status == ZX_OK && end != map_end) - status = _zx_vmar_unmap(_zx_vmar_root_self(), end, map_end - end); - } - _zx_handle_close(vmo); - - if (status != ZX_OK) { - if (status != ZX_ERR_NO_MEMORY) - ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status, false); - return nullptr; - } - - IncreaseTotalMmap(size); - - return reinterpret_cast(addr); -} - -void UnmapOrDie(void *addr, uptr size) { - UnmapOrDieVmar(addr, size, _zx_vmar_root_self()); -} - -// This is used on the shadow mapping, which cannot be changed. -// Zircon doesn't have anything like MADV_DONTNEED. -void ReleaseMemoryPagesToOS(uptr beg, uptr end) {} - -void DumpProcessMap() { - // TODO(mcgrathr): write it - return; -} - -bool IsAccessibleMemoryRange(uptr beg, uptr size) { - // TODO(mcgrathr): Figure out a better way. - zx_handle_t vmo; - zx_status_t status = _zx_vmo_create(size, 0, &vmo); - if (status == ZX_OK) { - status = _zx_vmo_write(vmo, reinterpret_cast(beg), 0, size); - _zx_handle_close(vmo); - } - return status == ZX_OK; -} - -// FIXME implement on this platform. -void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {} - -bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, - uptr *read_len, uptr max_len, error_t *errno_p) { - zx_handle_t vmo; - zx_status_t status = __sanitizer_get_configuration(file_name, &vmo); - if (status == ZX_OK) { - uint64_t vmo_size; - status = _zx_vmo_get_size(vmo, &vmo_size); - if (status == ZX_OK) { - if (vmo_size < max_len) max_len = vmo_size; - size_t map_size = RoundUpTo(max_len, PAGE_SIZE); - uintptr_t addr; - status = _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ, 0, vmo, 0, - map_size, &addr); - if (status == ZX_OK) { - *buff = reinterpret_cast(addr); - *buff_size = map_size; - *read_len = max_len; - } - } - _zx_handle_close(vmo); - } - if (status != ZX_OK && errno_p) *errno_p = status; - return status == ZX_OK; -} - -void RawWrite(const char *buffer) { - constexpr size_t size = 128; - static _Thread_local char line[size]; - static _Thread_local size_t lastLineEnd = 0; - static _Thread_local size_t cur = 0; - - while (*buffer) { - if (cur >= size) { - if (lastLineEnd == 0) - lastLineEnd = size; - __sanitizer_log_write(line, lastLineEnd); - internal_memmove(line, line + lastLineEnd, cur - lastLineEnd); - cur = cur - lastLineEnd; - lastLineEnd = 0; - } - if (*buffer == '\n') - lastLineEnd = cur + 1; - line[cur++] = *buffer++; - } - // Flush all complete lines before returning. - if (lastLineEnd != 0) { - __sanitizer_log_write(line, lastLineEnd); - internal_memmove(line, line + lastLineEnd, cur - lastLineEnd); - cur = cur - lastLineEnd; - lastLineEnd = 0; - } -} - -void CatastrophicErrorWrite(const char *buffer, uptr length) { - __sanitizer_log_write(buffer, length); -} - -char **StoredArgv; -char **StoredEnviron; - -char **GetArgv() { return StoredArgv; } -char **GetEnviron() { return StoredEnviron; } - -const char *GetEnv(const char *name) { - if (StoredEnviron) { - uptr NameLen = internal_strlen(name); - for (char **Env = StoredEnviron; *Env != 0; Env++) { - if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=') - return (*Env) + NameLen + 1; - } - } - return nullptr; -} - -uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) { - const char *argv0 = ""; - if (StoredArgv && StoredArgv[0]) { - argv0 = StoredArgv[0]; - } - internal_strncpy(buf, argv0, buf_len); - return internal_strlen(buf); -} - -uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { - return ReadBinaryName(buf, buf_len); -} - -uptr MainThreadStackBase, MainThreadStackSize; - -bool GetRandom(void *buffer, uptr length, bool blocking) { - CHECK_LE(length, ZX_CPRNG_DRAW_MAX_LEN); - _zx_cprng_draw(buffer, length); - return true; -} - -u32 GetNumberOfCPUs() { - return zx_system_get_num_cpus(); -} - -uptr GetRSS() { UNIMPLEMENTED(); } - -} // namespace __sanitizer - -using namespace __sanitizer; // NOLINT - -extern "C" { -void __sanitizer_startup_hook(int argc, char **argv, char **envp, - void *stack_base, size_t stack_size) { - __sanitizer::StoredArgv = argv; - __sanitizer::StoredEnviron = envp; - __sanitizer::MainThreadStackBase = reinterpret_cast(stack_base); - __sanitizer::MainThreadStackSize = stack_size; -} - -void __sanitizer_set_report_path(const char *path) { - // Handle the initialization code in each sanitizer, but no other calls. - // This setting is never consulted on Fuchsia. - DCHECK_EQ(path, common_flags()->log_path); -} - -void __sanitizer_set_report_fd(void *fd) { - UNREACHABLE("not available on Fuchsia"); -} -} // extern "C" - -#endif // SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cpp b/lib/sanitizer_common/sanitizer_fuchsia.cpp new file mode 100644 index 000000000000..6e2c6137f0ce --- /dev/null +++ b/lib/sanitizer_common/sanitizer_fuchsia.cpp @@ -0,0 +1,527 @@ +//===-- sanitizer_fuchsia.cpp ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and other sanitizer +// run-time libraries and implements Fuchsia-specific functions from +// sanitizer_common.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_fuchsia.h" +#if SANITIZER_FUCHSIA + +#include "sanitizer_common.h" +#include "sanitizer_libc.h" +#include "sanitizer_mutex.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace __sanitizer { + +void NORETURN internal__exit(int exitcode) { _zx_process_exit(exitcode); } + +uptr internal_sched_yield() { + zx_status_t status = _zx_nanosleep(0); + CHECK_EQ(status, ZX_OK); + return 0; // Why doesn't this return void? +} + +static void internal_nanosleep(zx_time_t ns) { + zx_status_t status = _zx_nanosleep(_zx_deadline_after(ns)); + CHECK_EQ(status, ZX_OK); +} + +unsigned int internal_sleep(unsigned int seconds) { + internal_nanosleep(ZX_SEC(seconds)); + return 0; +} + +u64 NanoTime() { + zx_time_t time; + zx_status_t status = _zx_clock_get(ZX_CLOCK_UTC, &time); + CHECK_EQ(status, ZX_OK); + return time; +} + +u64 MonotonicNanoTime() { return _zx_clock_get_monotonic(); } + +uptr internal_getpid() { + zx_info_handle_basic_t info; + zx_status_t status = + _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &info, + sizeof(info), NULL, NULL); + CHECK_EQ(status, ZX_OK); + uptr pid = static_cast(info.koid); + CHECK_EQ(pid, info.koid); + return pid; +} + +uptr GetThreadSelf() { return reinterpret_cast(thrd_current()); } + +tid_t GetTid() { return GetThreadSelf(); } + +void Abort() { abort(); } + +int Atexit(void (*function)(void)) { return atexit(function); } + +void SleepForSeconds(int seconds) { internal_sleep(seconds); } + +void SleepForMillis(int millis) { internal_nanosleep(ZX_MSEC(millis)); } + +void GetThreadStackTopAndBottom(bool, uptr *stack_top, uptr *stack_bottom) { + pthread_attr_t attr; + CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); + void *base; + size_t size; + CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0); + CHECK_EQ(pthread_attr_destroy(&attr), 0); + + *stack_bottom = reinterpret_cast(base); + *stack_top = *stack_bottom + size; +} + +void InitializePlatformEarly() {} +void MaybeReexec() {} +void CheckASLR() {} +void CheckMPROTECT() {} +void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} +void DisableCoreDumperIfNecessary() {} +void InstallDeadlySignalHandlers(SignalHandlerType handler) {} +void SetAlternateSignalStack() {} +void UnsetAlternateSignalStack() {} +void InitTlsSize() {} + +void PrintModuleMap() {} + +bool SignalContext::IsStackOverflow() const { return false; } +void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); } +const char *SignalContext::Describe() const { UNIMPLEMENTED(); } + +enum MutexState : int { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 }; + +BlockingMutex::BlockingMutex() { + // NOTE! It's important that this use internal_memset, because plain + // memset might be intercepted (e.g., actually be __asan_memset). + // Defining this so the compiler initializes each field, e.g.: + // BlockingMutex::BlockingMutex() : BlockingMutex(LINKER_INITIALIZED) {} + // might result in the compiler generating a call to memset, which would + // have the same problem. + internal_memset(this, 0, sizeof(*this)); +} + +void BlockingMutex::Lock() { + CHECK_EQ(owner_, 0); + atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); + if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked) + return; + while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) { + zx_status_t status = + _zx_futex_wait(reinterpret_cast(m), MtxSleeping, + ZX_HANDLE_INVALID, ZX_TIME_INFINITE); + if (status != ZX_ERR_BAD_STATE) // Normal race. + CHECK_EQ(status, ZX_OK); + } +} + +void BlockingMutex::Unlock() { + atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); + u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release); + CHECK_NE(v, MtxUnlocked); + if (v == MtxSleeping) { + zx_status_t status = _zx_futex_wake(reinterpret_cast(m), 1); + CHECK_EQ(status, ZX_OK); + } +} + +void BlockingMutex::CheckLocked() { + atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); + CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed)); +} + +uptr GetPageSize() { return PAGE_SIZE; } + +uptr GetMmapGranularity() { return PAGE_SIZE; } + +sanitizer_shadow_bounds_t ShadowBounds; + +uptr GetMaxUserVirtualAddress() { + ShadowBounds = __sanitizer_shadow_bounds(); + return ShadowBounds.memory_limit - 1; +} + +uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); } + +static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type, + bool raw_report, bool die_for_nomem) { + size = RoundUpTo(size, PAGE_SIZE); + + zx_handle_t vmo; + zx_status_t status = _zx_vmo_create(size, 0, &vmo); + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY || die_for_nomem) + ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status, + raw_report); + return nullptr; + } + _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type, + internal_strlen(mem_type)); + + // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that? + uintptr_t addr; + status = + _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, + vmo, 0, size, &addr); + _zx_handle_close(vmo); + + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY || die_for_nomem) + ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status, + raw_report); + return nullptr; + } + + IncreaseTotalMmap(size); + + return reinterpret_cast(addr); +} + +void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { + return DoAnonymousMmapOrDie(size, mem_type, raw_report, true); +} + +void *MmapNoReserveOrDie(uptr size, const char *mem_type) { + return MmapOrDie(size, mem_type); +} + +void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { + return DoAnonymousMmapOrDie(size, mem_type, false, false); +} + +uptr ReservedAddressRange::Init(uptr init_size, const char *name, + uptr fixed_addr) { + init_size = RoundUpTo(init_size, PAGE_SIZE); + DCHECK_EQ(os_handle_, ZX_HANDLE_INVALID); + uintptr_t base; + zx_handle_t vmar; + zx_status_t status = + _zx_vmar_allocate( + _zx_vmar_root_self(), + ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, + 0, init_size, &vmar, &base); + if (status != ZX_OK) + ReportMmapFailureAndDie(init_size, name, "zx_vmar_allocate", status); + base_ = reinterpret_cast(base); + size_ = init_size; + name_ = name; + os_handle_ = vmar; + + return reinterpret_cast(base_); +} + +static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size, + void *base, const char *name, bool die_for_nomem) { + uptr offset = fixed_addr - reinterpret_cast(base); + map_size = RoundUpTo(map_size, PAGE_SIZE); + zx_handle_t vmo; + zx_status_t status = _zx_vmo_create(map_size, 0, &vmo); + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY || die_for_nomem) + ReportMmapFailureAndDie(map_size, name, "zx_vmo_create", status); + return 0; + } + _zx_object_set_property(vmo, ZX_PROP_NAME, name, internal_strlen(name)); + DCHECK_GE(base + size_, map_size + offset); + uintptr_t addr; + + status = + _zx_vmar_map(vmar, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC, + offset, vmo, 0, map_size, &addr); + _zx_handle_close(vmo); + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY || die_for_nomem) { + ReportMmapFailureAndDie(map_size, name, "zx_vmar_map", status); + } + return 0; + } + IncreaseTotalMmap(map_size); + return addr; +} + +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size, + const char *name) { + return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, + name_, false); +} + +uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr map_size, + const char *name) { + return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, + name_, true); +} + +void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar) { + if (!addr || !size) return; + size = RoundUpTo(size, PAGE_SIZE); + + zx_status_t status = + _zx_vmar_unmap(target_vmar, reinterpret_cast(addr), size); + if (status != ZX_OK) { + Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", + SanitizerToolName, size, size, addr); + CHECK("unable to unmap" && 0); + } + + DecreaseTotalMmap(size); +} + +void ReservedAddressRange::Unmap(uptr addr, uptr size) { + CHECK_LE(size, size_); + const zx_handle_t vmar = static_cast(os_handle_); + if (addr == reinterpret_cast(base_)) { + if (size == size_) { + // Destroying the vmar effectively unmaps the whole mapping. + _zx_vmar_destroy(vmar); + _zx_handle_close(vmar); + os_handle_ = static_cast(ZX_HANDLE_INVALID); + DecreaseTotalMmap(size); + return; + } + } else { + CHECK_EQ(addr + size, reinterpret_cast(base_) + size_); + } + // Partial unmapping does not affect the fact that the initial range is still + // reserved, and the resulting unmapped memory can't be reused. + UnmapOrDieVmar(reinterpret_cast(addr), size, vmar); +} + +// This should never be called. +void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { + UNIMPLEMENTED(); +} + +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type) { + CHECK_GE(size, PAGE_SIZE); + CHECK(IsPowerOfTwo(size)); + CHECK(IsPowerOfTwo(alignment)); + + zx_handle_t vmo; + zx_status_t status = _zx_vmo_create(size, 0, &vmo); + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY) + ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status, false); + return nullptr; + } + _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type, + internal_strlen(mem_type)); + + // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that? + + // Map a larger size to get a chunk of address space big enough that + // it surely contains an aligned region of the requested size. Then + // overwrite the aligned middle portion with a mapping from the + // beginning of the VMO, and unmap the excess before and after. + size_t map_size = size + alignment; + uintptr_t addr; + status = + _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, + vmo, 0, map_size, &addr); + if (status == ZX_OK) { + uintptr_t map_addr = addr; + uintptr_t map_end = map_addr + map_size; + addr = RoundUpTo(map_addr, alignment); + uintptr_t end = addr + size; + if (addr != map_addr) { + zx_info_vmar_t info; + status = _zx_object_get_info(_zx_vmar_root_self(), ZX_INFO_VMAR, &info, + sizeof(info), NULL, NULL); + if (status == ZX_OK) { + uintptr_t new_addr; + status = _zx_vmar_map( + _zx_vmar_root_self(), + ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC_OVERWRITE, + addr - info.base, vmo, 0, size, &new_addr); + if (status == ZX_OK) CHECK_EQ(new_addr, addr); + } + } + if (status == ZX_OK && addr != map_addr) + status = _zx_vmar_unmap(_zx_vmar_root_self(), map_addr, addr - map_addr); + if (status == ZX_OK && end != map_end) + status = _zx_vmar_unmap(_zx_vmar_root_self(), end, map_end - end); + } + _zx_handle_close(vmo); + + if (status != ZX_OK) { + if (status != ZX_ERR_NO_MEMORY) + ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status, false); + return nullptr; + } + + IncreaseTotalMmap(size); + + return reinterpret_cast(addr); +} + +void UnmapOrDie(void *addr, uptr size) { + UnmapOrDieVmar(addr, size, _zx_vmar_root_self()); +} + +// This is used on the shadow mapping, which cannot be changed. +// Zircon doesn't have anything like MADV_DONTNEED. +void ReleaseMemoryPagesToOS(uptr beg, uptr end) {} + +void DumpProcessMap() { + // TODO(mcgrathr): write it + return; +} + +bool IsAccessibleMemoryRange(uptr beg, uptr size) { + // TODO(mcgrathr): Figure out a better way. + zx_handle_t vmo; + zx_status_t status = _zx_vmo_create(size, 0, &vmo); + if (status == ZX_OK) { + status = _zx_vmo_write(vmo, reinterpret_cast(beg), 0, size); + _zx_handle_close(vmo); + } + return status == ZX_OK; +} + +// FIXME implement on this platform. +void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {} + +bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, + uptr *read_len, uptr max_len, error_t *errno_p) { + zx_handle_t vmo; + zx_status_t status = __sanitizer_get_configuration(file_name, &vmo); + if (status == ZX_OK) { + uint64_t vmo_size; + status = _zx_vmo_get_size(vmo, &vmo_size); + if (status == ZX_OK) { + if (vmo_size < max_len) max_len = vmo_size; + size_t map_size = RoundUpTo(max_len, PAGE_SIZE); + uintptr_t addr; + status = _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ, 0, vmo, 0, + map_size, &addr); + if (status == ZX_OK) { + *buff = reinterpret_cast(addr); + *buff_size = map_size; + *read_len = max_len; + } + } + _zx_handle_close(vmo); + } + if (status != ZX_OK && errno_p) *errno_p = status; + return status == ZX_OK; +} + +void RawWrite(const char *buffer) { + constexpr size_t size = 128; + static _Thread_local char line[size]; + static _Thread_local size_t lastLineEnd = 0; + static _Thread_local size_t cur = 0; + + while (*buffer) { + if (cur >= size) { + if (lastLineEnd == 0) + lastLineEnd = size; + __sanitizer_log_write(line, lastLineEnd); + internal_memmove(line, line + lastLineEnd, cur - lastLineEnd); + cur = cur - lastLineEnd; + lastLineEnd = 0; + } + if (*buffer == '\n') + lastLineEnd = cur + 1; + line[cur++] = *buffer++; + } + // Flush all complete lines before returning. + if (lastLineEnd != 0) { + __sanitizer_log_write(line, lastLineEnd); + internal_memmove(line, line + lastLineEnd, cur - lastLineEnd); + cur = cur - lastLineEnd; + lastLineEnd = 0; + } +} + +void CatastrophicErrorWrite(const char *buffer, uptr length) { + __sanitizer_log_write(buffer, length); +} + +char **StoredArgv; +char **StoredEnviron; + +char **GetArgv() { return StoredArgv; } +char **GetEnviron() { return StoredEnviron; } + +const char *GetEnv(const char *name) { + if (StoredEnviron) { + uptr NameLen = internal_strlen(name); + for (char **Env = StoredEnviron; *Env != 0; Env++) { + if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=') + return (*Env) + NameLen + 1; + } + } + return nullptr; +} + +uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) { + const char *argv0 = ""; + if (StoredArgv && StoredArgv[0]) { + argv0 = StoredArgv[0]; + } + internal_strncpy(buf, argv0, buf_len); + return internal_strlen(buf); +} + +uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { + return ReadBinaryName(buf, buf_len); +} + +uptr MainThreadStackBase, MainThreadStackSize; + +bool GetRandom(void *buffer, uptr length, bool blocking) { + CHECK_LE(length, ZX_CPRNG_DRAW_MAX_LEN); + _zx_cprng_draw(buffer, length); + return true; +} + +u32 GetNumberOfCPUs() { + return zx_system_get_num_cpus(); +} + +uptr GetRSS() { UNIMPLEMENTED(); } + +} // namespace __sanitizer + +using namespace __sanitizer; + +extern "C" { +void __sanitizer_startup_hook(int argc, char **argv, char **envp, + void *stack_base, size_t stack_size) { + __sanitizer::StoredArgv = argv; + __sanitizer::StoredEnviron = envp; + __sanitizer::MainThreadStackBase = reinterpret_cast(stack_base); + __sanitizer::MainThreadStackSize = stack_size; +} + +void __sanitizer_set_report_path(const char *path) { + // Handle the initialization code in each sanitizer, but no other calls. + // This setting is never consulted on Fuchsia. + DCHECK_EQ(path, common_flags()->log_path); +} + +void __sanitizer_set_report_fd(void *fd) { + UNREACHABLE("not available on Fuchsia"); +} +} // extern "C" + +#endif // SANITIZER_FUCHSIA diff --git a/lib/sanitizer_common/sanitizer_getauxval.h b/lib/sanitizer_common/sanitizer_getauxval.h index cbd1af12c04f..86ad3a5e2c2a 100644 --- a/lib/sanitizer_common/sanitizer_getauxval.h +++ b/lib/sanitizer_common/sanitizer_getauxval.h @@ -9,6 +9,7 @@ // Common getauxval() guards and definitions. // getauxval() is not defined until glibc version 2.16, or until API level 21 // for Android. +// Implement the getauxval() compat function for NetBSD. // //===----------------------------------------------------------------------===// @@ -16,15 +17,10 @@ #define SANITIZER_GETAUXVAL_H #include "sanitizer_platform.h" +#include "sanitizer_glibc_version.h" #if SANITIZER_LINUX || SANITIZER_FUCHSIA -# include - -# ifndef __GLIBC_PREREQ -# define __GLIBC_PREREQ(x, y) 0 -# endif - # if __GLIBC_PREREQ(2, 16) || (SANITIZER_ANDROID && __ANDROID_API__ >= 21) || \ SANITIZER_FUCHSIA # define SANITIZER_USE_GETAUXVAL 1 @@ -38,10 +34,26 @@ // The weak getauxval definition allows to check for the function at runtime. // This is useful for Android, when compiled at a lower API level yet running // on a more recent platform that offers the function. -extern "C" SANITIZER_WEAK_ATTRIBUTE -unsigned long getauxval(unsigned long type); // NOLINT +extern "C" SANITIZER_WEAK_ATTRIBUTE unsigned long getauxval(unsigned long type); # endif -#endif // SANITIZER_LINUX || SANITIZER_FUCHSIA +#elif SANITIZER_NETBSD + +#define SANITIZER_USE_GETAUXVAL 1 + +#include +#include + +static inline decltype(AuxInfo::a_v) getauxval(decltype(AuxInfo::a_type) type) { + for (const AuxInfo *aux = (const AuxInfo *)_dlauxinfo(); + aux->a_type != AT_NULL; ++aux) { + if (type == aux->a_type) + return aux->a_v; + } + + return 0; +} + +#endif #endif // SANITIZER_GETAUXVAL_H diff --git a/lib/sanitizer_common/sanitizer_glibc_version.h b/lib/sanitizer_common/sanitizer_glibc_version.h new file mode 100644 index 000000000000..47175f20aa01 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_glibc_version.h @@ -0,0 +1,26 @@ +//===-- sanitizer_glibc_version.h -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_GLIBC_VERSION_H +#define SANITIZER_GLIBC_VERSION_H + +#include "sanitizer_platform.h" + +#if SANITIZER_LINUX || SANITIZER_FUCHSIA +#include +#endif + +#ifndef __GLIBC_PREREQ +#define __GLIBC_PREREQ(x, y) 0 +#endif + +#endif diff --git a/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc b/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc index f29226b3ee3a..03ef7c1788cd 100644 --- a/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc +++ b/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc @@ -24,7 +24,7 @@ struct ioctl_desc { const char *name; }; -const unsigned ioctl_table_max = 1200; +const unsigned ioctl_table_max = 1236; static ioctl_desc ioctl_table[ioctl_table_max]; static unsigned ioctl_table_size = 0; @@ -645,7 +645,7 @@ static void ioctl_table_fill() { _(SPKRTUNE, NONE, 0); _(SPKRGETVOL, WRITE, sizeof(unsigned int)); _(SPKRSETVOL, READ, sizeof(unsigned int)); -#if 0 /* WIP */ +#if defined(__x86_64__) /* Entries from file: dev/nvmm/nvmm_ioctl.h */ _(NVMM_IOC_CAPABILITY, WRITE, struct_nvmm_ioc_capability_sz); _(NVMM_IOC_MACHINE_CREATE, READWRITE, struct_nvmm_ioc_machine_create_sz); @@ -661,7 +661,11 @@ static void ioctl_table_fill() { _(NVMM_IOC_GPA_UNMAP, READ, struct_nvmm_ioc_gpa_unmap_sz); _(NVMM_IOC_HVA_MAP, READ, struct_nvmm_ioc_hva_map_sz); _(NVMM_IOC_HVA_UNMAP, READ, struct_nvmm_ioc_hva_unmap_sz); + _(NVMM_IOC_CTL, READ, struct_nvmm_ioc_ctl_sz); #endif + /* Entries from file: dev/spi/spi_io.h */ + _(SPI_IOCTL_CONFIGURE, READ, struct_spi_ioctl_configure_sz); + _(SPI_IOCTL_TRANSFER, READ, struct_spi_ioctl_transfer_sz); /* Entries from file: fs/autofs/autofs_ioctl.h */ _(AUTOFSREQUEST, WRITE, struct_autofs_daemon_request_sz); _(AUTOFSDONE, READ, struct_autofs_daemon_done_sz); @@ -895,6 +899,9 @@ static void ioctl_table_fill() { _(AUDIO_GETBUFINFO, WRITE, struct_audio_info_sz); _(AUDIO_SETCHAN, READ, sizeof(int)); _(AUDIO_GETCHAN, WRITE, sizeof(int)); + _(AUDIO_QUERYFORMAT, READWRITE, struct_audio_format_query_sz); + _(AUDIO_GETFORMAT, WRITE, struct_audio_info_sz); + _(AUDIO_SETFORMAT, READ, struct_audio_info_sz); _(AUDIO_MIXER_READ, READWRITE, struct_mixer_ctrl_sz); _(AUDIO_MIXER_WRITE, READWRITE, struct_mixer_ctrl_sz); _(AUDIO_MIXER_DEVINFO, READWRITE, struct_mixer_devinfo_sz); @@ -985,6 +992,7 @@ static void ioctl_table_fill() { _(DIOCMWEDGES, WRITE, sizeof(int)); _(DIOCGSECTORSIZE, WRITE, sizeof(unsigned int)); _(DIOCGMEDIASIZE, WRITE, sizeof(uptr)); + _(DIOCRMWEDGES, WRITE, sizeof(int)); /* Entries from file: sys/drvctlio.h */ _(DRVDETACHDEV, READ, struct_devdetachargs_sz); _(DRVRESCANBUS, READ, struct_devrescanargs_sz); @@ -1206,6 +1214,8 @@ static void ioctl_table_fill() { _(SIOCGETHERCAP, READWRITE, struct_eccapreq_sz); _(SIOCGIFINDEX, READWRITE, struct_ifreq_sz); _(SIOCSETHERCAP, READ, struct_eccapreq_sz); + _(SIOCSIFDESCR, READ, struct_ifreq_sz); + _(SIOCGIFDESCR, READWRITE, struct_ifreq_sz); _(SIOCGUMBINFO, READWRITE, struct_ifreq_sz); _(SIOCSUMBPARAM, READ, struct_ifreq_sz); _(SIOCGUMBPARAM, READWRITE, struct_ifreq_sz); @@ -1335,6 +1345,21 @@ static void ioctl_table_fill() { _(WDOGIOC_TICKLE, NONE, 0); _(WDOGIOC_GTICKLER, WRITE, sizeof(int)); _(WDOGIOC_GWDOGS, READWRITE, struct_wdog_conf_sz); + /* Entries from file: sys/kcov.h */ + _(KCOV_IOC_SETBUFSIZE, READ, sizeof(u64)); + _(KCOV_IOC_ENABLE, READ, sizeof(int)); + _(KCOV_IOC_DISABLE, NONE, 0); + /* Entries from file: sys/ipmi.h */ + _(IPMICTL_RECEIVE_MSG_TRUNC, READWRITE, struct_ipmi_recv_sz); + _(IPMICTL_RECEIVE_MSG, READWRITE, struct_ipmi_recv_sz); + _(IPMICTL_SEND_COMMAND, READ, struct_ipmi_req_sz); + _(IPMICTL_REGISTER_FOR_CMD, READ, struct_ipmi_cmdspec_sz); + _(IPMICTL_UNREGISTER_FOR_CMD, READ, struct_ipmi_cmdspec_sz); + _(IPMICTL_SET_GETS_EVENTS_CMD, READ, sizeof(int)); + _(IPMICTL_SET_MY_ADDRESS_CMD, READ, sizeof(unsigned int)); + _(IPMICTL_GET_MY_ADDRESS_CMD, WRITE, sizeof(unsigned int)); + _(IPMICTL_SET_MY_LUN_CMD, READ, sizeof(unsigned int)); + _(IPMICTL_GET_MY_LUN_CMD, WRITE, sizeof(unsigned int)); /* Entries from file: soundcard.h */ _(SNDCTL_DSP_RESET, NONE, 0); _(SNDCTL_DSP_SYNC, NONE, 0); @@ -1379,7 +1404,7 @@ static void ioctl_table_fill() { _(SNDCTL_DSP_SKIP, NONE, 0); _(SNDCTL_DSP_SILENCE, NONE, 0); #undef _ -} +} // NOLINT static bool ioctl_initialized = false; diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index e0c6506bed51..00226305e07c 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -133,27 +133,27 @@ namespace __sanitizer { #if defined(_WIN64) // 64-bit Windows uses LLP64 data model. -typedef unsigned long long uptr; // NOLINT -typedef signed long long sptr; // NOLINT +typedef unsigned long long uptr; +typedef signed long long sptr; #else -typedef unsigned long uptr; // NOLINT -typedef signed long sptr; // NOLINT +typedef unsigned long uptr; +typedef signed long sptr; #endif // defined(_WIN64) #if defined(__x86_64__) // Since x32 uses ILP32 data model in 64-bit hardware mode, we must use // 64-bit pointer to unwind stack frame. -typedef unsigned long long uhwptr; // NOLINT +typedef unsigned long long uhwptr; #else -typedef uptr uhwptr; // NOLINT +typedef uptr uhwptr; #endif typedef unsigned char u8; -typedef unsigned short u16; // NOLINT +typedef unsigned short u16; typedef unsigned int u32; -typedef unsigned long long u64; // NOLINT -typedef signed char s8; -typedef signed short s16; // NOLINT -typedef signed int s32; -typedef signed long long s64; // NOLINT +typedef unsigned long long u64; +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; #if SANITIZER_WINDOWS // On Windows, files are HANDLE, which is a synonim of void*. // Use void* to avoid including everywhere. @@ -264,7 +264,7 @@ typedef ALIGNED(1) s64 us64; #if SANITIZER_WINDOWS } // namespace __sanitizer -typedef unsigned long DWORD; // NOLINT +typedef unsigned long DWORD; namespace __sanitizer { typedef DWORD thread_return_t; # define THREAD_CALLING_CONV __stdcall @@ -419,18 +419,41 @@ inline void Trap() { } // namespace __sanitizer -namespace __asan { using namespace __sanitizer; } // NOLINT -namespace __dsan { using namespace __sanitizer; } // NOLINT -namespace __dfsan { using namespace __sanitizer; } // NOLINT -namespace __lsan { using namespace __sanitizer; } // NOLINT -namespace __msan { using namespace __sanitizer; } // NOLINT -namespace __hwasan { using namespace __sanitizer; } // NOLINT -namespace __tsan { using namespace __sanitizer; } // NOLINT -namespace __scudo { using namespace __sanitizer; } // NOLINT -namespace __ubsan { using namespace __sanitizer; } // NOLINT -namespace __xray { using namespace __sanitizer; } // NOLINT -namespace __interception { using namespace __sanitizer; } // NOLINT -namespace __hwasan { using namespace __sanitizer; } // NOLINT - +namespace __asan { +using namespace __sanitizer; +} +namespace __dsan { +using namespace __sanitizer; +} +namespace __dfsan { +using namespace __sanitizer; +} +namespace __lsan { +using namespace __sanitizer; +} +namespace __msan { +using namespace __sanitizer; +} +namespace __hwasan { +using namespace __sanitizer; +} +namespace __tsan { +using namespace __sanitizer; +} +namespace __scudo { +using namespace __sanitizer; +} +namespace __ubsan { +using namespace __sanitizer; +} +namespace __xray { +using namespace __sanitizer; +} +namespace __interception { +using namespace __sanitizer; +} +namespace __hwasan { +using namespace __sanitizer; +} #endif // SANITIZER_DEFS_H diff --git a/lib/sanitizer_common/sanitizer_libc.cc b/lib/sanitizer_common/sanitizer_libc.cc deleted file mode 100644 index 95c74441fd21..000000000000 --- a/lib/sanitizer_common/sanitizer_libc.cc +++ /dev/null @@ -1,279 +0,0 @@ -//===-- sanitizer_libc.cc -------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. See sanitizer_libc.h for details. -//===----------------------------------------------------------------------===// - -#include "sanitizer_allocator_internal.h" -#include "sanitizer_common.h" -#include "sanitizer_libc.h" - -namespace __sanitizer { - -s64 internal_atoll(const char *nptr) { - return internal_simple_strtoll(nptr, nullptr, 10); -} - -void *internal_memchr(const void *s, int c, uptr n) { - const char *t = (const char *)s; - for (uptr i = 0; i < n; ++i, ++t) - if (*t == c) - return reinterpret_cast(const_cast(t)); - return nullptr; -} - -void *internal_memrchr(const void *s, int c, uptr n) { - const char *t = (const char *)s; - void *res = nullptr; - for (uptr i = 0; i < n; ++i, ++t) { - if (*t == c) res = reinterpret_cast(const_cast(t)); - } - return res; -} - -int internal_memcmp(const void* s1, const void* s2, uptr n) { - const char *t1 = (const char *)s1; - const char *t2 = (const char *)s2; - for (uptr i = 0; i < n; ++i, ++t1, ++t2) - if (*t1 != *t2) - return *t1 < *t2 ? -1 : 1; - return 0; -} - -void *internal_memcpy(void *dest, const void *src, uptr n) { - char *d = (char*)dest; - const char *s = (const char *)src; - for (uptr i = 0; i < n; ++i) - d[i] = s[i]; - return dest; -} - -void *internal_memmove(void *dest, const void *src, uptr n) { - char *d = (char*)dest; - const char *s = (const char *)src; - sptr i, signed_n = (sptr)n; - CHECK_GE(signed_n, 0); - if (d < s) { - for (i = 0; i < signed_n; ++i) - d[i] = s[i]; - } else { - if (d > s && signed_n > 0) - for (i = signed_n - 1; i >= 0 ; --i) { - d[i] = s[i]; - } - } - return dest; -} - -void *internal_memset(void* s, int c, uptr n) { - // Optimize for the most performance-critical case: - if ((reinterpret_cast(s) % 16) == 0 && (n % 16) == 0) { - u64 *p = reinterpret_cast(s); - u64 *e = p + n / 8; - u64 v = c; - v |= v << 8; - v |= v << 16; - v |= v << 32; - for (; p < e; p += 2) - p[0] = p[1] = v; - return s; - } - // The next line prevents Clang from making a call to memset() instead of the - // loop below. - // FIXME: building the runtime with -ffreestanding is a better idea. However - // there currently are linktime problems due to PR12396. - char volatile *t = (char*)s; - for (uptr i = 0; i < n; ++i, ++t) { - *t = c; - } - return s; -} - -uptr internal_strcspn(const char *s, const char *reject) { - uptr i; - for (i = 0; s[i]; i++) { - if (internal_strchr(reject, s[i])) - return i; - } - return i; -} - -char* internal_strdup(const char *s) { - uptr len = internal_strlen(s); - char *s2 = (char*)InternalAlloc(len + 1); - internal_memcpy(s2, s, len); - s2[len] = 0; - return s2; -} - -int internal_strcmp(const char *s1, const char *s2) { - while (true) { - unsigned c1 = *s1; - unsigned c2 = *s2; - if (c1 != c2) return (c1 < c2) ? -1 : 1; - if (c1 == 0) break; - s1++; - s2++; - } - return 0; -} - -int internal_strncmp(const char *s1, const char *s2, uptr n) { - for (uptr i = 0; i < n; i++) { - unsigned c1 = *s1; - unsigned c2 = *s2; - if (c1 != c2) return (c1 < c2) ? -1 : 1; - if (c1 == 0) break; - s1++; - s2++; - } - return 0; -} - -char* internal_strchr(const char *s, int c) { - while (true) { - if (*s == (char)c) - return const_cast(s); - if (*s == 0) - return nullptr; - s++; - } -} - -char *internal_strchrnul(const char *s, int c) { - char *res = internal_strchr(s, c); - if (!res) - res = const_cast(s) + internal_strlen(s); - return res; -} - -char *internal_strrchr(const char *s, int c) { - const char *res = nullptr; - for (uptr i = 0; s[i]; i++) { - if (s[i] == c) res = s + i; - } - return const_cast(res); -} - -uptr internal_strlen(const char *s) { - uptr i = 0; - while (s[i]) i++; - return i; -} - -uptr internal_strlcat(char *dst, const char *src, uptr maxlen) { - const uptr srclen = internal_strlen(src); - const uptr dstlen = internal_strnlen(dst, maxlen); - if (dstlen == maxlen) return maxlen + srclen; - if (srclen < maxlen - dstlen) { - internal_memmove(dst + dstlen, src, srclen + 1); - } else { - internal_memmove(dst + dstlen, src, maxlen - dstlen - 1); - dst[maxlen - 1] = '\0'; - } - return dstlen + srclen; -} - -char *internal_strncat(char *dst, const char *src, uptr n) { - uptr len = internal_strlen(dst); - uptr i; - for (i = 0; i < n && src[i]; i++) - dst[len + i] = src[i]; - dst[len + i] = 0; - return dst; -} - -uptr internal_strlcpy(char *dst, const char *src, uptr maxlen) { - const uptr srclen = internal_strlen(src); - if (srclen < maxlen) { - internal_memmove(dst, src, srclen + 1); - } else if (maxlen != 0) { - internal_memmove(dst, src, maxlen - 1); - dst[maxlen - 1] = '\0'; - } - return srclen; -} - -char *internal_strncpy(char *dst, const char *src, uptr n) { - uptr i; - for (i = 0; i < n && src[i]; i++) - dst[i] = src[i]; - internal_memset(dst + i, '\0', n - i); - return dst; -} - -uptr internal_strnlen(const char *s, uptr maxlen) { - uptr i = 0; - while (i < maxlen && s[i]) i++; - return i; -} - -char *internal_strstr(const char *haystack, const char *needle) { - // This is O(N^2), but we are not using it in hot places. - uptr len1 = internal_strlen(haystack); - uptr len2 = internal_strlen(needle); - if (len1 < len2) return nullptr; - for (uptr pos = 0; pos <= len1 - len2; pos++) { - if (internal_memcmp(haystack + pos, needle, len2) == 0) - return const_cast(haystack) + pos; - } - return nullptr; -} - -s64 internal_simple_strtoll(const char *nptr, const char **endptr, int base) { - CHECK_EQ(base, 10); - while (IsSpace(*nptr)) nptr++; - int sgn = 1; - u64 res = 0; - bool have_digits = false; - char *old_nptr = const_cast(nptr); - if (*nptr == '+') { - sgn = 1; - nptr++; - } else if (*nptr == '-') { - sgn = -1; - nptr++; - } - while (IsDigit(*nptr)) { - res = (res <= UINT64_MAX / 10) ? res * 10 : UINT64_MAX; - int digit = ((*nptr) - '0'); - res = (res <= UINT64_MAX - digit) ? res + digit : UINT64_MAX; - have_digits = true; - nptr++; - } - if (endptr) { - *endptr = (have_digits) ? const_cast(nptr) : old_nptr; - } - if (sgn > 0) { - return (s64)(Min((u64)INT64_MAX, res)); - } else { - return (res > INT64_MAX) ? INT64_MIN : ((s64)res * -1); - } -} - -bool mem_is_zero(const char *beg, uptr size) { - CHECK_LE(size, 1ULL << FIRST_32_SECOND_64(30, 40)); // Sanity check. - const char *end = beg + size; - uptr *aligned_beg = (uptr *)RoundUpTo((uptr)beg, sizeof(uptr)); - uptr *aligned_end = (uptr *)RoundDownTo((uptr)end, sizeof(uptr)); - uptr all = 0; - // Prologue. - for (const char *mem = beg; mem < (char*)aligned_beg && mem < end; mem++) - all |= *mem; - // Aligned loop. - for (; aligned_beg < aligned_end; aligned_beg++) - all |= *aligned_beg; - // Epilogue. - if ((char*)aligned_end >= beg) - for (const char *mem = (char*)aligned_end; mem < end; mem++) - all |= *mem; - return all == 0; -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_libc.cpp b/lib/sanitizer_common/sanitizer_libc.cpp new file mode 100644 index 000000000000..4bc04b486870 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_libc.cpp @@ -0,0 +1,280 @@ +//===-- sanitizer_libc.cpp ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. See sanitizer_libc.h for details. +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_common.h" +#include "sanitizer_libc.h" + +namespace __sanitizer { + +s64 internal_atoll(const char *nptr) { + return internal_simple_strtoll(nptr, nullptr, 10); +} + +void *internal_memchr(const void *s, int c, uptr n) { + const char *t = (const char *)s; + for (uptr i = 0; i < n; ++i, ++t) + if (*t == c) + return reinterpret_cast(const_cast(t)); + return nullptr; +} + +void *internal_memrchr(const void *s, int c, uptr n) { + const char *t = (const char *)s; + void *res = nullptr; + for (uptr i = 0; i < n; ++i, ++t) { + if (*t == c) res = reinterpret_cast(const_cast(t)); + } + return res; +} + +int internal_memcmp(const void* s1, const void* s2, uptr n) { + const char *t1 = (const char *)s1; + const char *t2 = (const char *)s2; + for (uptr i = 0; i < n; ++i, ++t1, ++t2) + if (*t1 != *t2) + return *t1 < *t2 ? -1 : 1; + return 0; +} + +void *internal_memcpy(void *dest, const void *src, uptr n) { + char *d = (char*)dest; + const char *s = (const char *)src; + for (uptr i = 0; i < n; ++i) + d[i] = s[i]; + return dest; +} + +void *internal_memmove(void *dest, const void *src, uptr n) { + char *d = (char*)dest; + const char *s = (const char *)src; + sptr i, signed_n = (sptr)n; + CHECK_GE(signed_n, 0); + if (d < s) { + for (i = 0; i < signed_n; ++i) + d[i] = s[i]; + } else { + if (d > s && signed_n > 0) { + for (i = signed_n - 1; i >= 0; --i) { + d[i] = s[i]; + } + } + } + return dest; +} + +void *internal_memset(void* s, int c, uptr n) { + // Optimize for the most performance-critical case: + if ((reinterpret_cast(s) % 16) == 0 && (n % 16) == 0) { + u64 *p = reinterpret_cast(s); + u64 *e = p + n / 8; + u64 v = c; + v |= v << 8; + v |= v << 16; + v |= v << 32; + for (; p < e; p += 2) + p[0] = p[1] = v; + return s; + } + // The next line prevents Clang from making a call to memset() instead of the + // loop below. + // FIXME: building the runtime with -ffreestanding is a better idea. However + // there currently are linktime problems due to PR12396. + char volatile *t = (char*)s; + for (uptr i = 0; i < n; ++i, ++t) { + *t = c; + } + return s; +} + +uptr internal_strcspn(const char *s, const char *reject) { + uptr i; + for (i = 0; s[i]; i++) { + if (internal_strchr(reject, s[i])) + return i; + } + return i; +} + +char* internal_strdup(const char *s) { + uptr len = internal_strlen(s); + char *s2 = (char*)InternalAlloc(len + 1); + internal_memcpy(s2, s, len); + s2[len] = 0; + return s2; +} + +int internal_strcmp(const char *s1, const char *s2) { + while (true) { + unsigned c1 = *s1; + unsigned c2 = *s2; + if (c1 != c2) return (c1 < c2) ? -1 : 1; + if (c1 == 0) break; + s1++; + s2++; + } + return 0; +} + +int internal_strncmp(const char *s1, const char *s2, uptr n) { + for (uptr i = 0; i < n; i++) { + unsigned c1 = *s1; + unsigned c2 = *s2; + if (c1 != c2) return (c1 < c2) ? -1 : 1; + if (c1 == 0) break; + s1++; + s2++; + } + return 0; +} + +char* internal_strchr(const char *s, int c) { + while (true) { + if (*s == (char)c) + return const_cast(s); + if (*s == 0) + return nullptr; + s++; + } +} + +char *internal_strchrnul(const char *s, int c) { + char *res = internal_strchr(s, c); + if (!res) + res = const_cast(s) + internal_strlen(s); + return res; +} + +char *internal_strrchr(const char *s, int c) { + const char *res = nullptr; + for (uptr i = 0; s[i]; i++) { + if (s[i] == c) res = s + i; + } + return const_cast(res); +} + +uptr internal_strlen(const char *s) { + uptr i = 0; + while (s[i]) i++; + return i; +} + +uptr internal_strlcat(char *dst, const char *src, uptr maxlen) { + const uptr srclen = internal_strlen(src); + const uptr dstlen = internal_strnlen(dst, maxlen); + if (dstlen == maxlen) return maxlen + srclen; + if (srclen < maxlen - dstlen) { + internal_memmove(dst + dstlen, src, srclen + 1); + } else { + internal_memmove(dst + dstlen, src, maxlen - dstlen - 1); + dst[maxlen - 1] = '\0'; + } + return dstlen + srclen; +} + +char *internal_strncat(char *dst, const char *src, uptr n) { + uptr len = internal_strlen(dst); + uptr i; + for (i = 0; i < n && src[i]; i++) + dst[len + i] = src[i]; + dst[len + i] = 0; + return dst; +} + +uptr internal_strlcpy(char *dst, const char *src, uptr maxlen) { + const uptr srclen = internal_strlen(src); + if (srclen < maxlen) { + internal_memmove(dst, src, srclen + 1); + } else if (maxlen != 0) { + internal_memmove(dst, src, maxlen - 1); + dst[maxlen - 1] = '\0'; + } + return srclen; +} + +char *internal_strncpy(char *dst, const char *src, uptr n) { + uptr i; + for (i = 0; i < n && src[i]; i++) + dst[i] = src[i]; + internal_memset(dst + i, '\0', n - i); + return dst; +} + +uptr internal_strnlen(const char *s, uptr maxlen) { + uptr i = 0; + while (i < maxlen && s[i]) i++; + return i; +} + +char *internal_strstr(const char *haystack, const char *needle) { + // This is O(N^2), but we are not using it in hot places. + uptr len1 = internal_strlen(haystack); + uptr len2 = internal_strlen(needle); + if (len1 < len2) return nullptr; + for (uptr pos = 0; pos <= len1 - len2; pos++) { + if (internal_memcmp(haystack + pos, needle, len2) == 0) + return const_cast(haystack) + pos; + } + return nullptr; +} + +s64 internal_simple_strtoll(const char *nptr, const char **endptr, int base) { + CHECK_EQ(base, 10); + while (IsSpace(*nptr)) nptr++; + int sgn = 1; + u64 res = 0; + bool have_digits = false; + char *old_nptr = const_cast(nptr); + if (*nptr == '+') { + sgn = 1; + nptr++; + } else if (*nptr == '-') { + sgn = -1; + nptr++; + } + while (IsDigit(*nptr)) { + res = (res <= UINT64_MAX / 10) ? res * 10 : UINT64_MAX; + int digit = ((*nptr) - '0'); + res = (res <= UINT64_MAX - digit) ? res + digit : UINT64_MAX; + have_digits = true; + nptr++; + } + if (endptr) { + *endptr = (have_digits) ? const_cast(nptr) : old_nptr; + } + if (sgn > 0) { + return (s64)(Min((u64)INT64_MAX, res)); + } else { + return (res > INT64_MAX) ? INT64_MIN : ((s64)res * -1); + } +} + +bool mem_is_zero(const char *beg, uptr size) { + CHECK_LE(size, 1ULL << FIRST_32_SECOND_64(30, 40)); // Sanity check. + const char *end = beg + size; + uptr *aligned_beg = (uptr *)RoundUpTo((uptr)beg, sizeof(uptr)); + uptr *aligned_end = (uptr *)RoundDownTo((uptr)end, sizeof(uptr)); + uptr all = 0; + // Prologue. + for (const char *mem = beg; mem < (char*)aligned_beg && mem < end; mem++) + all |= *mem; + // Aligned loop. + for (; aligned_beg < aligned_end; aligned_beg++) + all |= *aligned_beg; + // Epilogue. + if ((char *)aligned_end >= beg) { + for (const char *mem = (char *)aligned_end; mem < end; mem++) all |= *mem; + } + return all == 0; +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_libignore.cc b/lib/sanitizer_common/sanitizer_libignore.cc deleted file mode 100644 index 6c7c132e99eb..000000000000 --- a/lib/sanitizer_common/sanitizer_libignore.cc +++ /dev/null @@ -1,129 +0,0 @@ -//===-- sanitizer_libignore.cc --------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \ - SANITIZER_NETBSD || SANITIZER_OPENBSD - -#include "sanitizer_libignore.h" -#include "sanitizer_flags.h" -#include "sanitizer_posix.h" -#include "sanitizer_procmaps.h" - -namespace __sanitizer { - -LibIgnore::LibIgnore(LinkerInitialized) { -} - -void LibIgnore::AddIgnoredLibrary(const char *name_templ) { - BlockingMutexLock lock(&mutex_); - if (count_ >= kMaxLibs) { - Report("%s: too many ignored libraries (max: %d)\n", SanitizerToolName, - kMaxLibs); - Die(); - } - Lib *lib = &libs_[count_++]; - lib->templ = internal_strdup(name_templ); - lib->name = nullptr; - lib->real_name = nullptr; - lib->loaded = false; -} - -void LibIgnore::OnLibraryLoaded(const char *name) { - BlockingMutexLock lock(&mutex_); - // Try to match suppressions with symlink target. - InternalScopedString buf(kMaxPathLength); - if (name && internal_readlink(name, buf.data(), buf.size() - 1) > 0 && - buf[0]) { - for (uptr i = 0; i < count_; i++) { - Lib *lib = &libs_[i]; - if (!lib->loaded && (!lib->real_name) && - TemplateMatch(lib->templ, name)) - lib->real_name = internal_strdup(buf.data()); - } - } - - // Scan suppressions list and find newly loaded and unloaded libraries. - ListOfModules modules; - modules.init(); - for (uptr i = 0; i < count_; i++) { - Lib *lib = &libs_[i]; - bool loaded = false; - for (const auto &mod : modules) { - for (const auto &range : mod.ranges()) { - if (!range.executable) - continue; - if (!TemplateMatch(lib->templ, mod.full_name()) && - !(lib->real_name && - internal_strcmp(lib->real_name, mod.full_name()) == 0)) - continue; - if (loaded) { - Report("%s: called_from_lib suppression '%s' is matched against" - " 2 libraries: '%s' and '%s'\n", - SanitizerToolName, lib->templ, lib->name, mod.full_name()); - Die(); - } - loaded = true; - if (lib->loaded) - continue; - VReport(1, - "Matched called_from_lib suppression '%s' against library" - " '%s'\n", - lib->templ, mod.full_name()); - lib->loaded = true; - lib->name = internal_strdup(mod.full_name()); - const uptr idx = - atomic_load(&ignored_ranges_count_, memory_order_relaxed); - CHECK_LT(idx, ARRAY_SIZE(ignored_code_ranges_)); - ignored_code_ranges_[idx].begin = range.beg; - ignored_code_ranges_[idx].end = range.end; - atomic_store(&ignored_ranges_count_, idx + 1, memory_order_release); - break; - } - } - if (lib->loaded && !loaded) { - Report("%s: library '%s' that was matched against called_from_lib" - " suppression '%s' is unloaded\n", - SanitizerToolName, lib->name, lib->templ); - Die(); - } - } - - // Track instrumented ranges. - if (track_instrumented_libs_) { - for (const auto &mod : modules) { - if (!mod.instrumented()) - continue; - for (const auto &range : mod.ranges()) { - if (!range.executable) - continue; - if (IsPcInstrumented(range.beg) && IsPcInstrumented(range.end - 1)) - continue; - VReport(1, "Adding instrumented range %p-%p from library '%s'\n", - range.beg, range.end, mod.full_name()); - const uptr idx = - atomic_load(&instrumented_ranges_count_, memory_order_relaxed); - CHECK_LT(idx, ARRAY_SIZE(instrumented_code_ranges_)); - instrumented_code_ranges_[idx].begin = range.beg; - instrumented_code_ranges_[idx].end = range.end; - atomic_store(&instrumented_ranges_count_, idx + 1, - memory_order_release); - } - } - } -} - -void LibIgnore::OnLibraryUnloaded() { - OnLibraryLoaded(nullptr); -} - -} // namespace __sanitizer - -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || - // SANITIZER_NETBSD diff --git a/lib/sanitizer_common/sanitizer_libignore.cpp b/lib/sanitizer_common/sanitizer_libignore.cpp new file mode 100644 index 000000000000..eb9bb765013d --- /dev/null +++ b/lib/sanitizer_common/sanitizer_libignore.cpp @@ -0,0 +1,129 @@ +//===-- sanitizer_libignore.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \ + SANITIZER_NETBSD || SANITIZER_OPENBSD + +#include "sanitizer_libignore.h" +#include "sanitizer_flags.h" +#include "sanitizer_posix.h" +#include "sanitizer_procmaps.h" + +namespace __sanitizer { + +LibIgnore::LibIgnore(LinkerInitialized) { +} + +void LibIgnore::AddIgnoredLibrary(const char *name_templ) { + BlockingMutexLock lock(&mutex_); + if (count_ >= kMaxLibs) { + Report("%s: too many ignored libraries (max: %d)\n", SanitizerToolName, + kMaxLibs); + Die(); + } + Lib *lib = &libs_[count_++]; + lib->templ = internal_strdup(name_templ); + lib->name = nullptr; + lib->real_name = nullptr; + lib->loaded = false; +} + +void LibIgnore::OnLibraryLoaded(const char *name) { + BlockingMutexLock lock(&mutex_); + // Try to match suppressions with symlink target. + InternalScopedString buf(kMaxPathLength); + if (name && internal_readlink(name, buf.data(), buf.size() - 1) > 0 && + buf[0]) { + for (uptr i = 0; i < count_; i++) { + Lib *lib = &libs_[i]; + if (!lib->loaded && (!lib->real_name) && + TemplateMatch(lib->templ, name)) + lib->real_name = internal_strdup(buf.data()); + } + } + + // Scan suppressions list and find newly loaded and unloaded libraries. + ListOfModules modules; + modules.init(); + for (uptr i = 0; i < count_; i++) { + Lib *lib = &libs_[i]; + bool loaded = false; + for (const auto &mod : modules) { + for (const auto &range : mod.ranges()) { + if (!range.executable) + continue; + if (!TemplateMatch(lib->templ, mod.full_name()) && + !(lib->real_name && + internal_strcmp(lib->real_name, mod.full_name()) == 0)) + continue; + if (loaded) { + Report("%s: called_from_lib suppression '%s' is matched against" + " 2 libraries: '%s' and '%s'\n", + SanitizerToolName, lib->templ, lib->name, mod.full_name()); + Die(); + } + loaded = true; + if (lib->loaded) + continue; + VReport(1, + "Matched called_from_lib suppression '%s' against library" + " '%s'\n", + lib->templ, mod.full_name()); + lib->loaded = true; + lib->name = internal_strdup(mod.full_name()); + const uptr idx = + atomic_load(&ignored_ranges_count_, memory_order_relaxed); + CHECK_LT(idx, ARRAY_SIZE(ignored_code_ranges_)); + ignored_code_ranges_[idx].begin = range.beg; + ignored_code_ranges_[idx].end = range.end; + atomic_store(&ignored_ranges_count_, idx + 1, memory_order_release); + break; + } + } + if (lib->loaded && !loaded) { + Report("%s: library '%s' that was matched against called_from_lib" + " suppression '%s' is unloaded\n", + SanitizerToolName, lib->name, lib->templ); + Die(); + } + } + + // Track instrumented ranges. + if (track_instrumented_libs_) { + for (const auto &mod : modules) { + if (!mod.instrumented()) + continue; + for (const auto &range : mod.ranges()) { + if (!range.executable) + continue; + if (IsPcInstrumented(range.beg) && IsPcInstrumented(range.end - 1)) + continue; + VReport(1, "Adding instrumented range %p-%p from library '%s'\n", + range.beg, range.end, mod.full_name()); + const uptr idx = + atomic_load(&instrumented_ranges_count_, memory_order_relaxed); + CHECK_LT(idx, ARRAY_SIZE(instrumented_code_ranges_)); + instrumented_code_ranges_[idx].begin = range.beg; + instrumented_code_ranges_[idx].end = range.end; + atomic_store(&instrumented_ranges_count_, idx + 1, + memory_order_release); + } + } + } +} + +void LibIgnore::OnLibraryUnloaded() { + OnLibraryLoaded(nullptr); +} + +} // namespace __sanitizer + +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || + // SANITIZER_NETBSD diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc deleted file mode 100644 index 88ab0979bb05..000000000000 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ /dev/null @@ -1,2102 +0,0 @@ -//===-- sanitizer_linux.cc ------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries and implements linux-specific functions from -// sanitizer_libc.h. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS - -#include "sanitizer_common.h" -#include "sanitizer_flags.h" -#include "sanitizer_getauxval.h" -#include "sanitizer_internal_defs.h" -#include "sanitizer_libc.h" -#include "sanitizer_linux.h" -#include "sanitizer_mutex.h" -#include "sanitizer_placement_new.h" -#include "sanitizer_procmaps.h" - -#if SANITIZER_LINUX -#include -#endif - -// For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat' -// format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To -// access stat from asm/stat.h, without conflicting with definition in -// sys/stat.h, we use this trick. -#if defined(__mips64) -#include -#include -#define stat kernel_stat -#include -#undef stat -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if !SANITIZER_SOLARIS -#include -#endif -#include -#include -#include -#include -#include -#if !SANITIZER_OPENBSD -#include -#endif -#if SANITIZER_OPENBSD -#include -#include -#endif -#include - -#if SANITIZER_LINUX -#include -#endif - -#if SANITIZER_LINUX && !SANITIZER_ANDROID -#include -#endif - -#if SANITIZER_FREEBSD -#include -#include -#include -extern "C" { -// must be included after and on -// FreeBSD 9.2 and 10.0. -#include -} -#include -#endif // SANITIZER_FREEBSD - -#if SANITIZER_NETBSD -#include // For NAME_MAX -#include -#include -extern struct ps_strings *__ps_strings; -#endif // SANITIZER_NETBSD - -#if SANITIZER_SOLARIS -#include -#include -#define environ _environ -#endif - -extern char **environ; - -#if SANITIZER_LINUX -// -struct kernel_timeval { - long tv_sec; - long tv_usec; -}; - -// is broken on some linux distributions. -const int FUTEX_WAIT = 0; -const int FUTEX_WAKE = 1; -const int FUTEX_PRIVATE_FLAG = 128; -const int FUTEX_WAIT_PRIVATE = FUTEX_WAIT | FUTEX_PRIVATE_FLAG; -const int FUTEX_WAKE_PRIVATE = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; -#endif // SANITIZER_LINUX - -// Are we using 32-bit or 64-bit Linux syscalls? -// x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32 -// but it still needs to use 64-bit syscalls. -#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \ - SANITIZER_WORDSIZE == 64) -# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1 -#else -# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0 -#endif - -// Note : FreeBSD had implemented both -// Linux and OpenBSD apis, available from -// future 12.x version most likely -#if SANITIZER_LINUX && defined(__NR_getrandom) -# if !defined(GRND_NONBLOCK) -# define GRND_NONBLOCK 1 -# endif -# define SANITIZER_USE_GETRANDOM 1 -#else -# define SANITIZER_USE_GETRANDOM 0 -#endif // SANITIZER_LINUX && defined(__NR_getrandom) - -#if SANITIZER_OPENBSD -# define SANITIZER_USE_GETENTROPY 1 -#else -# if SANITIZER_FREEBSD && __FreeBSD_version >= 1200000 -# define SANITIZER_USE_GETENTROPY 1 -# else -# define SANITIZER_USE_GETENTROPY 0 -# endif -#endif // SANITIZER_USE_GETENTROPY - -namespace __sanitizer { - -#if SANITIZER_LINUX && defined(__x86_64__) -#include "sanitizer_syscall_linux_x86_64.inc" -#elif SANITIZER_LINUX && defined(__aarch64__) -#include "sanitizer_syscall_linux_aarch64.inc" -#elif SANITIZER_LINUX && defined(__arm__) -#include "sanitizer_syscall_linux_arm.inc" -#else -#include "sanitizer_syscall_generic.inc" -#endif - -// --------------- sanitizer_libc.h -#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD -#if !SANITIZER_S390 && !SANITIZER_OPENBSD -uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, - OFF_T offset) { -#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS - return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd, - offset); -#else - // mmap2 specifies file offset in 4096-byte units. - CHECK(IsAligned(offset, 4096)); - return internal_syscall(SYSCALL(mmap2), addr, length, prot, flags, fd, - offset / 4096); -#endif -} -#endif // !SANITIZER_S390 && !SANITIZER_OPENBSD - -#if !SANITIZER_OPENBSD -uptr internal_munmap(void *addr, uptr length) { - return internal_syscall(SYSCALL(munmap), (uptr)addr, length); -} - -int internal_mprotect(void *addr, uptr length, int prot) { - return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot); -} -#endif - -uptr internal_close(fd_t fd) { - return internal_syscall(SYSCALL(close), fd); -} - -uptr internal_open(const char *filename, int flags) { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS - return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags); -#else - return internal_syscall(SYSCALL(open), (uptr)filename, flags); -#endif -} - -uptr internal_open(const char *filename, int flags, u32 mode) { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS - return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags, - mode); -#else - return internal_syscall(SYSCALL(open), (uptr)filename, flags, mode); -#endif -} - -uptr internal_read(fd_t fd, void *buf, uptr count) { - sptr res; - HANDLE_EINTR(res, - (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, count)); - return res; -} - -uptr internal_write(fd_t fd, const void *buf, uptr count) { - sptr res; - HANDLE_EINTR(res, - (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf, count)); - return res; -} - -uptr internal_ftruncate(fd_t fd, uptr size) { - sptr res; - HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, - (OFF_T)size)); - return res; -} - -#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX -static void stat64_to_stat(struct stat64 *in, struct stat *out) { - internal_memset(out, 0, sizeof(*out)); - out->st_dev = in->st_dev; - out->st_ino = in->st_ino; - out->st_mode = in->st_mode; - out->st_nlink = in->st_nlink; - out->st_uid = in->st_uid; - out->st_gid = in->st_gid; - out->st_rdev = in->st_rdev; - out->st_size = in->st_size; - out->st_blksize = in->st_blksize; - out->st_blocks = in->st_blocks; - out->st_atime = in->st_atime; - out->st_mtime = in->st_mtime; - out->st_ctime = in->st_ctime; -} -#endif - -#if defined(__mips64) -// Undefine compatibility macros from -// so that they would not clash with the kernel_stat -// st_[a|m|c]time fields -#undef st_atime -#undef st_mtime -#undef st_ctime -#if defined(SANITIZER_ANDROID) -// Bionic sys/stat.h defines additional macros -// for compatibility with the old NDKs and -// they clash with the kernel_stat structure -// st_[a|m|c]time_nsec fields. -#undef st_atime_nsec -#undef st_mtime_nsec -#undef st_ctime_nsec -#endif -static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { - internal_memset(out, 0, sizeof(*out)); - out->st_dev = in->st_dev; - out->st_ino = in->st_ino; - out->st_mode = in->st_mode; - out->st_nlink = in->st_nlink; - out->st_uid = in->st_uid; - out->st_gid = in->st_gid; - out->st_rdev = in->st_rdev; - out->st_size = in->st_size; - out->st_blksize = in->st_blksize; - out->st_blocks = in->st_blocks; -#if defined(__USE_MISC) || \ - defined(__USE_XOPEN2K8) || \ - defined(SANITIZER_ANDROID) - out->st_atim.tv_sec = in->st_atime; - out->st_atim.tv_nsec = in->st_atime_nsec; - out->st_mtim.tv_sec = in->st_mtime; - out->st_mtim.tv_nsec = in->st_mtime_nsec; - out->st_ctim.tv_sec = in->st_ctime; - out->st_ctim.tv_nsec = in->st_ctime_nsec; -#else - out->st_atime = in->st_atime; - out->st_atimensec = in->st_atime_nsec; - out->st_mtime = in->st_mtime; - out->st_mtimensec = in->st_mtime_nsec; - out->st_ctime = in->st_ctime; - out->st_atimensec = in->st_ctime_nsec; -#endif -} -#endif - -uptr internal_stat(const char *path, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_OPENBSD - return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0); -#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS - return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, - 0); -#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS -# if defined(__mips64) - // For mips64, stat syscall fills buffer in the format of kernel_stat - struct kernel_stat kbuf; - int res = internal_syscall(SYSCALL(stat), path, &kbuf); - kernel_stat_to_stat(&kbuf, (struct stat *)buf); - return res; -# else - return internal_syscall(SYSCALL(stat), (uptr)path, (uptr)buf); -# endif -#else - struct stat64 buf64; - int res = internal_syscall(SYSCALL(stat64), path, &buf64); - stat64_to_stat(&buf64, (struct stat *)buf); - return res; -#endif -} - -uptr internal_lstat(const char *path, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_OPENBSD - return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, - AT_SYMLINK_NOFOLLOW); -#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS - return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, - AT_SYMLINK_NOFOLLOW); -#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS -# if SANITIZER_MIPS64 - // For mips64, lstat syscall fills buffer in the format of kernel_stat - struct kernel_stat kbuf; - int res = internal_syscall(SYSCALL(lstat), path, &kbuf); - kernel_stat_to_stat(&kbuf, (struct stat *)buf); - return res; -# else - return internal_syscall(SYSCALL(lstat), (uptr)path, (uptr)buf); -# endif -#else - struct stat64 buf64; - int res = internal_syscall(SYSCALL(lstat64), path, &buf64); - stat64_to_stat(&buf64, (struct stat *)buf); - return res; -#endif -} - -uptr internal_fstat(fd_t fd, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_OPENBSD || \ - SANITIZER_LINUX_USES_64BIT_SYSCALLS -#if SANITIZER_MIPS64 && !SANITIZER_OPENBSD - // For mips64, fstat syscall fills buffer in the format of kernel_stat - struct kernel_stat kbuf; - int res = internal_syscall(SYSCALL(fstat), fd, &kbuf); - kernel_stat_to_stat(&kbuf, (struct stat *)buf); - return res; -# else - return internal_syscall(SYSCALL(fstat), fd, (uptr)buf); -# endif -#else - struct stat64 buf64; - int res = internal_syscall(SYSCALL(fstat64), fd, &buf64); - stat64_to_stat(&buf64, (struct stat *)buf); - return res; -#endif -} - -uptr internal_filesize(fd_t fd) { - struct stat st; - if (internal_fstat(fd, &st)) - return -1; - return (uptr)st.st_size; -} - -uptr internal_dup(int oldfd) { - return internal_syscall(SYSCALL(dup), oldfd); -} - -uptr internal_dup2(int oldfd, int newfd) { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS - return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0); -#else - return internal_syscall(SYSCALL(dup2), oldfd, newfd); -#endif -} - -uptr internal_readlink(const char *path, char *buf, uptr bufsize) { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS - return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, - bufsize); -#elif SANITIZER_OPENBSD - return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, - bufsize); -#else - return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize); -#endif -} - -uptr internal_unlink(const char *path) { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD - return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0); -#else - return internal_syscall(SYSCALL(unlink), (uptr)path); -#endif -} - -uptr internal_rename(const char *oldpath, const char *newpath) { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD - return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD, - (uptr)newpath); -#else - return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath); -#endif -} - -uptr internal_sched_yield() { - return internal_syscall(SYSCALL(sched_yield)); -} - -void internal__exit(int exitcode) { -#if SANITIZER_FREEBSD || SANITIZER_OPENBSD - internal_syscall(SYSCALL(exit), exitcode); -#else - internal_syscall(SYSCALL(exit_group), exitcode); -#endif - Die(); // Unreachable. -} - -unsigned int internal_sleep(unsigned int seconds) { - struct timespec ts; - ts.tv_sec = seconds; - ts.tv_nsec = 0; - int res = internal_syscall(SYSCALL(nanosleep), &ts, &ts); - if (res) return ts.tv_sec; - return 0; -} - -uptr internal_execve(const char *filename, char *const argv[], - char *const envp[]) { - return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv, - (uptr)envp); -} -#endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD - -// ----------------- sanitizer_common.h -bool FileExists(const char *filename) { - if (ShouldMockFailureToOpen(filename)) - return false; - struct stat st; -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS - if (internal_syscall(SYSCALL(newfstatat), AT_FDCWD, filename, &st, 0)) -#else - if (internal_stat(filename, &st)) -#endif - return false; - // Sanity check: filename is a regular file. - return S_ISREG(st.st_mode); -} - -#if !SANITIZER_NETBSD -tid_t GetTid() { -#if SANITIZER_FREEBSD - long Tid; - thr_self(&Tid); - return Tid; -#elif SANITIZER_OPENBSD - return internal_syscall(SYSCALL(getthrid)); -#elif SANITIZER_SOLARIS - return thr_self(); -#else - return internal_syscall(SYSCALL(gettid)); -#endif -} - -int TgKill(pid_t pid, tid_t tid, int sig) { -#if SANITIZER_LINUX - return internal_syscall(SYSCALL(tgkill), pid, tid, sig); -#elif SANITIZER_FREEBSD - return internal_syscall(SYSCALL(thr_kill2), pid, tid, sig); -#elif SANITIZER_OPENBSD - (void)pid; - return internal_syscall(SYSCALL(thrkill), tid, sig, nullptr); -#elif SANITIZER_SOLARIS - (void)pid; - return thr_kill(tid, sig); -#endif -} -#endif - -#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD -u64 NanoTime() { -#if SANITIZER_FREEBSD || SANITIZER_OPENBSD - timeval tv; -#else - kernel_timeval tv; -#endif - internal_memset(&tv, 0, sizeof(tv)); - internal_syscall(SYSCALL(gettimeofday), &tv, 0); - return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000; -} - -uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { - return internal_syscall(SYSCALL(clock_gettime), clk_id, tp); -} -#endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD - -// Like getenv, but reads env directly from /proc (on Linux) or parses the -// 'environ' array (on some others) and does not use libc. This function -// should be called first inside __asan_init. -const char *GetEnv(const char *name) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD || \ - SANITIZER_SOLARIS - if (::environ != 0) { - uptr NameLen = internal_strlen(name); - for (char **Env = ::environ; *Env != 0; Env++) { - if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=') - return (*Env) + NameLen + 1; - } - } - return 0; // Not found. -#elif SANITIZER_LINUX - static char *environ; - static uptr len; - static bool inited; - if (!inited) { - inited = true; - uptr environ_size; - if (!ReadFileToBuffer("/proc/self/environ", &environ, &environ_size, &len)) - environ = nullptr; - } - if (!environ || len == 0) return nullptr; - uptr namelen = internal_strlen(name); - const char *p = environ; - while (*p != '\0') { // will happen at the \0\0 that terminates the buffer - // proc file has the format NAME=value\0NAME=value\0NAME=value\0... - const char* endp = - (char*)internal_memchr(p, '\0', len - (p - environ)); - if (!endp) // this entry isn't NUL terminated - return nullptr; - else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match. - return p + namelen + 1; // point after = - p = endp + 1; - } - return nullptr; // Not found. -#else -#error "Unsupported platform" -#endif -} - -#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD -extern "C" { -SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end; -} -#endif - -#if !SANITIZER_GO && !SANITIZER_FREEBSD && !SANITIZER_NETBSD && \ - !SANITIZER_OPENBSD -static void ReadNullSepFileToArray(const char *path, char ***arr, - int arr_size) { - char *buff; - uptr buff_size; - uptr buff_len; - *arr = (char **)MmapOrDie(arr_size * sizeof(char *), "NullSepFileArray"); - if (!ReadFileToBuffer(path, &buff, &buff_size, &buff_len, 1024 * 1024)) { - (*arr)[0] = nullptr; - return; - } - (*arr)[0] = buff; - int count, i; - for (count = 1, i = 1; ; i++) { - if (buff[i] == 0) { - if (buff[i+1] == 0) break; - (*arr)[count] = &buff[i+1]; - CHECK_LE(count, arr_size - 1); // FIXME: make this more flexible. - count++; - } - } - (*arr)[count] = nullptr; -} -#endif - -#if !SANITIZER_OPENBSD -static void GetArgsAndEnv(char ***argv, char ***envp) { -#if SANITIZER_FREEBSD - // On FreeBSD, retrieving the argument and environment arrays is done via the - // kern.ps_strings sysctl, which returns a pointer to a structure containing - // this information. See also . - ps_strings *pss; - uptr sz = sizeof(pss); - if (internal_sysctlbyname("kern.ps_strings", &pss, &sz, NULL, 0) == -1) { - Printf("sysctl kern.ps_strings failed\n"); - Die(); - } - *argv = pss->ps_argvstr; - *envp = pss->ps_envstr; -#elif SANITIZER_NETBSD - *argv = __ps_strings->ps_argvstr; - *envp = __ps_strings->ps_envstr; -#else // SANITIZER_FREEBSD -#if !SANITIZER_GO - if (&__libc_stack_end) { -#endif // !SANITIZER_GO - uptr* stack_end = (uptr*)__libc_stack_end; - int argc = *stack_end; - *argv = (char**)(stack_end + 1); - *envp = (char**)(stack_end + argc + 2); -#if !SANITIZER_GO - } else { - static const int kMaxArgv = 2000, kMaxEnvp = 2000; - ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv); - ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp); - } -#endif // !SANITIZER_GO -#endif // SANITIZER_FREEBSD -} - -char **GetArgv() { - char **argv, **envp; - GetArgsAndEnv(&argv, &envp); - return argv; -} - -char **GetEnviron() { - char **argv, **envp; - GetArgsAndEnv(&argv, &envp); - return envp; -} - -#endif // !SANITIZER_OPENBSD - -#if !SANITIZER_SOLARIS -enum MutexState { - MtxUnlocked = 0, - MtxLocked = 1, - MtxSleeping = 2 -}; - -BlockingMutex::BlockingMutex() { - internal_memset(this, 0, sizeof(*this)); -} - -void BlockingMutex::Lock() { - CHECK_EQ(owner_, 0); - atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); - if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked) - return; - while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) { -#if SANITIZER_FREEBSD - _umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0); -#elif SANITIZER_NETBSD - sched_yield(); /* No userspace futex-like synchronization */ -#else - internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT_PRIVATE, MtxSleeping, - 0, 0, 0); -#endif - } -} - -void BlockingMutex::Unlock() { - atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); - u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release); - CHECK_NE(v, MtxUnlocked); - if (v == MtxSleeping) { -#if SANITIZER_FREEBSD - _umtx_op(m, UMTX_OP_WAKE, 1, 0, 0); -#elif SANITIZER_NETBSD - /* No userspace futex-like synchronization */ -#else - internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE_PRIVATE, 1, 0, 0, 0); -#endif - } -} - -void BlockingMutex::CheckLocked() { - atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); - CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed)); -} -#endif // !SANITIZER_SOLARIS - -// ----------------- sanitizer_linux.h -// The actual size of this structure is specified by d_reclen. -// Note that getdents64 uses a different structure format. We only provide the -// 32-bit syscall here. -#if SANITIZER_NETBSD -// Not used -#elif SANITIZER_OPENBSD -// struct dirent is different for Linux and us. At this moment, we use only -// d_fileno (Linux call this d_ino), d_reclen, and d_name. -struct linux_dirent { - u64 d_ino; // d_fileno - u16 d_reclen; - u16 d_namlen; // not used - u8 d_type; // not used - char d_name[NAME_MAX + 1]; -}; -#else -struct linux_dirent { -#if SANITIZER_X32 || defined(__aarch64__) - u64 d_ino; - u64 d_off; -#else - unsigned long d_ino; - unsigned long d_off; -#endif - unsigned short d_reclen; -#ifdef __aarch64__ - unsigned char d_type; -#endif - char d_name[256]; -}; -#endif - -#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD -// Syscall wrappers. -uptr internal_ptrace(int request, int pid, void *addr, void *data) { - return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr, - (uptr)data); -} - -uptr internal_waitpid(int pid, int *status, int options) { - return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options, - 0 /* rusage */); -} - -uptr internal_getpid() { - return internal_syscall(SYSCALL(getpid)); -} - -uptr internal_getppid() { - return internal_syscall(SYSCALL(getppid)); -} - -uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { -#if SANITIZER_FREEBSD - return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL); -#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS - return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count); -#else - return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count); -#endif -} - -uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { - return internal_syscall(SYSCALL(lseek), fd, offset, whence); -} - -#if SANITIZER_LINUX -uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { - return internal_syscall(SYSCALL(prctl), option, arg2, arg3, arg4, arg5); -} -#endif - -uptr internal_sigaltstack(const void *ss, void *oss) { - return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss); -} - -int internal_fork() { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS - return internal_syscall(SYSCALL(clone), SIGCHLD, 0); -#else - return internal_syscall(SYSCALL(fork)); -#endif -} - -#if SANITIZER_FREEBSD || SANITIZER_OPENBSD -int internal_sysctl(const int *name, unsigned int namelen, void *oldp, - uptr *oldlenp, const void *newp, uptr newlen) { -#if SANITIZER_OPENBSD - return sysctl(name, namelen, oldp, (size_t *)oldlenp, (void *)newp, - (size_t)newlen); -#else - return internal_syscall(SYSCALL(__sysctl), name, namelen, oldp, - (size_t *)oldlenp, newp, (size_t)newlen); -#endif -} - -#if SANITIZER_FREEBSD -int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, - const void *newp, uptr newlen) { - return sysctlbyname(sname, oldp, (size_t *)oldlenp, newp, (size_t)newlen); -} -#endif -#endif - -#if SANITIZER_LINUX -#define SA_RESTORER 0x04000000 -// Doesn't set sa_restorer if the caller did not set it, so use with caution -//(see below). -int internal_sigaction_norestorer(int signum, const void *act, void *oldact) { - __sanitizer_kernel_sigaction_t k_act, k_oldact; - internal_memset(&k_act, 0, sizeof(__sanitizer_kernel_sigaction_t)); - internal_memset(&k_oldact, 0, sizeof(__sanitizer_kernel_sigaction_t)); - const __sanitizer_sigaction *u_act = (const __sanitizer_sigaction *)act; - __sanitizer_sigaction *u_oldact = (__sanitizer_sigaction *)oldact; - if (u_act) { - k_act.handler = u_act->handler; - k_act.sigaction = u_act->sigaction; - internal_memcpy(&k_act.sa_mask, &u_act->sa_mask, - sizeof(__sanitizer_kernel_sigset_t)); - // Without SA_RESTORER kernel ignores the calls (probably returns EINVAL). - k_act.sa_flags = u_act->sa_flags | SA_RESTORER; - // FIXME: most often sa_restorer is unset, however the kernel requires it - // to point to a valid signal restorer that calls the rt_sigreturn syscall. - // If sa_restorer passed to the kernel is NULL, the program may crash upon - // signal delivery or fail to unwind the stack in the signal handler. - // libc implementation of sigaction() passes its own restorer to - // rt_sigaction, so we need to do the same (we'll need to reimplement the - // restorers; for x86_64 the restorer address can be obtained from - // oldact->sa_restorer upon a call to sigaction(xxx, NULL, oldact). -#if !SANITIZER_ANDROID || !SANITIZER_MIPS32 - k_act.sa_restorer = u_act->sa_restorer; -#endif - } - - uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum, - (uptr)(u_act ? &k_act : nullptr), - (uptr)(u_oldact ? &k_oldact : nullptr), - (uptr)sizeof(__sanitizer_kernel_sigset_t)); - - if ((result == 0) && u_oldact) { - u_oldact->handler = k_oldact.handler; - u_oldact->sigaction = k_oldact.sigaction; - internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask, - sizeof(__sanitizer_kernel_sigset_t)); - u_oldact->sa_flags = k_oldact.sa_flags; -#if !SANITIZER_ANDROID || !SANITIZER_MIPS32 - u_oldact->sa_restorer = k_oldact.sa_restorer; -#endif - } - return result; -} -#endif // SANITIZER_LINUX - -uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, - __sanitizer_sigset_t *oldset) { -#if SANITIZER_FREEBSD || SANITIZER_OPENBSD - return internal_syscall(SYSCALL(sigprocmask), how, set, oldset); -#else - __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; - __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset; - return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how, - (uptr)&k_set->sig[0], (uptr)&k_oldset->sig[0], - sizeof(__sanitizer_kernel_sigset_t)); -#endif -} - -void internal_sigfillset(__sanitizer_sigset_t *set) { - internal_memset(set, 0xff, sizeof(*set)); -} - -void internal_sigemptyset(__sanitizer_sigset_t *set) { - internal_memset(set, 0, sizeof(*set)); -} - -#if SANITIZER_LINUX -void internal_sigdelset(__sanitizer_sigset_t *set, int signum) { - signum -= 1; - CHECK_GE(signum, 0); - CHECK_LT(signum, sizeof(*set) * 8); - __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; - const uptr idx = signum / (sizeof(k_set->sig[0]) * 8); - const uptr bit = signum % (sizeof(k_set->sig[0]) * 8); - k_set->sig[idx] &= ~(1 << bit); -} - -bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { - signum -= 1; - CHECK_GE(signum, 0); - CHECK_LT(signum, sizeof(*set) * 8); - __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; - const uptr idx = signum / (sizeof(k_set->sig[0]) * 8); - const uptr bit = signum % (sizeof(k_set->sig[0]) * 8); - return k_set->sig[idx] & (1 << bit); -} -#elif SANITIZER_FREEBSD -void internal_sigdelset(__sanitizer_sigset_t *set, int signum) { - sigset_t *rset = reinterpret_cast(set); - sigdelset(rset, signum); -} - -bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { - sigset_t *rset = reinterpret_cast(set); - return sigismember(rset, signum); -} -#endif -#endif // !SANITIZER_SOLARIS - -#if !SANITIZER_NETBSD -// ThreadLister implementation. -ThreadLister::ThreadLister(pid_t pid) : pid_(pid), buffer_(4096) { - char task_directory_path[80]; - internal_snprintf(task_directory_path, sizeof(task_directory_path), - "/proc/%d/task/", pid); - descriptor_ = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY); - if (internal_iserror(descriptor_)) { - Report("Can't open /proc/%d/task for reading.\n", pid); - } -} - -ThreadLister::Result ThreadLister::ListThreads( - InternalMmapVector *threads) { - if (internal_iserror(descriptor_)) - return Error; - internal_lseek(descriptor_, 0, SEEK_SET); - threads->clear(); - - Result result = Ok; - for (bool first_read = true;; first_read = false) { - // Resize to max capacity if it was downsized by IsAlive. - buffer_.resize(buffer_.capacity()); - CHECK_GE(buffer_.size(), 4096); - uptr read = internal_getdents( - descriptor_, (struct linux_dirent *)buffer_.data(), buffer_.size()); - if (!read) - return result; - if (internal_iserror(read)) { - Report("Can't read directory entries from /proc/%d/task.\n", pid_); - return Error; - } - - for (uptr begin = (uptr)buffer_.data(), end = begin + read; begin < end;) { - struct linux_dirent *entry = (struct linux_dirent *)begin; - begin += entry->d_reclen; - if (entry->d_ino == 1) { - // Inode 1 is for bad blocks and also can be a reason for early return. - // Should be emitted if kernel tried to output terminating thread. - // See proc_task_readdir implementation in Linux. - result = Incomplete; - } - if (entry->d_ino && *entry->d_name >= '0' && *entry->d_name <= '9') - threads->push_back(internal_atoll(entry->d_name)); - } - - // Now we are going to detect short-read or early EOF. In such cases Linux - // can return inconsistent list with missing alive threads. - // Code will just remember that the list can be incomplete but it will - // continue reads to return as much as possible. - if (!first_read) { - // The first one was a short-read by definition. - result = Incomplete; - } else if (read > buffer_.size() - 1024) { - // Read was close to the buffer size. So double the size and assume the - // worst. - buffer_.resize(buffer_.size() * 2); - result = Incomplete; - } else if (!threads->empty() && !IsAlive(threads->back())) { - // Maybe Linux early returned from read on terminated thread (!pid_alive) - // and failed to restore read position. - // See next_tid and proc_task_instantiate in Linux. - result = Incomplete; - } - } -} - -bool ThreadLister::IsAlive(int tid) { - // /proc/%d/task/%d/status uses same call to detect alive threads as - // proc_task_readdir. See task_state implementation in Linux. - char path[80]; - internal_snprintf(path, sizeof(path), "/proc/%d/task/%d/status", pid_, tid); - if (!ReadFileToVector(path, &buffer_) || buffer_.empty()) - return false; - buffer_.push_back(0); - static const char kPrefix[] = "\nPPid:"; - const char *field = internal_strstr(buffer_.data(), kPrefix); - if (!field) - return false; - field += internal_strlen(kPrefix); - return (int)internal_atoll(field) != 0; -} - -ThreadLister::~ThreadLister() { - if (!internal_iserror(descriptor_)) - internal_close(descriptor_); -} -#endif - -#if SANITIZER_WORDSIZE == 32 -// Take care of unusable kernel area in top gigabyte. -static uptr GetKernelAreaSize() { -#if SANITIZER_LINUX && !SANITIZER_X32 - const uptr gbyte = 1UL << 30; - - // Firstly check if there are writable segments - // mapped to top gigabyte (e.g. stack). - MemoryMappingLayout proc_maps(/*cache_enabled*/true); - if (proc_maps.Error()) - return 0; - MemoryMappedSegment segment; - while (proc_maps.Next(&segment)) { - if ((segment.end >= 3 * gbyte) && segment.IsWritable()) return 0; - } - -#if !SANITIZER_ANDROID - // Even if nothing is mapped, top Gb may still be accessible - // if we are running on 64-bit kernel. - // Uname may report misleading results if personality type - // is modified (e.g. under schroot) so check this as well. - struct utsname uname_info; - int pers = personality(0xffffffffUL); - if (!(pers & PER_MASK) - && uname(&uname_info) == 0 - && internal_strstr(uname_info.machine, "64")) - return 0; -#endif // SANITIZER_ANDROID - - // Top gigabyte is reserved for kernel. - return gbyte; -#else - return 0; -#endif // SANITIZER_LINUX && !SANITIZER_X32 -} -#endif // SANITIZER_WORDSIZE == 32 - -uptr GetMaxVirtualAddress() { -#if (SANITIZER_NETBSD || SANITIZER_OPENBSD) && defined(__x86_64__) - return 0x7f7ffffff000ULL; // (0x00007f8000000000 - PAGE_SIZE) -#elif SANITIZER_WORDSIZE == 64 -# if defined(__powerpc64__) || defined(__aarch64__) - // On PowerPC64 we have two different address space layouts: 44- and 46-bit. - // We somehow need to figure out which one we are using now and choose - // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL. - // Note that with 'ulimit -s unlimited' the stack is moved away from the top - // of the address space, so simply checking the stack address is not enough. - // This should (does) work for both PowerPC64 Endian modes. - // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit. - return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1; -# elif defined(__mips64) - return (1ULL << 40) - 1; // 0x000000ffffffffffUL; -# elif defined(__s390x__) - return (1ULL << 53) - 1; // 0x001fffffffffffffUL; -#elif defined(__sparc__) - return ~(uptr)0; -# else - return (1ULL << 47) - 1; // 0x00007fffffffffffUL; -# endif -#else // SANITIZER_WORDSIZE == 32 -# if defined(__s390__) - return (1ULL << 31) - 1; // 0x7fffffff; -# else - return (1ULL << 32) - 1; // 0xffffffff; -# endif -#endif // SANITIZER_WORDSIZE -} - -uptr GetMaxUserVirtualAddress() { - uptr addr = GetMaxVirtualAddress(); -#if SANITIZER_WORDSIZE == 32 && !defined(__s390__) - if (!common_flags()->full_address_space) - addr -= GetKernelAreaSize(); - CHECK_LT(reinterpret_cast(&addr), addr); -#endif - return addr; -} - -#if !SANITIZER_ANDROID -uptr GetPageSize() { -#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) - return EXEC_PAGESIZE; -#elif SANITIZER_USE_GETAUXVAL - return getauxval(AT_PAGESZ); -#elif SANITIZER_FREEBSD || SANITIZER_NETBSD -// Use sysctl as sysconf can trigger interceptors internally. - int pz = 0; - uptr pzl = sizeof(pz); - int mib[2] = {CTL_HW, HW_PAGESIZE}; - int rv = internal_sysctl(mib, 2, &pz, &pzl, nullptr, 0); - CHECK_EQ(rv, 0); - return (uptr)pz; -#else - return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy. -#endif -} -#endif // !SANITIZER_ANDROID - -#if !SANITIZER_OPENBSD -uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { -#if SANITIZER_SOLARIS - const char *default_module_name = getexecname(); - CHECK_NE(default_module_name, NULL); - return internal_snprintf(buf, buf_len, "%s", default_module_name); -#else -#if SANITIZER_FREEBSD || SANITIZER_NETBSD -#if SANITIZER_FREEBSD - const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; -#else - const int Mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; -#endif - const char *default_module_name = "kern.proc.pathname"; - uptr Size = buf_len; - bool IsErr = - (internal_sysctl(Mib, ARRAY_SIZE(Mib), buf, &Size, NULL, 0) != 0); - int readlink_error = IsErr ? errno : 0; - uptr module_name_len = Size; -#else - const char *default_module_name = "/proc/self/exe"; - uptr module_name_len = internal_readlink( - default_module_name, buf, buf_len); - int readlink_error; - bool IsErr = internal_iserror(module_name_len, &readlink_error); -#endif // SANITIZER_SOLARIS - if (IsErr) { - // We can't read binary name for some reason, assume it's unknown. - Report("WARNING: reading executable name failed with errno %d, " - "some stack frames may not be symbolized\n", readlink_error); - module_name_len = internal_snprintf(buf, buf_len, "%s", - default_module_name); - CHECK_LT(module_name_len, buf_len); - } - return module_name_len; -#endif -} -#endif // !SANITIZER_OPENBSD - -uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { -#if SANITIZER_LINUX - char *tmpbuf; - uptr tmpsize; - uptr tmplen; - if (ReadFileToBuffer("/proc/self/cmdline", &tmpbuf, &tmpsize, &tmplen, - 1024 * 1024)) { - internal_strncpy(buf, tmpbuf, buf_len); - UnmapOrDie(tmpbuf, tmpsize); - return internal_strlen(buf); - } -#endif - return ReadBinaryName(buf, buf_len); -} - -// Match full names of the form /path/to/base_name{-,.}* -bool LibraryNameIs(const char *full_name, const char *base_name) { - const char *name = full_name; - // Strip path. - while (*name != '\0') name++; - while (name > full_name && *name != '/') name--; - if (*name == '/') name++; - uptr base_name_length = internal_strlen(base_name); - if (internal_strncmp(name, base_name, base_name_length)) return false; - return (name[base_name_length] == '-' || name[base_name_length] == '.'); -} - -#if !SANITIZER_ANDROID -// Call cb for each region mapped by map. -void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) { - CHECK_NE(map, nullptr); -#if !SANITIZER_FREEBSD && !SANITIZER_OPENBSD - typedef ElfW(Phdr) Elf_Phdr; - typedef ElfW(Ehdr) Elf_Ehdr; -#endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD - char *base = (char *)map->l_addr; - Elf_Ehdr *ehdr = (Elf_Ehdr *)base; - char *phdrs = base + ehdr->e_phoff; - char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize; - - // Find the segment with the minimum base so we can "relocate" the p_vaddr - // fields. Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC - // objects have a non-zero base. - uptr preferred_base = (uptr)-1; - for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { - Elf_Phdr *phdr = (Elf_Phdr *)iter; - if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr) - preferred_base = (uptr)phdr->p_vaddr; - } - - // Compute the delta from the real base to get a relocation delta. - sptr delta = (uptr)base - preferred_base; - // Now we can figure out what the loader really mapped. - for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { - Elf_Phdr *phdr = (Elf_Phdr *)iter; - if (phdr->p_type == PT_LOAD) { - uptr seg_start = phdr->p_vaddr + delta; - uptr seg_end = seg_start + phdr->p_memsz; - // None of these values are aligned. We consider the ragged edges of the - // load command as defined, since they are mapped from the file. - seg_start = RoundDownTo(seg_start, GetPageSizeCached()); - seg_end = RoundUpTo(seg_end, GetPageSizeCached()); - cb((void *)seg_start, seg_end - seg_start); - } - } -} -#endif - -#if defined(__x86_64__) && SANITIZER_LINUX -// We cannot use glibc's clone wrapper, because it messes with the child -// task's TLS. It writes the PID and TID of the child task to its thread -// descriptor, but in our case the child task shares the thread descriptor with -// the parent (because we don't know how to allocate a new thread -// descriptor to keep glibc happy). So the stock version of clone(), when -// used with CLONE_VM, would end up corrupting the parent's thread descriptor. -uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, - int *parent_tidptr, void *newtls, int *child_tidptr) { - long long res; - if (!fn || !child_stack) - return -EINVAL; - CHECK_EQ(0, (uptr)child_stack % 16); - child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); - ((unsigned long long *)child_stack)[0] = (uptr)fn; - ((unsigned long long *)child_stack)[1] = (uptr)arg; - register void *r8 __asm__("r8") = newtls; - register int *r10 __asm__("r10") = child_tidptr; - __asm__ __volatile__( - /* %rax = syscall(%rax = SYSCALL(clone), - * %rdi = flags, - * %rsi = child_stack, - * %rdx = parent_tidptr, - * %r8 = new_tls, - * %r10 = child_tidptr) - */ - "syscall\n" - - /* if (%rax != 0) - * return; - */ - "testq %%rax,%%rax\n" - "jnz 1f\n" - - /* In the child. Terminate unwind chain. */ - // XXX: We should also terminate the CFI unwind chain - // here. Unfortunately clang 3.2 doesn't support the - // necessary CFI directives, so we skip that part. - "xorq %%rbp,%%rbp\n" - - /* Call "fn(arg)". */ - "popq %%rax\n" - "popq %%rdi\n" - "call *%%rax\n" - - /* Call _exit(%rax). */ - "movq %%rax,%%rdi\n" - "movq %2,%%rax\n" - "syscall\n" - - /* Return to parent. */ - "1:\n" - : "=a" (res) - : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), - "S"(child_stack), - "D"(flags), - "d"(parent_tidptr), - "r"(r8), - "r"(r10) - : "memory", "r11", "rcx"); - return res; -} -#elif defined(__mips__) -uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, - int *parent_tidptr, void *newtls, int *child_tidptr) { - long long res; - if (!fn || !child_stack) - return -EINVAL; - CHECK_EQ(0, (uptr)child_stack % 16); - child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); - ((unsigned long long *)child_stack)[0] = (uptr)fn; - ((unsigned long long *)child_stack)[1] = (uptr)arg; - register void *a3 __asm__("$7") = newtls; - register int *a4 __asm__("$8") = child_tidptr; - // We don't have proper CFI directives here because it requires alot of code - // for very marginal benefits. - __asm__ __volatile__( - /* $v0 = syscall($v0 = __NR_clone, - * $a0 = flags, - * $a1 = child_stack, - * $a2 = parent_tidptr, - * $a3 = new_tls, - * $a4 = child_tidptr) - */ - ".cprestore 16;\n" - "move $4,%1;\n" - "move $5,%2;\n" - "move $6,%3;\n" - "move $7,%4;\n" - /* Store the fifth argument on stack - * if we are using 32-bit abi. - */ -#if SANITIZER_WORDSIZE == 32 - "lw %5,16($29);\n" -#else - "move $8,%5;\n" -#endif - "li $2,%6;\n" - "syscall;\n" - - /* if ($v0 != 0) - * return; - */ - "bnez $2,1f;\n" - - /* Call "fn(arg)". */ -#if SANITIZER_WORDSIZE == 32 -#ifdef __BIG_ENDIAN__ - "lw $25,4($29);\n" - "lw $4,12($29);\n" -#else - "lw $25,0($29);\n" - "lw $4,8($29);\n" -#endif -#else - "ld $25,0($29);\n" - "ld $4,8($29);\n" -#endif - "jal $25;\n" - - /* Call _exit($v0). */ - "move $4,$2;\n" - "li $2,%7;\n" - "syscall;\n" - - /* Return to parent. */ - "1:\n" - : "=r" (res) - : "r"(flags), - "r"(child_stack), - "r"(parent_tidptr), - "r"(a3), - "r"(a4), - "i"(__NR_clone), - "i"(__NR_exit) - : "memory", "$29" ); - return res; -} -#elif defined(__aarch64__) -uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, - int *parent_tidptr, void *newtls, int *child_tidptr) { - long long res; - if (!fn || !child_stack) - return -EINVAL; - CHECK_EQ(0, (uptr)child_stack % 16); - child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); - ((unsigned long long *)child_stack)[0] = (uptr)fn; - ((unsigned long long *)child_stack)[1] = (uptr)arg; - - register int (*__fn)(void *) __asm__("x0") = fn; - register void *__stack __asm__("x1") = child_stack; - register int __flags __asm__("x2") = flags; - register void *__arg __asm__("x3") = arg; - register int *__ptid __asm__("x4") = parent_tidptr; - register void *__tls __asm__("x5") = newtls; - register int *__ctid __asm__("x6") = child_tidptr; - - __asm__ __volatile__( - "mov x0,x2\n" /* flags */ - "mov x2,x4\n" /* ptid */ - "mov x3,x5\n" /* tls */ - "mov x4,x6\n" /* ctid */ - "mov x8,%9\n" /* clone */ - - "svc 0x0\n" - - /* if (%r0 != 0) - * return %r0; - */ - "cmp x0, #0\n" - "bne 1f\n" - - /* In the child, now. Call "fn(arg)". */ - "ldp x1, x0, [sp], #16\n" - "blr x1\n" - - /* Call _exit(%r0). */ - "mov x8, %10\n" - "svc 0x0\n" - "1:\n" - - : "=r" (res) - : "i"(-EINVAL), - "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg), - "r"(__ptid), "r"(__tls), "r"(__ctid), - "i"(__NR_clone), "i"(__NR_exit) - : "x30", "memory"); - return res; -} -#elif defined(__powerpc64__) -uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, - int *parent_tidptr, void *newtls, int *child_tidptr) { - long long res; -// Stack frame structure. -#if SANITIZER_PPC64V1 -// Back chain == 0 (SP + 112) -// Frame (112 bytes): -// Parameter save area (SP + 48), 8 doublewords -// TOC save area (SP + 40) -// Link editor doubleword (SP + 32) -// Compiler doubleword (SP + 24) -// LR save area (SP + 16) -// CR save area (SP + 8) -// Back chain (SP + 0) -# define FRAME_SIZE 112 -# define FRAME_TOC_SAVE_OFFSET 40 -#elif SANITIZER_PPC64V2 -// Back chain == 0 (SP + 32) -// Frame (32 bytes): -// TOC save area (SP + 24) -// LR save area (SP + 16) -// CR save area (SP + 8) -// Back chain (SP + 0) -# define FRAME_SIZE 32 -# define FRAME_TOC_SAVE_OFFSET 24 -#else -# error "Unsupported PPC64 ABI" -#endif - if (!fn || !child_stack) - return -EINVAL; - CHECK_EQ(0, (uptr)child_stack % 16); - - register int (*__fn)(void *) __asm__("r3") = fn; - register void *__cstack __asm__("r4") = child_stack; - register int __flags __asm__("r5") = flags; - register void *__arg __asm__("r6") = arg; - register int *__ptidptr __asm__("r7") = parent_tidptr; - register void *__newtls __asm__("r8") = newtls; - register int *__ctidptr __asm__("r9") = child_tidptr; - - __asm__ __volatile__( - /* fn and arg are saved across the syscall */ - "mr 28, %5\n\t" - "mr 27, %8\n\t" - - /* syscall - r0 == __NR_clone - r3 == flags - r4 == child_stack - r5 == parent_tidptr - r6 == newtls - r7 == child_tidptr */ - "mr 3, %7\n\t" - "mr 5, %9\n\t" - "mr 6, %10\n\t" - "mr 7, %11\n\t" - "li 0, %3\n\t" - "sc\n\t" - - /* Test if syscall was successful */ - "cmpdi cr1, 3, 0\n\t" - "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t" - "bne- cr1, 1f\n\t" - - /* Set up stack frame */ - "li 29, 0\n\t" - "stdu 29, -8(1)\n\t" - "stdu 1, -%12(1)\n\t" - /* Do the function call */ - "std 2, %13(1)\n\t" -#if SANITIZER_PPC64V1 - "ld 0, 0(28)\n\t" - "ld 2, 8(28)\n\t" - "mtctr 0\n\t" -#elif SANITIZER_PPC64V2 - "mr 12, 28\n\t" - "mtctr 12\n\t" -#else -# error "Unsupported PPC64 ABI" -#endif - "mr 3, 27\n\t" - "bctrl\n\t" - "ld 2, %13(1)\n\t" - - /* Call _exit(r3) */ - "li 0, %4\n\t" - "sc\n\t" - - /* Return to parent */ - "1:\n\t" - "mr %0, 3\n\t" - : "=r" (res) - : "0" (-1), - "i" (EINVAL), - "i" (__NR_clone), - "i" (__NR_exit), - "r" (__fn), - "r" (__cstack), - "r" (__flags), - "r" (__arg), - "r" (__ptidptr), - "r" (__newtls), - "r" (__ctidptr), - "i" (FRAME_SIZE), - "i" (FRAME_TOC_SAVE_OFFSET) - : "cr0", "cr1", "memory", "ctr", "r0", "r27", "r28", "r29"); - return res; -} -#elif defined(__i386__) && SANITIZER_LINUX -uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, - int *parent_tidptr, void *newtls, int *child_tidptr) { - int res; - if (!fn || !child_stack) - return -EINVAL; - CHECK_EQ(0, (uptr)child_stack % 16); - child_stack = (char *)child_stack - 7 * sizeof(unsigned int); - ((unsigned int *)child_stack)[0] = (uptr)flags; - ((unsigned int *)child_stack)[1] = (uptr)0; - ((unsigned int *)child_stack)[2] = (uptr)fn; - ((unsigned int *)child_stack)[3] = (uptr)arg; - __asm__ __volatile__( - /* %eax = syscall(%eax = SYSCALL(clone), - * %ebx = flags, - * %ecx = child_stack, - * %edx = parent_tidptr, - * %esi = new_tls, - * %edi = child_tidptr) - */ - - /* Obtain flags */ - "movl (%%ecx), %%ebx\n" - /* Do the system call */ - "pushl %%ebx\n" - "pushl %%esi\n" - "pushl %%edi\n" - /* Remember the flag value. */ - "movl %%ebx, (%%ecx)\n" - "int $0x80\n" - "popl %%edi\n" - "popl %%esi\n" - "popl %%ebx\n" - - /* if (%eax != 0) - * return; - */ - - "test %%eax,%%eax\n" - "jnz 1f\n" - - /* terminate the stack frame */ - "xorl %%ebp,%%ebp\n" - /* Call FN. */ - "call *%%ebx\n" -#ifdef PIC - "call here\n" - "here:\n" - "popl %%ebx\n" - "addl $_GLOBAL_OFFSET_TABLE_+[.-here], %%ebx\n" -#endif - /* Call exit */ - "movl %%eax, %%ebx\n" - "movl %2, %%eax\n" - "int $0x80\n" - "1:\n" - : "=a" (res) - : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), - "c"(child_stack), - "d"(parent_tidptr), - "S"(newtls), - "D"(child_tidptr) - : "memory"); - return res; -} -#elif defined(__arm__) && SANITIZER_LINUX -uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, - int *parent_tidptr, void *newtls, int *child_tidptr) { - unsigned int res; - if (!fn || !child_stack) - return -EINVAL; - child_stack = (char *)child_stack - 2 * sizeof(unsigned int); - ((unsigned int *)child_stack)[0] = (uptr)fn; - ((unsigned int *)child_stack)[1] = (uptr)arg; - register int r0 __asm__("r0") = flags; - register void *r1 __asm__("r1") = child_stack; - register int *r2 __asm__("r2") = parent_tidptr; - register void *r3 __asm__("r3") = newtls; - register int *r4 __asm__("r4") = child_tidptr; - register int r7 __asm__("r7") = __NR_clone; - -#if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__) -# define ARCH_HAS_BX -#endif -#if __ARM_ARCH > 4 -# define ARCH_HAS_BLX -#endif - -#ifdef ARCH_HAS_BX -# ifdef ARCH_HAS_BLX -# define BLX(R) "blx " #R "\n" -# else -# define BLX(R) "mov lr, pc; bx " #R "\n" -# endif -#else -# define BLX(R) "mov lr, pc; mov pc," #R "\n" -#endif - - __asm__ __volatile__( - /* %r0 = syscall(%r7 = SYSCALL(clone), - * %r0 = flags, - * %r1 = child_stack, - * %r2 = parent_tidptr, - * %r3 = new_tls, - * %r4 = child_tidptr) - */ - - /* Do the system call */ - "swi 0x0\n" - - /* if (%r0 != 0) - * return %r0; - */ - "cmp r0, #0\n" - "bne 1f\n" - - /* In the child, now. Call "fn(arg)". */ - "ldr r0, [sp, #4]\n" - "ldr ip, [sp], #8\n" - BLX(ip) - /* Call _exit(%r0). */ - "mov r7, %7\n" - "swi 0x0\n" - "1:\n" - "mov %0, r0\n" - : "=r"(res) - : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7), - "i"(__NR_exit) - : "memory"); - return res; -} -#endif // defined(__x86_64__) && SANITIZER_LINUX - -#if SANITIZER_ANDROID -#if __ANDROID_API__ < 21 -extern "C" __attribute__((weak)) int dl_iterate_phdr( - int (*)(struct dl_phdr_info *, size_t, void *), void *); -#endif - -static int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size, - void *data) { - // Any name starting with "lib" indicates a bug in L where library base names - // are returned instead of paths. - if (info->dlpi_name && info->dlpi_name[0] == 'l' && - info->dlpi_name[1] == 'i' && info->dlpi_name[2] == 'b') { - *(bool *)data = true; - return 1; - } - return 0; -} - -static atomic_uint32_t android_api_level; - -static AndroidApiLevel AndroidDetectApiLevelStatic() { -#if __ANDROID_API__ <= 19 - return ANDROID_KITKAT; -#elif __ANDROID_API__ <= 22 - return ANDROID_LOLLIPOP_MR1; -#else - return ANDROID_POST_LOLLIPOP; -#endif -} - -static AndroidApiLevel AndroidDetectApiLevel() { - if (!&dl_iterate_phdr) - return ANDROID_KITKAT; // K or lower - bool base_name_seen = false; - dl_iterate_phdr(dl_iterate_phdr_test_cb, &base_name_seen); - if (base_name_seen) - return ANDROID_LOLLIPOP_MR1; // L MR1 - return ANDROID_POST_LOLLIPOP; // post-L - // Plain L (API level 21) is completely broken wrt ASan and not very - // interesting to detect. -} - -extern "C" __attribute__((weak)) void* _DYNAMIC; - -AndroidApiLevel AndroidGetApiLevel() { - AndroidApiLevel level = - (AndroidApiLevel)atomic_load(&android_api_level, memory_order_relaxed); - if (level) return level; - level = &_DYNAMIC == nullptr ? AndroidDetectApiLevelStatic() - : AndroidDetectApiLevel(); - atomic_store(&android_api_level, level, memory_order_relaxed); - return level; -} - -#endif - -static HandleSignalMode GetHandleSignalModeImpl(int signum) { - switch (signum) { - case SIGABRT: - return common_flags()->handle_abort; - case SIGILL: - return common_flags()->handle_sigill; - case SIGTRAP: - return common_flags()->handle_sigtrap; - case SIGFPE: - return common_flags()->handle_sigfpe; - case SIGSEGV: - return common_flags()->handle_segv; - case SIGBUS: - return common_flags()->handle_sigbus; - } - return kHandleSignalNo; -} - -HandleSignalMode GetHandleSignalMode(int signum) { - HandleSignalMode result = GetHandleSignalModeImpl(signum); - if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler) - return kHandleSignalExclusive; - return result; -} - -#if !SANITIZER_GO -void *internal_start_thread(void(*func)(void *arg), void *arg) { - // Start the thread with signals blocked, otherwise it can steal user signals. - __sanitizer_sigset_t set, old; - internal_sigfillset(&set); -#if SANITIZER_LINUX && !SANITIZER_ANDROID - // Glibc uses SIGSETXID signal during setuid call. If this signal is blocked - // on any thread, setuid call hangs (see test/tsan/setuid.c). - internal_sigdelset(&set, 33); -#endif - internal_sigprocmask(SIG_SETMASK, &set, &old); - void *th; - real_pthread_create(&th, nullptr, (void*(*)(void *arg))func, arg); - internal_sigprocmask(SIG_SETMASK, &old, nullptr); - return th; -} - -void internal_join_thread(void *th) { - real_pthread_join(th, nullptr); -} -#else -void *internal_start_thread(void (*func)(void *), void *arg) { return 0; } - -void internal_join_thread(void *th) {} -#endif - -#if defined(__aarch64__) -// Android headers in the older NDK releases miss this definition. -struct __sanitizer_esr_context { - struct _aarch64_ctx head; - uint64_t esr; -}; - -static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) { - static const u32 kEsrMagic = 0x45535201; - u8 *aux = ucontext->uc_mcontext.__reserved; - while (true) { - _aarch64_ctx *ctx = (_aarch64_ctx *)aux; - if (ctx->size == 0) break; - if (ctx->magic == kEsrMagic) { - *esr = ((__sanitizer_esr_context *)ctx)->esr; - return true; - } - aux += ctx->size; - } - return false; -} -#endif - -#if SANITIZER_OPENBSD -using Context = sigcontext; -#else -using Context = ucontext_t; -#endif - -SignalContext::WriteFlag SignalContext::GetWriteFlag() const { - Context *ucontext = (Context *)context; -#if defined(__x86_64__) || defined(__i386__) - static const uptr PF_WRITE = 1U << 1; -#if SANITIZER_FREEBSD - uptr err = ucontext->uc_mcontext.mc_err; -#elif SANITIZER_NETBSD - uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR]; -#elif SANITIZER_OPENBSD - uptr err = ucontext->sc_err; -#elif SANITIZER_SOLARIS && defined(__i386__) - const int Err = 13; - uptr err = ucontext->uc_mcontext.gregs[Err]; -#else - uptr err = ucontext->uc_mcontext.gregs[REG_ERR]; -#endif // SANITIZER_FREEBSD - return err & PF_WRITE ? WRITE : READ; -#elif defined(__mips__) - uint32_t *exception_source; - uint32_t faulty_instruction; - uint32_t op_code; - - exception_source = (uint32_t *)ucontext->uc_mcontext.pc; - faulty_instruction = (uint32_t)(*exception_source); - - op_code = (faulty_instruction >> 26) & 0x3f; - - // FIXME: Add support for FPU, microMIPS, DSP, MSA memory instructions. - switch (op_code) { - case 0x28: // sb - case 0x29: // sh - case 0x2b: // sw - case 0x3f: // sd -#if __mips_isa_rev < 6 - case 0x2c: // sdl - case 0x2d: // sdr - case 0x2a: // swl - case 0x2e: // swr -#endif - return SignalContext::WRITE; - - case 0x20: // lb - case 0x24: // lbu - case 0x21: // lh - case 0x25: // lhu - case 0x23: // lw - case 0x27: // lwu - case 0x37: // ld -#if __mips_isa_rev < 6 - case 0x1a: // ldl - case 0x1b: // ldr - case 0x22: // lwl - case 0x26: // lwr -#endif - return SignalContext::READ; -#if __mips_isa_rev == 6 - case 0x3b: // pcrel - op_code = (faulty_instruction >> 19) & 0x3; - switch (op_code) { - case 0x1: // lwpc - case 0x2: // lwupc - return SignalContext::READ; - } -#endif - } - return SignalContext::UNKNOWN; -#elif defined(__arm__) - static const uptr FSR_WRITE = 1U << 11; - uptr fsr = ucontext->uc_mcontext.error_code; - return fsr & FSR_WRITE ? WRITE : READ; -#elif defined(__aarch64__) - static const u64 ESR_ELx_WNR = 1U << 6; - u64 esr; - if (!Aarch64GetESR(ucontext, &esr)) return UNKNOWN; - return esr & ESR_ELx_WNR ? WRITE : READ; -#elif defined(__sparc__) - // Decode the instruction to determine the access type. - // From OpenSolaris $SRC/uts/sun4/os/trap.c (get_accesstype). -#if SANITIZER_SOLARIS - uptr pc = ucontext->uc_mcontext.gregs[REG_PC]; -#else - // Historical BSDism here. - struct sigcontext *scontext = (struct sigcontext *)context; -#if defined(__arch64__) - uptr pc = scontext->sigc_regs.tpc; -#else - uptr pc = scontext->si_regs.pc; -#endif -#endif - u32 instr = *(u32 *)pc; - return (instr >> 21) & 1 ? WRITE: READ; -#else - (void)ucontext; - return UNKNOWN; // FIXME: Implement. -#endif -} - -void SignalContext::DumpAllRegisters(void *context) { - // FIXME: Implement this. -} - -static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { -#if SANITIZER_NETBSD - // This covers all NetBSD architectures - ucontext_t *ucontext = (ucontext_t *)context; - *pc = _UC_MACHINE_PC(ucontext); - *bp = _UC_MACHINE_FP(ucontext); - *sp = _UC_MACHINE_SP(ucontext); -#elif defined(__arm__) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.arm_pc; - *bp = ucontext->uc_mcontext.arm_fp; - *sp = ucontext->uc_mcontext.arm_sp; -#elif defined(__aarch64__) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.pc; - *bp = ucontext->uc_mcontext.regs[29]; - *sp = ucontext->uc_mcontext.sp; -#elif defined(__hppa__) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.sc_iaoq[0]; - /* GCC uses %r3 whenever a frame pointer is needed. */ - *bp = ucontext->uc_mcontext.sc_gr[3]; - *sp = ucontext->uc_mcontext.sc_gr[30]; -#elif defined(__x86_64__) -# if SANITIZER_FREEBSD - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.mc_rip; - *bp = ucontext->uc_mcontext.mc_rbp; - *sp = ucontext->uc_mcontext.mc_rsp; -#elif SANITIZER_OPENBSD - sigcontext *ucontext = (sigcontext *)context; - *pc = ucontext->sc_rip; - *bp = ucontext->sc_rbp; - *sp = ucontext->sc_rsp; -# else - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.gregs[REG_RIP]; - *bp = ucontext->uc_mcontext.gregs[REG_RBP]; - *sp = ucontext->uc_mcontext.gregs[REG_RSP]; -# endif -#elif defined(__i386__) -# if SANITIZER_FREEBSD - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.mc_eip; - *bp = ucontext->uc_mcontext.mc_ebp; - *sp = ucontext->uc_mcontext.mc_esp; -#elif SANITIZER_OPENBSD - sigcontext *ucontext = (sigcontext *)context; - *pc = ucontext->sc_eip; - *bp = ucontext->sc_ebp; - *sp = ucontext->sc_esp; -# else - ucontext_t *ucontext = (ucontext_t*)context; -# if SANITIZER_SOLARIS - /* Use the numeric values: the symbolic ones are undefined by llvm - include/llvm/Support/Solaris.h. */ -# ifndef REG_EIP -# define REG_EIP 14 // REG_PC -# endif -# ifndef REG_EBP -# define REG_EBP 6 // REG_FP -# endif -# ifndef REG_ESP -# define REG_ESP 17 // REG_SP -# endif -# endif - *pc = ucontext->uc_mcontext.gregs[REG_EIP]; - *bp = ucontext->uc_mcontext.gregs[REG_EBP]; - *sp = ucontext->uc_mcontext.gregs[REG_ESP]; -# endif -#elif defined(__powerpc__) || defined(__powerpc64__) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.regs->nip; - *sp = ucontext->uc_mcontext.regs->gpr[PT_R1]; - // The powerpc{,64}-linux ABIs do not specify r31 as the frame - // pointer, but GCC always uses r31 when we need a frame pointer. - *bp = ucontext->uc_mcontext.regs->gpr[PT_R31]; -#elif defined(__sparc__) -#if defined(__arch64__) || defined(__sparcv9) -#define STACK_BIAS 2047 -#else -#define STACK_BIAS 0 -# endif -# if SANITIZER_SOLARIS - ucontext_t *ucontext = (ucontext_t *)context; - *pc = ucontext->uc_mcontext.gregs[REG_PC]; - *sp = ucontext->uc_mcontext.gregs[REG_O6] + STACK_BIAS; -#else - // Historical BSDism here. - struct sigcontext *scontext = (struct sigcontext *)context; -#if defined(__arch64__) - *pc = scontext->sigc_regs.tpc; - *sp = scontext->sigc_regs.u_regs[14] + STACK_BIAS; -#else - *pc = scontext->si_regs.pc; - *sp = scontext->si_regs.u_regs[14]; -#endif -# endif - *bp = (uptr)((uhwptr *)*sp)[14] + STACK_BIAS; -#elif defined(__mips__) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.pc; - *bp = ucontext->uc_mcontext.gregs[30]; - *sp = ucontext->uc_mcontext.gregs[29]; -#elif defined(__s390__) - ucontext_t *ucontext = (ucontext_t*)context; -# if defined(__s390x__) - *pc = ucontext->uc_mcontext.psw.addr; -# else - *pc = ucontext->uc_mcontext.psw.addr & 0x7fffffff; -# endif - *bp = ucontext->uc_mcontext.gregs[11]; - *sp = ucontext->uc_mcontext.gregs[15]; -#else -# error "Unsupported arch" -#endif -} - -void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } - -void InitializePlatformEarly() { - // Do nothing. -} - -void MaybeReexec() { - // No need to re-exec on Linux. -} - -void CheckASLR() { -#if SANITIZER_NETBSD - int mib[3]; - int paxflags; - uptr len = sizeof(paxflags); - - mib[0] = CTL_PROC; - mib[1] = internal_getpid(); - mib[2] = PROC_PID_PAXFLAGS; - - if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) { - Printf("sysctl failed\n"); - Die(); - } - - if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) { - Printf("This sanitizer is not compatible with enabled ASLR\n"); - Die(); - } -#elif SANITIZER_PPC64V2 - // Disable ASLR for Linux PPC64LE. - int old_personality = personality(0xffffffff); - if (old_personality != -1 && (old_personality & ADDR_NO_RANDOMIZE) == 0) { - VReport(1, "WARNING: Program is being run with address space layout " - "randomization (ASLR) enabled which prevents the thread and " - "memory sanitizers from working on powerpc64le.\n" - "ASLR will be disabled and the program re-executed.\n"); - CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1); - ReExec(); - } -#else - // Do nothing -#endif -} - -void CheckMPROTECT() { -#if SANITIZER_NETBSD - int mib[3]; - int paxflags; - uptr len = sizeof(paxflags); - - mib[0] = CTL_PROC; - mib[1] = internal_getpid(); - mib[2] = PROC_PID_PAXFLAGS; - - if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) { - Printf("sysctl failed\n"); - Die(); - } - - if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_MPROTECT)) { - Printf("This sanitizer is not compatible with enabled MPROTECT\n"); - Die(); - } -#else - // Do nothing -#endif -} - -void PrintModuleMap() { } - -void CheckNoDeepBind(const char *filename, int flag) { -#ifdef RTLD_DEEPBIND - if (flag & RTLD_DEEPBIND) { - Report( - "You are trying to dlopen a %s shared library with RTLD_DEEPBIND flag" - " which is incompatibe with sanitizer runtime " - "(see https://github.com/google/sanitizers/issues/611 for details" - "). If you want to run %s library under sanitizers please remove " - "RTLD_DEEPBIND from dlopen flags.\n", - filename, filename); - Die(); - } -#endif -} - -uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, - uptr *largest_gap_found, - uptr *max_occupied_addr) { - UNREACHABLE("FindAvailableMemoryRange is not available"); - return 0; -} - -bool GetRandom(void *buffer, uptr length, bool blocking) { - if (!buffer || !length || length > 256) - return false; -#if SANITIZER_USE_GETENTROPY - uptr rnd = getentropy(buffer, length); - int rverrno = 0; - if (internal_iserror(rnd, &rverrno) && rverrno == EFAULT) - return false; - else if (rnd == 0) - return true; -#endif // SANITIZER_USE_GETENTROPY - -#if SANITIZER_USE_GETRANDOM - static atomic_uint8_t skip_getrandom_syscall; - if (!atomic_load_relaxed(&skip_getrandom_syscall)) { - // Up to 256 bytes, getrandom will not be interrupted. - uptr res = internal_syscall(SYSCALL(getrandom), buffer, length, - blocking ? 0 : GRND_NONBLOCK); - int rverrno = 0; - if (internal_iserror(res, &rverrno) && rverrno == ENOSYS) - atomic_store_relaxed(&skip_getrandom_syscall, 1); - else if (res == length) - return true; - } -#endif // SANITIZER_USE_GETRANDOM - // Up to 256 bytes, a read off /dev/urandom will not be interrupted. - // blocking is moot here, O_NONBLOCK has no effect when opening /dev/urandom. - uptr fd = internal_open("/dev/urandom", O_RDONLY); - if (internal_iserror(fd)) - return false; - uptr res = internal_read(fd, buffer, length); - if (internal_iserror(res)) - return false; - internal_close(fd); - return true; -} - -} // namespace __sanitizer - -#endif diff --git a/lib/sanitizer_common/sanitizer_linux.cpp b/lib/sanitizer_common/sanitizer_linux.cpp new file mode 100644 index 000000000000..0b53da6c349f --- /dev/null +++ b/lib/sanitizer_common/sanitizer_linux.cpp @@ -0,0 +1,2141 @@ +//===-- sanitizer_linux.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries and implements linux-specific functions from +// sanitizer_libc.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ + SANITIZER_OPENBSD || SANITIZER_SOLARIS + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_getauxval.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_linux.h" +#include "sanitizer_mutex.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_procmaps.h" + +#if SANITIZER_LINUX +#include +#endif + +// For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat' +// format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To +// access stat from asm/stat.h, without conflicting with definition in +// sys/stat.h, we use this trick. +#if defined(__mips64) +#include +#include +#define stat kernel_stat +#include +#undef stat +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !SANITIZER_SOLARIS +#include +#endif +#include +#include +#include +#include +#include +#if !SANITIZER_OPENBSD +#include +#endif +#if SANITIZER_OPENBSD +#include +#include +#endif +#include + +#if SANITIZER_LINUX +#include +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +#include +#endif + +#if SANITIZER_FREEBSD +#include +#include +#include +extern "C" { +// must be included after and on +// FreeBSD 9.2 and 10.0. +#include +} +#include +#endif // SANITIZER_FREEBSD + +#if SANITIZER_NETBSD +#include // For NAME_MAX +#include +#include +extern struct ps_strings *__ps_strings; +#endif // SANITIZER_NETBSD + +#if SANITIZER_SOLARIS +#include +#include +#define environ _environ +#endif + +extern char **environ; + +#if SANITIZER_LINUX +// +struct kernel_timeval { + long tv_sec; + long tv_usec; +}; + +// is broken on some linux distributions. +const int FUTEX_WAIT = 0; +const int FUTEX_WAKE = 1; +const int FUTEX_PRIVATE_FLAG = 128; +const int FUTEX_WAIT_PRIVATE = FUTEX_WAIT | FUTEX_PRIVATE_FLAG; +const int FUTEX_WAKE_PRIVATE = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; +#endif // SANITIZER_LINUX + +// Are we using 32-bit or 64-bit Linux syscalls? +// x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32 +// but it still needs to use 64-bit syscalls. +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \ + SANITIZER_WORDSIZE == 64) +# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1 +#else +# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0 +#endif + +// Note : FreeBSD had implemented both +// Linux and OpenBSD apis, available from +// future 12.x version most likely +#if SANITIZER_LINUX && defined(__NR_getrandom) +# if !defined(GRND_NONBLOCK) +# define GRND_NONBLOCK 1 +# endif +# define SANITIZER_USE_GETRANDOM 1 +#else +# define SANITIZER_USE_GETRANDOM 0 +#endif // SANITIZER_LINUX && defined(__NR_getrandom) + +#if SANITIZER_OPENBSD +# define SANITIZER_USE_GETENTROPY 1 +#else +# if SANITIZER_FREEBSD && __FreeBSD_version >= 1200000 +# define SANITIZER_USE_GETENTROPY 1 +# else +# define SANITIZER_USE_GETENTROPY 0 +# endif +#endif // SANITIZER_USE_GETENTROPY + +namespace __sanitizer { + +#if SANITIZER_LINUX && defined(__x86_64__) +#include "sanitizer_syscall_linux_x86_64.inc" +#elif SANITIZER_LINUX && defined(__aarch64__) +#include "sanitizer_syscall_linux_aarch64.inc" +#elif SANITIZER_LINUX && defined(__arm__) +#include "sanitizer_syscall_linux_arm.inc" +#else +#include "sanitizer_syscall_generic.inc" +#endif + +// --------------- sanitizer_libc.h +#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD +#if !SANITIZER_S390 && !SANITIZER_OPENBSD +uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, + OFF_T offset) { +#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS + return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd, + offset); +#else + // mmap2 specifies file offset in 4096-byte units. + CHECK(IsAligned(offset, 4096)); + return internal_syscall(SYSCALL(mmap2), addr, length, prot, flags, fd, + offset / 4096); +#endif +} +#endif // !SANITIZER_S390 && !SANITIZER_OPENBSD + +#if !SANITIZER_OPENBSD +uptr internal_munmap(void *addr, uptr length) { + return internal_syscall(SYSCALL(munmap), (uptr)addr, length); +} + +int internal_mprotect(void *addr, uptr length, int prot) { + return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot); +} +#endif + +uptr internal_close(fd_t fd) { + return internal_syscall(SYSCALL(close), fd); +} + +uptr internal_open(const char *filename, int flags) { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags); +#else + return internal_syscall(SYSCALL(open), (uptr)filename, flags); +#endif +} + +uptr internal_open(const char *filename, int flags, u32 mode) { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags, + mode); +#else + return internal_syscall(SYSCALL(open), (uptr)filename, flags, mode); +#endif +} + +uptr internal_read(fd_t fd, void *buf, uptr count) { + sptr res; + HANDLE_EINTR(res, + (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, count)); + return res; +} + +uptr internal_write(fd_t fd, const void *buf, uptr count) { + sptr res; + HANDLE_EINTR(res, + (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf, count)); + return res; +} + +uptr internal_ftruncate(fd_t fd, uptr size) { + sptr res; + HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, + (OFF_T)size)); + return res; +} + +#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX +static void stat64_to_stat(struct stat64 *in, struct stat *out) { + internal_memset(out, 0, sizeof(*out)); + out->st_dev = in->st_dev; + out->st_ino = in->st_ino; + out->st_mode = in->st_mode; + out->st_nlink = in->st_nlink; + out->st_uid = in->st_uid; + out->st_gid = in->st_gid; + out->st_rdev = in->st_rdev; + out->st_size = in->st_size; + out->st_blksize = in->st_blksize; + out->st_blocks = in->st_blocks; + out->st_atime = in->st_atime; + out->st_mtime = in->st_mtime; + out->st_ctime = in->st_ctime; +} +#endif + +#if defined(__mips64) +// Undefine compatibility macros from +// so that they would not clash with the kernel_stat +// st_[a|m|c]time fields +#undef st_atime +#undef st_mtime +#undef st_ctime +#if defined(SANITIZER_ANDROID) +// Bionic sys/stat.h defines additional macros +// for compatibility with the old NDKs and +// they clash with the kernel_stat structure +// st_[a|m|c]time_nsec fields. +#undef st_atime_nsec +#undef st_mtime_nsec +#undef st_ctime_nsec +#endif +static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { + internal_memset(out, 0, sizeof(*out)); + out->st_dev = in->st_dev; + out->st_ino = in->st_ino; + out->st_mode = in->st_mode; + out->st_nlink = in->st_nlink; + out->st_uid = in->st_uid; + out->st_gid = in->st_gid; + out->st_rdev = in->st_rdev; + out->st_size = in->st_size; + out->st_blksize = in->st_blksize; + out->st_blocks = in->st_blocks; +#if defined(__USE_MISC) || \ + defined(__USE_XOPEN2K8) || \ + defined(SANITIZER_ANDROID) + out->st_atim.tv_sec = in->st_atime; + out->st_atim.tv_nsec = in->st_atime_nsec; + out->st_mtim.tv_sec = in->st_mtime; + out->st_mtim.tv_nsec = in->st_mtime_nsec; + out->st_ctim.tv_sec = in->st_ctime; + out->st_ctim.tv_nsec = in->st_ctime_nsec; +#else + out->st_atime = in->st_atime; + out->st_atimensec = in->st_atime_nsec; + out->st_mtime = in->st_mtime; + out->st_mtimensec = in->st_mtime_nsec; + out->st_ctime = in->st_ctime; + out->st_atimensec = in->st_ctime_nsec; +#endif +} +#endif + +uptr internal_stat(const char *path, void *buf) { +#if SANITIZER_FREEBSD || SANITIZER_OPENBSD + return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0); +#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, + 0); +#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS +# if defined(__mips64) + // For mips64, stat syscall fills buffer in the format of kernel_stat + struct kernel_stat kbuf; + int res = internal_syscall(SYSCALL(stat), path, &kbuf); + kernel_stat_to_stat(&kbuf, (struct stat *)buf); + return res; +# else + return internal_syscall(SYSCALL(stat), (uptr)path, (uptr)buf); +# endif +#else + struct stat64 buf64; + int res = internal_syscall(SYSCALL(stat64), path, &buf64); + stat64_to_stat(&buf64, (struct stat *)buf); + return res; +#endif +} + +uptr internal_lstat(const char *path, void *buf) { +#if SANITIZER_FREEBSD || SANITIZER_OPENBSD + return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, + AT_SYMLINK_NOFOLLOW); +#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, + AT_SYMLINK_NOFOLLOW); +#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS +# if SANITIZER_MIPS64 + // For mips64, lstat syscall fills buffer in the format of kernel_stat + struct kernel_stat kbuf; + int res = internal_syscall(SYSCALL(lstat), path, &kbuf); + kernel_stat_to_stat(&kbuf, (struct stat *)buf); + return res; +# else + return internal_syscall(SYSCALL(lstat), (uptr)path, (uptr)buf); +# endif +#else + struct stat64 buf64; + int res = internal_syscall(SYSCALL(lstat64), path, &buf64); + stat64_to_stat(&buf64, (struct stat *)buf); + return res; +#endif +} + +uptr internal_fstat(fd_t fd, void *buf) { +#if SANITIZER_FREEBSD || SANITIZER_OPENBSD || \ + SANITIZER_LINUX_USES_64BIT_SYSCALLS +#if SANITIZER_MIPS64 && !SANITIZER_OPENBSD + // For mips64, fstat syscall fills buffer in the format of kernel_stat + struct kernel_stat kbuf; + int res = internal_syscall(SYSCALL(fstat), fd, &kbuf); + kernel_stat_to_stat(&kbuf, (struct stat *)buf); + return res; +# else + return internal_syscall(SYSCALL(fstat), fd, (uptr)buf); +# endif +#else + struct stat64 buf64; + int res = internal_syscall(SYSCALL(fstat64), fd, &buf64); + stat64_to_stat(&buf64, (struct stat *)buf); + return res; +#endif +} + +uptr internal_filesize(fd_t fd) { + struct stat st; + if (internal_fstat(fd, &st)) + return -1; + return (uptr)st.st_size; +} + +uptr internal_dup(int oldfd) { + return internal_syscall(SYSCALL(dup), oldfd); +} + +uptr internal_dup2(int oldfd, int newfd) { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0); +#else + return internal_syscall(SYSCALL(dup2), oldfd, newfd); +#endif +} + +uptr internal_readlink(const char *path, char *buf, uptr bufsize) { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, + bufsize); +#elif SANITIZER_OPENBSD + return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, + bufsize); +#else + return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize); +#endif +} + +uptr internal_unlink(const char *path) { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD + return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0); +#else + return internal_syscall(SYSCALL(unlink), (uptr)path); +#endif +} + +uptr internal_rename(const char *oldpath, const char *newpath) { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD + return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD, + (uptr)newpath); +#else + return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath); +#endif +} + +uptr internal_sched_yield() { + return internal_syscall(SYSCALL(sched_yield)); +} + +void internal__exit(int exitcode) { +#if SANITIZER_FREEBSD || SANITIZER_OPENBSD + internal_syscall(SYSCALL(exit), exitcode); +#else + internal_syscall(SYSCALL(exit_group), exitcode); +#endif + Die(); // Unreachable. +} + +unsigned int internal_sleep(unsigned int seconds) { + struct timespec ts; + ts.tv_sec = seconds; + ts.tv_nsec = 0; + int res = internal_syscall(SYSCALL(nanosleep), &ts, &ts); + if (res) return ts.tv_sec; + return 0; +} + +uptr internal_execve(const char *filename, char *const argv[], + char *const envp[]) { + return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv, + (uptr)envp); +} +#endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD + +// ----------------- sanitizer_common.h +bool FileExists(const char *filename) { + if (ShouldMockFailureToOpen(filename)) + return false; + struct stat st; +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + if (internal_syscall(SYSCALL(newfstatat), AT_FDCWD, filename, &st, 0)) +#else + if (internal_stat(filename, &st)) +#endif + return false; + // Sanity check: filename is a regular file. + return S_ISREG(st.st_mode); +} + +#if !SANITIZER_NETBSD +tid_t GetTid() { +#if SANITIZER_FREEBSD + long Tid; + thr_self(&Tid); + return Tid; +#elif SANITIZER_OPENBSD + return internal_syscall(SYSCALL(getthrid)); +#elif SANITIZER_SOLARIS + return thr_self(); +#else + return internal_syscall(SYSCALL(gettid)); +#endif +} + +int TgKill(pid_t pid, tid_t tid, int sig) { +#if SANITIZER_LINUX + return internal_syscall(SYSCALL(tgkill), pid, tid, sig); +#elif SANITIZER_FREEBSD + return internal_syscall(SYSCALL(thr_kill2), pid, tid, sig); +#elif SANITIZER_OPENBSD + (void)pid; + return internal_syscall(SYSCALL(thrkill), tid, sig, nullptr); +#elif SANITIZER_SOLARIS + (void)pid; + return thr_kill(tid, sig); +#endif +} +#endif + +#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD +u64 NanoTime() { +#if SANITIZER_FREEBSD || SANITIZER_OPENBSD + timeval tv; +#else + kernel_timeval tv; +#endif + internal_memset(&tv, 0, sizeof(tv)); + internal_syscall(SYSCALL(gettimeofday), &tv, 0); + return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000; +} + +uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { + return internal_syscall(SYSCALL(clock_gettime), clk_id, tp); +} +#endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD + +// Like getenv, but reads env directly from /proc (on Linux) or parses the +// 'environ' array (on some others) and does not use libc. This function +// should be called first inside __asan_init. +const char *GetEnv(const char *name) { +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD || \ + SANITIZER_SOLARIS + if (::environ != 0) { + uptr NameLen = internal_strlen(name); + for (char **Env = ::environ; *Env != 0; Env++) { + if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=') + return (*Env) + NameLen + 1; + } + } + return 0; // Not found. +#elif SANITIZER_LINUX + static char *environ; + static uptr len; + static bool inited; + if (!inited) { + inited = true; + uptr environ_size; + if (!ReadFileToBuffer("/proc/self/environ", &environ, &environ_size, &len)) + environ = nullptr; + } + if (!environ || len == 0) return nullptr; + uptr namelen = internal_strlen(name); + const char *p = environ; + while (*p != '\0') { // will happen at the \0\0 that terminates the buffer + // proc file has the format NAME=value\0NAME=value\0NAME=value\0... + const char* endp = + (char*)internal_memchr(p, '\0', len - (p - environ)); + if (!endp) // this entry isn't NUL terminated + return nullptr; + else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match. + return p + namelen + 1; // point after = + p = endp + 1; + } + return nullptr; // Not found. +#else +#error "Unsupported platform" +#endif +} + +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD +extern "C" { +SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end; +} +#endif + +#if !SANITIZER_GO && !SANITIZER_FREEBSD && !SANITIZER_NETBSD && \ + !SANITIZER_OPENBSD +static void ReadNullSepFileToArray(const char *path, char ***arr, + int arr_size) { + char *buff; + uptr buff_size; + uptr buff_len; + *arr = (char **)MmapOrDie(arr_size * sizeof(char *), "NullSepFileArray"); + if (!ReadFileToBuffer(path, &buff, &buff_size, &buff_len, 1024 * 1024)) { + (*arr)[0] = nullptr; + return; + } + (*arr)[0] = buff; + int count, i; + for (count = 1, i = 1; ; i++) { + if (buff[i] == 0) { + if (buff[i+1] == 0) break; + (*arr)[count] = &buff[i+1]; + CHECK_LE(count, arr_size - 1); // FIXME: make this more flexible. + count++; + } + } + (*arr)[count] = nullptr; +} +#endif + +#if !SANITIZER_OPENBSD +static void GetArgsAndEnv(char ***argv, char ***envp) { +#if SANITIZER_FREEBSD + // On FreeBSD, retrieving the argument and environment arrays is done via the + // kern.ps_strings sysctl, which returns a pointer to a structure containing + // this information. See also . + ps_strings *pss; + uptr sz = sizeof(pss); + if (internal_sysctlbyname("kern.ps_strings", &pss, &sz, NULL, 0) == -1) { + Printf("sysctl kern.ps_strings failed\n"); + Die(); + } + *argv = pss->ps_argvstr; + *envp = pss->ps_envstr; +#elif SANITIZER_NETBSD + *argv = __ps_strings->ps_argvstr; + *envp = __ps_strings->ps_envstr; +#else // SANITIZER_FREEBSD +#if !SANITIZER_GO + if (&__libc_stack_end) { +#endif // !SANITIZER_GO + uptr* stack_end = (uptr*)__libc_stack_end; + int argc = *stack_end; + *argv = (char**)(stack_end + 1); + *envp = (char**)(stack_end + argc + 2); +#if !SANITIZER_GO + } else { + static const int kMaxArgv = 2000, kMaxEnvp = 2000; + ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv); + ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp); + } +#endif // !SANITIZER_GO +#endif // SANITIZER_FREEBSD +} + +char **GetArgv() { + char **argv, **envp; + GetArgsAndEnv(&argv, &envp); + return argv; +} + +char **GetEnviron() { + char **argv, **envp; + GetArgsAndEnv(&argv, &envp); + return envp; +} + +#endif // !SANITIZER_OPENBSD + +#if !SANITIZER_SOLARIS +enum MutexState { + MtxUnlocked = 0, + MtxLocked = 1, + MtxSleeping = 2 +}; + +BlockingMutex::BlockingMutex() { + internal_memset(this, 0, sizeof(*this)); +} + +void BlockingMutex::Lock() { + CHECK_EQ(owner_, 0); + atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); + if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked) + return; + while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) { +#if SANITIZER_FREEBSD + _umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0); +#elif SANITIZER_NETBSD + sched_yield(); /* No userspace futex-like synchronization */ +#else + internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT_PRIVATE, MtxSleeping, + 0, 0, 0); +#endif + } +} + +void BlockingMutex::Unlock() { + atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); + u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release); + CHECK_NE(v, MtxUnlocked); + if (v == MtxSleeping) { +#if SANITIZER_FREEBSD + _umtx_op(m, UMTX_OP_WAKE, 1, 0, 0); +#elif SANITIZER_NETBSD + /* No userspace futex-like synchronization */ +#else + internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE_PRIVATE, 1, 0, 0, 0); +#endif + } +} + +void BlockingMutex::CheckLocked() { + atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); + CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed)); +} +#endif // !SANITIZER_SOLARIS + +// ----------------- sanitizer_linux.h +// The actual size of this structure is specified by d_reclen. +// Note that getdents64 uses a different structure format. We only provide the +// 32-bit syscall here. +#if SANITIZER_NETBSD +// Not used +#elif SANITIZER_OPENBSD +// struct dirent is different for Linux and us. At this moment, we use only +// d_fileno (Linux call this d_ino), d_reclen, and d_name. +struct linux_dirent { + u64 d_ino; // d_fileno + u16 d_reclen; + u16 d_namlen; // not used + u8 d_type; // not used + char d_name[NAME_MAX + 1]; +}; +#else +struct linux_dirent { +#if SANITIZER_X32 || defined(__aarch64__) + u64 d_ino; + u64 d_off; +#else + unsigned long d_ino; + unsigned long d_off; +#endif + unsigned short d_reclen; +#ifdef __aarch64__ + unsigned char d_type; +#endif + char d_name[256]; +}; +#endif + +#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD +// Syscall wrappers. +uptr internal_ptrace(int request, int pid, void *addr, void *data) { + return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr, + (uptr)data); +} + +uptr internal_waitpid(int pid, int *status, int options) { + return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options, + 0 /* rusage */); +} + +uptr internal_getpid() { + return internal_syscall(SYSCALL(getpid)); +} + +uptr internal_getppid() { + return internal_syscall(SYSCALL(getppid)); +} + +uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { +#if SANITIZER_FREEBSD + return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL); +#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count); +#else + return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count); +#endif +} + +uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { + return internal_syscall(SYSCALL(lseek), fd, offset, whence); +} + +#if SANITIZER_LINUX +uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { + return internal_syscall(SYSCALL(prctl), option, arg2, arg3, arg4, arg5); +} +#endif + +uptr internal_sigaltstack(const void *ss, void *oss) { + return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss); +} + +int internal_fork() { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(clone), SIGCHLD, 0); +#else + return internal_syscall(SYSCALL(fork)); +#endif +} + +#if SANITIZER_FREEBSD || SANITIZER_OPENBSD +int internal_sysctl(const int *name, unsigned int namelen, void *oldp, + uptr *oldlenp, const void *newp, uptr newlen) { +#if SANITIZER_OPENBSD + return sysctl(name, namelen, oldp, (size_t *)oldlenp, (void *)newp, + (size_t)newlen); +#else + return internal_syscall(SYSCALL(__sysctl), name, namelen, oldp, + (size_t *)oldlenp, newp, (size_t)newlen); +#endif +} + +#if SANITIZER_FREEBSD +int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, + const void *newp, uptr newlen) { + static decltype(sysctlbyname) *real = nullptr; + if (!real) + real = (decltype(sysctlbyname) *)dlsym(RTLD_NEXT, "sysctlbyname"); + CHECK(real); + return real(sname, oldp, (size_t *)oldlenp, newp, (size_t)newlen); +} +#endif +#endif + +#if SANITIZER_LINUX +#define SA_RESTORER 0x04000000 +// Doesn't set sa_restorer if the caller did not set it, so use with caution +//(see below). +int internal_sigaction_norestorer(int signum, const void *act, void *oldact) { + __sanitizer_kernel_sigaction_t k_act, k_oldact; + internal_memset(&k_act, 0, sizeof(__sanitizer_kernel_sigaction_t)); + internal_memset(&k_oldact, 0, sizeof(__sanitizer_kernel_sigaction_t)); + const __sanitizer_sigaction *u_act = (const __sanitizer_sigaction *)act; + __sanitizer_sigaction *u_oldact = (__sanitizer_sigaction *)oldact; + if (u_act) { + k_act.handler = u_act->handler; + k_act.sigaction = u_act->sigaction; + internal_memcpy(&k_act.sa_mask, &u_act->sa_mask, + sizeof(__sanitizer_kernel_sigset_t)); + // Without SA_RESTORER kernel ignores the calls (probably returns EINVAL). + k_act.sa_flags = u_act->sa_flags | SA_RESTORER; + // FIXME: most often sa_restorer is unset, however the kernel requires it + // to point to a valid signal restorer that calls the rt_sigreturn syscall. + // If sa_restorer passed to the kernel is NULL, the program may crash upon + // signal delivery or fail to unwind the stack in the signal handler. + // libc implementation of sigaction() passes its own restorer to + // rt_sigaction, so we need to do the same (we'll need to reimplement the + // restorers; for x86_64 the restorer address can be obtained from + // oldact->sa_restorer upon a call to sigaction(xxx, NULL, oldact). +#if !SANITIZER_ANDROID || !SANITIZER_MIPS32 + k_act.sa_restorer = u_act->sa_restorer; +#endif + } + + uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum, + (uptr)(u_act ? &k_act : nullptr), + (uptr)(u_oldact ? &k_oldact : nullptr), + (uptr)sizeof(__sanitizer_kernel_sigset_t)); + + if ((result == 0) && u_oldact) { + u_oldact->handler = k_oldact.handler; + u_oldact->sigaction = k_oldact.sigaction; + internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask, + sizeof(__sanitizer_kernel_sigset_t)); + u_oldact->sa_flags = k_oldact.sa_flags; +#if !SANITIZER_ANDROID || !SANITIZER_MIPS32 + u_oldact->sa_restorer = k_oldact.sa_restorer; +#endif + } + return result; +} +#endif // SANITIZER_LINUX + +uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset) { +#if SANITIZER_FREEBSD || SANITIZER_OPENBSD + return internal_syscall(SYSCALL(sigprocmask), how, set, oldset); +#else + __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; + __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset; + return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how, + (uptr)&k_set->sig[0], (uptr)&k_oldset->sig[0], + sizeof(__sanitizer_kernel_sigset_t)); +#endif +} + +void internal_sigfillset(__sanitizer_sigset_t *set) { + internal_memset(set, 0xff, sizeof(*set)); +} + +void internal_sigemptyset(__sanitizer_sigset_t *set) { + internal_memset(set, 0, sizeof(*set)); +} + +#if SANITIZER_LINUX +void internal_sigdelset(__sanitizer_sigset_t *set, int signum) { + signum -= 1; + CHECK_GE(signum, 0); + CHECK_LT(signum, sizeof(*set) * 8); + __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; + const uptr idx = signum / (sizeof(k_set->sig[0]) * 8); + const uptr bit = signum % (sizeof(k_set->sig[0]) * 8); + k_set->sig[idx] &= ~(1 << bit); +} + +bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { + signum -= 1; + CHECK_GE(signum, 0); + CHECK_LT(signum, sizeof(*set) * 8); + __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; + const uptr idx = signum / (sizeof(k_set->sig[0]) * 8); + const uptr bit = signum % (sizeof(k_set->sig[0]) * 8); + return k_set->sig[idx] & (1 << bit); +} +#elif SANITIZER_FREEBSD +void internal_sigdelset(__sanitizer_sigset_t *set, int signum) { + sigset_t *rset = reinterpret_cast(set); + sigdelset(rset, signum); +} + +bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { + sigset_t *rset = reinterpret_cast(set); + return sigismember(rset, signum); +} +#endif +#endif // !SANITIZER_SOLARIS + +#if !SANITIZER_NETBSD +// ThreadLister implementation. +ThreadLister::ThreadLister(pid_t pid) : pid_(pid), buffer_(4096) { + char task_directory_path[80]; + internal_snprintf(task_directory_path, sizeof(task_directory_path), + "/proc/%d/task/", pid); + descriptor_ = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY); + if (internal_iserror(descriptor_)) { + Report("Can't open /proc/%d/task for reading.\n", pid); + } +} + +ThreadLister::Result ThreadLister::ListThreads( + InternalMmapVector *threads) { + if (internal_iserror(descriptor_)) + return Error; + internal_lseek(descriptor_, 0, SEEK_SET); + threads->clear(); + + Result result = Ok; + for (bool first_read = true;; first_read = false) { + // Resize to max capacity if it was downsized by IsAlive. + buffer_.resize(buffer_.capacity()); + CHECK_GE(buffer_.size(), 4096); + uptr read = internal_getdents( + descriptor_, (struct linux_dirent *)buffer_.data(), buffer_.size()); + if (!read) + return result; + if (internal_iserror(read)) { + Report("Can't read directory entries from /proc/%d/task.\n", pid_); + return Error; + } + + for (uptr begin = (uptr)buffer_.data(), end = begin + read; begin < end;) { + struct linux_dirent *entry = (struct linux_dirent *)begin; + begin += entry->d_reclen; + if (entry->d_ino == 1) { + // Inode 1 is for bad blocks and also can be a reason for early return. + // Should be emitted if kernel tried to output terminating thread. + // See proc_task_readdir implementation in Linux. + result = Incomplete; + } + if (entry->d_ino && *entry->d_name >= '0' && *entry->d_name <= '9') + threads->push_back(internal_atoll(entry->d_name)); + } + + // Now we are going to detect short-read or early EOF. In such cases Linux + // can return inconsistent list with missing alive threads. + // Code will just remember that the list can be incomplete but it will + // continue reads to return as much as possible. + if (!first_read) { + // The first one was a short-read by definition. + result = Incomplete; + } else if (read > buffer_.size() - 1024) { + // Read was close to the buffer size. So double the size and assume the + // worst. + buffer_.resize(buffer_.size() * 2); + result = Incomplete; + } else if (!threads->empty() && !IsAlive(threads->back())) { + // Maybe Linux early returned from read on terminated thread (!pid_alive) + // and failed to restore read position. + // See next_tid and proc_task_instantiate in Linux. + result = Incomplete; + } + } +} + +bool ThreadLister::IsAlive(int tid) { + // /proc/%d/task/%d/status uses same call to detect alive threads as + // proc_task_readdir. See task_state implementation in Linux. + char path[80]; + internal_snprintf(path, sizeof(path), "/proc/%d/task/%d/status", pid_, tid); + if (!ReadFileToVector(path, &buffer_) || buffer_.empty()) + return false; + buffer_.push_back(0); + static const char kPrefix[] = "\nPPid:"; + const char *field = internal_strstr(buffer_.data(), kPrefix); + if (!field) + return false; + field += internal_strlen(kPrefix); + return (int)internal_atoll(field) != 0; +} + +ThreadLister::~ThreadLister() { + if (!internal_iserror(descriptor_)) + internal_close(descriptor_); +} +#endif + +#if SANITIZER_WORDSIZE == 32 +// Take care of unusable kernel area in top gigabyte. +static uptr GetKernelAreaSize() { +#if SANITIZER_LINUX && !SANITIZER_X32 + const uptr gbyte = 1UL << 30; + + // Firstly check if there are writable segments + // mapped to top gigabyte (e.g. stack). + MemoryMappingLayout proc_maps(/*cache_enabled*/true); + if (proc_maps.Error()) + return 0; + MemoryMappedSegment segment; + while (proc_maps.Next(&segment)) { + if ((segment.end >= 3 * gbyte) && segment.IsWritable()) return 0; + } + +#if !SANITIZER_ANDROID + // Even if nothing is mapped, top Gb may still be accessible + // if we are running on 64-bit kernel. + // Uname may report misleading results if personality type + // is modified (e.g. under schroot) so check this as well. + struct utsname uname_info; + int pers = personality(0xffffffffUL); + if (!(pers & PER_MASK) + && uname(&uname_info) == 0 + && internal_strstr(uname_info.machine, "64")) + return 0; +#endif // SANITIZER_ANDROID + + // Top gigabyte is reserved for kernel. + return gbyte; +#else + return 0; +#endif // SANITIZER_LINUX && !SANITIZER_X32 +} +#endif // SANITIZER_WORDSIZE == 32 + +uptr GetMaxVirtualAddress() { +#if (SANITIZER_NETBSD || SANITIZER_OPENBSD) && defined(__x86_64__) + return 0x7f7ffffff000ULL; // (0x00007f8000000000 - PAGE_SIZE) +#elif SANITIZER_WORDSIZE == 64 +# if defined(__powerpc64__) || defined(__aarch64__) + // On PowerPC64 we have two different address space layouts: 44- and 46-bit. + // We somehow need to figure out which one we are using now and choose + // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL. + // Note that with 'ulimit -s unlimited' the stack is moved away from the top + // of the address space, so simply checking the stack address is not enough. + // This should (does) work for both PowerPC64 Endian modes. + // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit. + return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1; +# elif defined(__mips64) + return (1ULL << 40) - 1; // 0x000000ffffffffffUL; +# elif defined(__s390x__) + return (1ULL << 53) - 1; // 0x001fffffffffffffUL; +#elif defined(__sparc__) + return ~(uptr)0; +# else + return (1ULL << 47) - 1; // 0x00007fffffffffffUL; +# endif +#else // SANITIZER_WORDSIZE == 32 +# if defined(__s390__) + return (1ULL << 31) - 1; // 0x7fffffff; +# else + return (1ULL << 32) - 1; // 0xffffffff; +# endif +#endif // SANITIZER_WORDSIZE +} + +uptr GetMaxUserVirtualAddress() { + uptr addr = GetMaxVirtualAddress(); +#if SANITIZER_WORDSIZE == 32 && !defined(__s390__) + if (!common_flags()->full_address_space) + addr -= GetKernelAreaSize(); + CHECK_LT(reinterpret_cast(&addr), addr); +#endif + return addr; +} + +#if !SANITIZER_ANDROID +uptr GetPageSize() { +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) + return EXEC_PAGESIZE; +#elif SANITIZER_FREEBSD || SANITIZER_NETBSD +// Use sysctl as sysconf can trigger interceptors internally. + int pz = 0; + uptr pzl = sizeof(pz); + int mib[2] = {CTL_HW, HW_PAGESIZE}; + int rv = internal_sysctl(mib, 2, &pz, &pzl, nullptr, 0); + CHECK_EQ(rv, 0); + return (uptr)pz; +#elif SANITIZER_USE_GETAUXVAL + return getauxval(AT_PAGESZ); +#else + return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy. +#endif +} +#endif // !SANITIZER_ANDROID + +#if !SANITIZER_OPENBSD +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { +#if SANITIZER_SOLARIS + const char *default_module_name = getexecname(); + CHECK_NE(default_module_name, NULL); + return internal_snprintf(buf, buf_len, "%s", default_module_name); +#else +#if SANITIZER_FREEBSD || SANITIZER_NETBSD +#if SANITIZER_FREEBSD + const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; +#else + const int Mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; +#endif + const char *default_module_name = "kern.proc.pathname"; + uptr Size = buf_len; + bool IsErr = + (internal_sysctl(Mib, ARRAY_SIZE(Mib), buf, &Size, NULL, 0) != 0); + int readlink_error = IsErr ? errno : 0; + uptr module_name_len = Size; +#else + const char *default_module_name = "/proc/self/exe"; + uptr module_name_len = internal_readlink( + default_module_name, buf, buf_len); + int readlink_error; + bool IsErr = internal_iserror(module_name_len, &readlink_error); +#endif // SANITIZER_SOLARIS + if (IsErr) { + // We can't read binary name for some reason, assume it's unknown. + Report("WARNING: reading executable name failed with errno %d, " + "some stack frames may not be symbolized\n", readlink_error); + module_name_len = internal_snprintf(buf, buf_len, "%s", + default_module_name); + CHECK_LT(module_name_len, buf_len); + } + return module_name_len; +#endif +} +#endif // !SANITIZER_OPENBSD + +uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { +#if SANITIZER_LINUX + char *tmpbuf; + uptr tmpsize; + uptr tmplen; + if (ReadFileToBuffer("/proc/self/cmdline", &tmpbuf, &tmpsize, &tmplen, + 1024 * 1024)) { + internal_strncpy(buf, tmpbuf, buf_len); + UnmapOrDie(tmpbuf, tmpsize); + return internal_strlen(buf); + } +#endif + return ReadBinaryName(buf, buf_len); +} + +// Match full names of the form /path/to/base_name{-,.}* +bool LibraryNameIs(const char *full_name, const char *base_name) { + const char *name = full_name; + // Strip path. + while (*name != '\0') name++; + while (name > full_name && *name != '/') name--; + if (*name == '/') name++; + uptr base_name_length = internal_strlen(base_name); + if (internal_strncmp(name, base_name, base_name_length)) return false; + return (name[base_name_length] == '-' || name[base_name_length] == '.'); +} + +#if !SANITIZER_ANDROID +// Call cb for each region mapped by map. +void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) { + CHECK_NE(map, nullptr); +#if !SANITIZER_FREEBSD && !SANITIZER_OPENBSD + typedef ElfW(Phdr) Elf_Phdr; + typedef ElfW(Ehdr) Elf_Ehdr; +#endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD + char *base = (char *)map->l_addr; + Elf_Ehdr *ehdr = (Elf_Ehdr *)base; + char *phdrs = base + ehdr->e_phoff; + char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize; + + // Find the segment with the minimum base so we can "relocate" the p_vaddr + // fields. Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC + // objects have a non-zero base. + uptr preferred_base = (uptr)-1; + for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { + Elf_Phdr *phdr = (Elf_Phdr *)iter; + if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr) + preferred_base = (uptr)phdr->p_vaddr; + } + + // Compute the delta from the real base to get a relocation delta. + sptr delta = (uptr)base - preferred_base; + // Now we can figure out what the loader really mapped. + for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { + Elf_Phdr *phdr = (Elf_Phdr *)iter; + if (phdr->p_type == PT_LOAD) { + uptr seg_start = phdr->p_vaddr + delta; + uptr seg_end = seg_start + phdr->p_memsz; + // None of these values are aligned. We consider the ragged edges of the + // load command as defined, since they are mapped from the file. + seg_start = RoundDownTo(seg_start, GetPageSizeCached()); + seg_end = RoundUpTo(seg_end, GetPageSizeCached()); + cb((void *)seg_start, seg_end - seg_start); + } + } +} +#endif + +#if defined(__x86_64__) && SANITIZER_LINUX +// We cannot use glibc's clone wrapper, because it messes with the child +// task's TLS. It writes the PID and TID of the child task to its thread +// descriptor, but in our case the child task shares the thread descriptor with +// the parent (because we don't know how to allocate a new thread +// descriptor to keep glibc happy). So the stock version of clone(), when +// used with CLONE_VM, would end up corrupting the parent's thread descriptor. +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + long long res; + if (!fn || !child_stack) + return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); + child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); + ((unsigned long long *)child_stack)[0] = (uptr)fn; + ((unsigned long long *)child_stack)[1] = (uptr)arg; + register void *r8 __asm__("r8") = newtls; + register int *r10 __asm__("r10") = child_tidptr; + __asm__ __volatile__( + /* %rax = syscall(%rax = SYSCALL(clone), + * %rdi = flags, + * %rsi = child_stack, + * %rdx = parent_tidptr, + * %r8 = new_tls, + * %r10 = child_tidptr) + */ + "syscall\n" + + /* if (%rax != 0) + * return; + */ + "testq %%rax,%%rax\n" + "jnz 1f\n" + + /* In the child. Terminate unwind chain. */ + // XXX: We should also terminate the CFI unwind chain + // here. Unfortunately clang 3.2 doesn't support the + // necessary CFI directives, so we skip that part. + "xorq %%rbp,%%rbp\n" + + /* Call "fn(arg)". */ + "popq %%rax\n" + "popq %%rdi\n" + "call *%%rax\n" + + /* Call _exit(%rax). */ + "movq %%rax,%%rdi\n" + "movq %2,%%rax\n" + "syscall\n" + + /* Return to parent. */ + "1:\n" + : "=a" (res) + : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), + "S"(child_stack), + "D"(flags), + "d"(parent_tidptr), + "r"(r8), + "r"(r10) + : "memory", "r11", "rcx"); + return res; +} +#elif defined(__mips__) +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + long long res; + if (!fn || !child_stack) + return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); + child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); + ((unsigned long long *)child_stack)[0] = (uptr)fn; + ((unsigned long long *)child_stack)[1] = (uptr)arg; + register void *a3 __asm__("$7") = newtls; + register int *a4 __asm__("$8") = child_tidptr; + // We don't have proper CFI directives here because it requires alot of code + // for very marginal benefits. + __asm__ __volatile__( + /* $v0 = syscall($v0 = __NR_clone, + * $a0 = flags, + * $a1 = child_stack, + * $a2 = parent_tidptr, + * $a3 = new_tls, + * $a4 = child_tidptr) + */ + ".cprestore 16;\n" + "move $4,%1;\n" + "move $5,%2;\n" + "move $6,%3;\n" + "move $7,%4;\n" + /* Store the fifth argument on stack + * if we are using 32-bit abi. + */ +#if SANITIZER_WORDSIZE == 32 + "lw %5,16($29);\n" +#else + "move $8,%5;\n" +#endif + "li $2,%6;\n" + "syscall;\n" + + /* if ($v0 != 0) + * return; + */ + "bnez $2,1f;\n" + + /* Call "fn(arg)". */ +#if SANITIZER_WORDSIZE == 32 +#ifdef __BIG_ENDIAN__ + "lw $25,4($29);\n" + "lw $4,12($29);\n" +#else + "lw $25,0($29);\n" + "lw $4,8($29);\n" +#endif +#else + "ld $25,0($29);\n" + "ld $4,8($29);\n" +#endif + "jal $25;\n" + + /* Call _exit($v0). */ + "move $4,$2;\n" + "li $2,%7;\n" + "syscall;\n" + + /* Return to parent. */ + "1:\n" + : "=r" (res) + : "r"(flags), + "r"(child_stack), + "r"(parent_tidptr), + "r"(a3), + "r"(a4), + "i"(__NR_clone), + "i"(__NR_exit) + : "memory", "$29" ); + return res; +} +#elif defined(__aarch64__) +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + long long res; + if (!fn || !child_stack) + return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); + child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); + ((unsigned long long *)child_stack)[0] = (uptr)fn; + ((unsigned long long *)child_stack)[1] = (uptr)arg; + + register int (*__fn)(void *) __asm__("x0") = fn; + register void *__stack __asm__("x1") = child_stack; + register int __flags __asm__("x2") = flags; + register void *__arg __asm__("x3") = arg; + register int *__ptid __asm__("x4") = parent_tidptr; + register void *__tls __asm__("x5") = newtls; + register int *__ctid __asm__("x6") = child_tidptr; + + __asm__ __volatile__( + "mov x0,x2\n" /* flags */ + "mov x2,x4\n" /* ptid */ + "mov x3,x5\n" /* tls */ + "mov x4,x6\n" /* ctid */ + "mov x8,%9\n" /* clone */ + + "svc 0x0\n" + + /* if (%r0 != 0) + * return %r0; + */ + "cmp x0, #0\n" + "bne 1f\n" + + /* In the child, now. Call "fn(arg)". */ + "ldp x1, x0, [sp], #16\n" + "blr x1\n" + + /* Call _exit(%r0). */ + "mov x8, %10\n" + "svc 0x0\n" + "1:\n" + + : "=r" (res) + : "i"(-EINVAL), + "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg), + "r"(__ptid), "r"(__tls), "r"(__ctid), + "i"(__NR_clone), "i"(__NR_exit) + : "x30", "memory"); + return res; +} +#elif defined(__powerpc64__) +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + long long res; +// Stack frame structure. +#if SANITIZER_PPC64V1 +// Back chain == 0 (SP + 112) +// Frame (112 bytes): +// Parameter save area (SP + 48), 8 doublewords +// TOC save area (SP + 40) +// Link editor doubleword (SP + 32) +// Compiler doubleword (SP + 24) +// LR save area (SP + 16) +// CR save area (SP + 8) +// Back chain (SP + 0) +# define FRAME_SIZE 112 +# define FRAME_TOC_SAVE_OFFSET 40 +#elif SANITIZER_PPC64V2 +// Back chain == 0 (SP + 32) +// Frame (32 bytes): +// TOC save area (SP + 24) +// LR save area (SP + 16) +// CR save area (SP + 8) +// Back chain (SP + 0) +# define FRAME_SIZE 32 +# define FRAME_TOC_SAVE_OFFSET 24 +#else +# error "Unsupported PPC64 ABI" +#endif + if (!fn || !child_stack) + return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); + + register int (*__fn)(void *) __asm__("r3") = fn; + register void *__cstack __asm__("r4") = child_stack; + register int __flags __asm__("r5") = flags; + register void *__arg __asm__("r6") = arg; + register int *__ptidptr __asm__("r7") = parent_tidptr; + register void *__newtls __asm__("r8") = newtls; + register int *__ctidptr __asm__("r9") = child_tidptr; + + __asm__ __volatile__( + /* fn and arg are saved across the syscall */ + "mr 28, %5\n\t" + "mr 27, %8\n\t" + + /* syscall + r0 == __NR_clone + r3 == flags + r4 == child_stack + r5 == parent_tidptr + r6 == newtls + r7 == child_tidptr */ + "mr 3, %7\n\t" + "mr 5, %9\n\t" + "mr 6, %10\n\t" + "mr 7, %11\n\t" + "li 0, %3\n\t" + "sc\n\t" + + /* Test if syscall was successful */ + "cmpdi cr1, 3, 0\n\t" + "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t" + "bne- cr1, 1f\n\t" + + /* Set up stack frame */ + "li 29, 0\n\t" + "stdu 29, -8(1)\n\t" + "stdu 1, -%12(1)\n\t" + /* Do the function call */ + "std 2, %13(1)\n\t" +#if SANITIZER_PPC64V1 + "ld 0, 0(28)\n\t" + "ld 2, 8(28)\n\t" + "mtctr 0\n\t" +#elif SANITIZER_PPC64V2 + "mr 12, 28\n\t" + "mtctr 12\n\t" +#else +# error "Unsupported PPC64 ABI" +#endif + "mr 3, 27\n\t" + "bctrl\n\t" + "ld 2, %13(1)\n\t" + + /* Call _exit(r3) */ + "li 0, %4\n\t" + "sc\n\t" + + /* Return to parent */ + "1:\n\t" + "mr %0, 3\n\t" + : "=r" (res) + : "0" (-1), + "i" (EINVAL), + "i" (__NR_clone), + "i" (__NR_exit), + "r" (__fn), + "r" (__cstack), + "r" (__flags), + "r" (__arg), + "r" (__ptidptr), + "r" (__newtls), + "r" (__ctidptr), + "i" (FRAME_SIZE), + "i" (FRAME_TOC_SAVE_OFFSET) + : "cr0", "cr1", "memory", "ctr", "r0", "r27", "r28", "r29"); + return res; +} +#elif defined(__i386__) && SANITIZER_LINUX +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + int res; + if (!fn || !child_stack) + return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); + child_stack = (char *)child_stack - 7 * sizeof(unsigned int); + ((unsigned int *)child_stack)[0] = (uptr)flags; + ((unsigned int *)child_stack)[1] = (uptr)0; + ((unsigned int *)child_stack)[2] = (uptr)fn; + ((unsigned int *)child_stack)[3] = (uptr)arg; + __asm__ __volatile__( + /* %eax = syscall(%eax = SYSCALL(clone), + * %ebx = flags, + * %ecx = child_stack, + * %edx = parent_tidptr, + * %esi = new_tls, + * %edi = child_tidptr) + */ + + /* Obtain flags */ + "movl (%%ecx), %%ebx\n" + /* Do the system call */ + "pushl %%ebx\n" + "pushl %%esi\n" + "pushl %%edi\n" + /* Remember the flag value. */ + "movl %%ebx, (%%ecx)\n" + "int $0x80\n" + "popl %%edi\n" + "popl %%esi\n" + "popl %%ebx\n" + + /* if (%eax != 0) + * return; + */ + + "test %%eax,%%eax\n" + "jnz 1f\n" + + /* terminate the stack frame */ + "xorl %%ebp,%%ebp\n" + /* Call FN. */ + "call *%%ebx\n" +#ifdef PIC + "call here\n" + "here:\n" + "popl %%ebx\n" + "addl $_GLOBAL_OFFSET_TABLE_+[.-here], %%ebx\n" +#endif + /* Call exit */ + "movl %%eax, %%ebx\n" + "movl %2, %%eax\n" + "int $0x80\n" + "1:\n" + : "=a" (res) + : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), + "c"(child_stack), + "d"(parent_tidptr), + "S"(newtls), + "D"(child_tidptr) + : "memory"); + return res; +} +#elif defined(__arm__) && SANITIZER_LINUX +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + unsigned int res; + if (!fn || !child_stack) + return -EINVAL; + child_stack = (char *)child_stack - 2 * sizeof(unsigned int); + ((unsigned int *)child_stack)[0] = (uptr)fn; + ((unsigned int *)child_stack)[1] = (uptr)arg; + register int r0 __asm__("r0") = flags; + register void *r1 __asm__("r1") = child_stack; + register int *r2 __asm__("r2") = parent_tidptr; + register void *r3 __asm__("r3") = newtls; + register int *r4 __asm__("r4") = child_tidptr; + register int r7 __asm__("r7") = __NR_clone; + +#if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__) +# define ARCH_HAS_BX +#endif +#if __ARM_ARCH > 4 +# define ARCH_HAS_BLX +#endif + +#ifdef ARCH_HAS_BX +# ifdef ARCH_HAS_BLX +# define BLX(R) "blx " #R "\n" +# else +# define BLX(R) "mov lr, pc; bx " #R "\n" +# endif +#else +# define BLX(R) "mov lr, pc; mov pc," #R "\n" +#endif + + __asm__ __volatile__( + /* %r0 = syscall(%r7 = SYSCALL(clone), + * %r0 = flags, + * %r1 = child_stack, + * %r2 = parent_tidptr, + * %r3 = new_tls, + * %r4 = child_tidptr) + */ + + /* Do the system call */ + "swi 0x0\n" + + /* if (%r0 != 0) + * return %r0; + */ + "cmp r0, #0\n" + "bne 1f\n" + + /* In the child, now. Call "fn(arg)". */ + "ldr r0, [sp, #4]\n" + "ldr ip, [sp], #8\n" + BLX(ip) + /* Call _exit(%r0). */ + "mov r7, %7\n" + "swi 0x0\n" + "1:\n" + "mov %0, r0\n" + : "=r"(res) + : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7), + "i"(__NR_exit) + : "memory"); + return res; +} +#endif // defined(__x86_64__) && SANITIZER_LINUX + +#if SANITIZER_ANDROID +#if __ANDROID_API__ < 21 +extern "C" __attribute__((weak)) int dl_iterate_phdr( + int (*)(struct dl_phdr_info *, size_t, void *), void *); +#endif + +static int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size, + void *data) { + // Any name starting with "lib" indicates a bug in L where library base names + // are returned instead of paths. + if (info->dlpi_name && info->dlpi_name[0] == 'l' && + info->dlpi_name[1] == 'i' && info->dlpi_name[2] == 'b') { + *(bool *)data = true; + return 1; + } + return 0; +} + +static atomic_uint32_t android_api_level; + +static AndroidApiLevel AndroidDetectApiLevelStatic() { +#if __ANDROID_API__ <= 19 + return ANDROID_KITKAT; +#elif __ANDROID_API__ <= 22 + return ANDROID_LOLLIPOP_MR1; +#else + return ANDROID_POST_LOLLIPOP; +#endif +} + +static AndroidApiLevel AndroidDetectApiLevel() { + if (!&dl_iterate_phdr) + return ANDROID_KITKAT; // K or lower + bool base_name_seen = false; + dl_iterate_phdr(dl_iterate_phdr_test_cb, &base_name_seen); + if (base_name_seen) + return ANDROID_LOLLIPOP_MR1; // L MR1 + return ANDROID_POST_LOLLIPOP; // post-L + // Plain L (API level 21) is completely broken wrt ASan and not very + // interesting to detect. +} + +extern "C" __attribute__((weak)) void* _DYNAMIC; + +AndroidApiLevel AndroidGetApiLevel() { + AndroidApiLevel level = + (AndroidApiLevel)atomic_load(&android_api_level, memory_order_relaxed); + if (level) return level; + level = &_DYNAMIC == nullptr ? AndroidDetectApiLevelStatic() + : AndroidDetectApiLevel(); + atomic_store(&android_api_level, level, memory_order_relaxed); + return level; +} + +#endif + +static HandleSignalMode GetHandleSignalModeImpl(int signum) { + switch (signum) { + case SIGABRT: + return common_flags()->handle_abort; + case SIGILL: + return common_flags()->handle_sigill; + case SIGTRAP: + return common_flags()->handle_sigtrap; + case SIGFPE: + return common_flags()->handle_sigfpe; + case SIGSEGV: + return common_flags()->handle_segv; + case SIGBUS: + return common_flags()->handle_sigbus; + } + return kHandleSignalNo; +} + +HandleSignalMode GetHandleSignalMode(int signum) { + HandleSignalMode result = GetHandleSignalModeImpl(signum); + if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler) + return kHandleSignalExclusive; + return result; +} + +#if !SANITIZER_GO +void *internal_start_thread(void(*func)(void *arg), void *arg) { + // Start the thread with signals blocked, otherwise it can steal user signals. + __sanitizer_sigset_t set, old; + internal_sigfillset(&set); +#if SANITIZER_LINUX && !SANITIZER_ANDROID + // Glibc uses SIGSETXID signal during setuid call. If this signal is blocked + // on any thread, setuid call hangs (see test/tsan/setuid.c). + internal_sigdelset(&set, 33); +#endif + internal_sigprocmask(SIG_SETMASK, &set, &old); + void *th; + real_pthread_create(&th, nullptr, (void*(*)(void *arg))func, arg); + internal_sigprocmask(SIG_SETMASK, &old, nullptr); + return th; +} + +void internal_join_thread(void *th) { + real_pthread_join(th, nullptr); +} +#else +void *internal_start_thread(void (*func)(void *), void *arg) { return 0; } + +void internal_join_thread(void *th) {} +#endif + +#if defined(__aarch64__) +// Android headers in the older NDK releases miss this definition. +struct __sanitizer_esr_context { + struct _aarch64_ctx head; + uint64_t esr; +}; + +static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) { + static const u32 kEsrMagic = 0x45535201; + u8 *aux = ucontext->uc_mcontext.__reserved; + while (true) { + _aarch64_ctx *ctx = (_aarch64_ctx *)aux; + if (ctx->size == 0) break; + if (ctx->magic == kEsrMagic) { + *esr = ((__sanitizer_esr_context *)ctx)->esr; + return true; + } + aux += ctx->size; + } + return false; +} +#endif + +#if SANITIZER_OPENBSD +using Context = sigcontext; +#else +using Context = ucontext_t; +#endif + +SignalContext::WriteFlag SignalContext::GetWriteFlag() const { + Context *ucontext = (Context *)context; +#if defined(__x86_64__) || defined(__i386__) + static const uptr PF_WRITE = 1U << 1; +#if SANITIZER_FREEBSD + uptr err = ucontext->uc_mcontext.mc_err; +#elif SANITIZER_NETBSD + uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR]; +#elif SANITIZER_OPENBSD + uptr err = ucontext->sc_err; +#elif SANITIZER_SOLARIS && defined(__i386__) + const int Err = 13; + uptr err = ucontext->uc_mcontext.gregs[Err]; +#else + uptr err = ucontext->uc_mcontext.gregs[REG_ERR]; +#endif // SANITIZER_FREEBSD + return err & PF_WRITE ? WRITE : READ; +#elif defined(__mips__) + uint32_t *exception_source; + uint32_t faulty_instruction; + uint32_t op_code; + + exception_source = (uint32_t *)ucontext->uc_mcontext.pc; + faulty_instruction = (uint32_t)(*exception_source); + + op_code = (faulty_instruction >> 26) & 0x3f; + + // FIXME: Add support for FPU, microMIPS, DSP, MSA memory instructions. + switch (op_code) { + case 0x28: // sb + case 0x29: // sh + case 0x2b: // sw + case 0x3f: // sd +#if __mips_isa_rev < 6 + case 0x2c: // sdl + case 0x2d: // sdr + case 0x2a: // swl + case 0x2e: // swr +#endif + return SignalContext::WRITE; + + case 0x20: // lb + case 0x24: // lbu + case 0x21: // lh + case 0x25: // lhu + case 0x23: // lw + case 0x27: // lwu + case 0x37: // ld +#if __mips_isa_rev < 6 + case 0x1a: // ldl + case 0x1b: // ldr + case 0x22: // lwl + case 0x26: // lwr +#endif + return SignalContext::READ; +#if __mips_isa_rev == 6 + case 0x3b: // pcrel + op_code = (faulty_instruction >> 19) & 0x3; + switch (op_code) { + case 0x1: // lwpc + case 0x2: // lwupc + return SignalContext::READ; + } +#endif + } + return SignalContext::UNKNOWN; +#elif defined(__arm__) + static const uptr FSR_WRITE = 1U << 11; + uptr fsr = ucontext->uc_mcontext.error_code; + return fsr & FSR_WRITE ? WRITE : READ; +#elif defined(__aarch64__) + static const u64 ESR_ELx_WNR = 1U << 6; + u64 esr; + if (!Aarch64GetESR(ucontext, &esr)) return UNKNOWN; + return esr & ESR_ELx_WNR ? WRITE : READ; +#elif defined(__sparc__) + // Decode the instruction to determine the access type. + // From OpenSolaris $SRC/uts/sun4/os/trap.c (get_accesstype). +#if SANITIZER_SOLARIS + uptr pc = ucontext->uc_mcontext.gregs[REG_PC]; +#else + // Historical BSDism here. + struct sigcontext *scontext = (struct sigcontext *)context; +#if defined(__arch64__) + uptr pc = scontext->sigc_regs.tpc; +#else + uptr pc = scontext->si_regs.pc; +#endif +#endif + u32 instr = *(u32 *)pc; + return (instr >> 21) & 1 ? WRITE: READ; +#else + (void)ucontext; + return UNKNOWN; // FIXME: Implement. +#endif +} + +bool SignalContext::IsTrueFaultingAddress() const { + auto si = static_cast(siginfo); + // SIGSEGV signals without a true fault address have si_code set to 128. + return si->si_signo == SIGSEGV && si->si_code != 128; +} + +void SignalContext::DumpAllRegisters(void *context) { + // FIXME: Implement this. +} + +static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { +#if SANITIZER_NETBSD + // This covers all NetBSD architectures + ucontext_t *ucontext = (ucontext_t *)context; + *pc = _UC_MACHINE_PC(ucontext); + *bp = _UC_MACHINE_FP(ucontext); + *sp = _UC_MACHINE_SP(ucontext); +#elif defined(__arm__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.arm_pc; + *bp = ucontext->uc_mcontext.arm_fp; + *sp = ucontext->uc_mcontext.arm_sp; +#elif defined(__aarch64__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.pc; + *bp = ucontext->uc_mcontext.regs[29]; + *sp = ucontext->uc_mcontext.sp; +#elif defined(__hppa__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.sc_iaoq[0]; + /* GCC uses %r3 whenever a frame pointer is needed. */ + *bp = ucontext->uc_mcontext.sc_gr[3]; + *sp = ucontext->uc_mcontext.sc_gr[30]; +#elif defined(__x86_64__) +# if SANITIZER_FREEBSD + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.mc_rip; + *bp = ucontext->uc_mcontext.mc_rbp; + *sp = ucontext->uc_mcontext.mc_rsp; +#elif SANITIZER_OPENBSD + sigcontext *ucontext = (sigcontext *)context; + *pc = ucontext->sc_rip; + *bp = ucontext->sc_rbp; + *sp = ucontext->sc_rsp; +# else + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.gregs[REG_RIP]; + *bp = ucontext->uc_mcontext.gregs[REG_RBP]; + *sp = ucontext->uc_mcontext.gregs[REG_RSP]; +# endif +#elif defined(__i386__) +# if SANITIZER_FREEBSD + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.mc_eip; + *bp = ucontext->uc_mcontext.mc_ebp; + *sp = ucontext->uc_mcontext.mc_esp; +#elif SANITIZER_OPENBSD + sigcontext *ucontext = (sigcontext *)context; + *pc = ucontext->sc_eip; + *bp = ucontext->sc_ebp; + *sp = ucontext->sc_esp; +# else + ucontext_t *ucontext = (ucontext_t*)context; +# if SANITIZER_SOLARIS + /* Use the numeric values: the symbolic ones are undefined by llvm + include/llvm/Support/Solaris.h. */ +# ifndef REG_EIP +# define REG_EIP 14 // REG_PC +# endif +# ifndef REG_EBP +# define REG_EBP 6 // REG_FP +# endif +# ifndef REG_ESP +# define REG_ESP 17 // REG_SP +# endif +# endif + *pc = ucontext->uc_mcontext.gregs[REG_EIP]; + *bp = ucontext->uc_mcontext.gregs[REG_EBP]; + *sp = ucontext->uc_mcontext.gregs[REG_ESP]; +# endif +#elif defined(__powerpc__) || defined(__powerpc64__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.regs->nip; + *sp = ucontext->uc_mcontext.regs->gpr[PT_R1]; + // The powerpc{,64}-linux ABIs do not specify r31 as the frame + // pointer, but GCC always uses r31 when we need a frame pointer. + *bp = ucontext->uc_mcontext.regs->gpr[PT_R31]; +#elif defined(__sparc__) +#if defined(__arch64__) || defined(__sparcv9) +#define STACK_BIAS 2047 +#else +#define STACK_BIAS 0 +# endif +# if SANITIZER_SOLARIS + ucontext_t *ucontext = (ucontext_t *)context; + *pc = ucontext->uc_mcontext.gregs[REG_PC]; + *sp = ucontext->uc_mcontext.gregs[REG_O6] + STACK_BIAS; +#else + // Historical BSDism here. + struct sigcontext *scontext = (struct sigcontext *)context; +#if defined(__arch64__) + *pc = scontext->sigc_regs.tpc; + *sp = scontext->sigc_regs.u_regs[14] + STACK_BIAS; +#else + *pc = scontext->si_regs.pc; + *sp = scontext->si_regs.u_regs[14]; +#endif +# endif + *bp = (uptr)((uhwptr *)*sp)[14] + STACK_BIAS; +#elif defined(__mips__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.pc; + *bp = ucontext->uc_mcontext.gregs[30]; + *sp = ucontext->uc_mcontext.gregs[29]; +#elif defined(__s390__) + ucontext_t *ucontext = (ucontext_t*)context; +# if defined(__s390x__) + *pc = ucontext->uc_mcontext.psw.addr; +# else + *pc = ucontext->uc_mcontext.psw.addr & 0x7fffffff; +# endif + *bp = ucontext->uc_mcontext.gregs[11]; + *sp = ucontext->uc_mcontext.gregs[15]; +#else +# error "Unsupported arch" +#endif +} + +void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } + +void InitializePlatformEarly() { + // Do nothing. +} + +void MaybeReexec() { + // No need to re-exec on Linux. +} + +void CheckASLR() { +#if SANITIZER_NETBSD + int mib[3]; + int paxflags; + uptr len = sizeof(paxflags); + + mib[0] = CTL_PROC; + mib[1] = internal_getpid(); + mib[2] = PROC_PID_PAXFLAGS; + + if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) { + Printf("sysctl failed\n"); + Die(); + } + + if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) { + Printf("This sanitizer is not compatible with enabled ASLR\n"); + Die(); + } +#elif SANITIZER_PPC64V2 + // Disable ASLR for Linux PPC64LE. + int old_personality = personality(0xffffffff); + if (old_personality != -1 && (old_personality & ADDR_NO_RANDOMIZE) == 0) { + VReport(1, "WARNING: Program is being run with address space layout " + "randomization (ASLR) enabled which prevents the thread and " + "memory sanitizers from working on powerpc64le.\n" + "ASLR will be disabled and the program re-executed.\n"); + CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1); + ReExec(); + } +#elif SANITIZER_FREEBSD + int aslr_pie; + uptr len = sizeof(aslr_pie); +#if SANITIZER_WORDSIZE == 64 + if (UNLIKELY(internal_sysctlbyname("kern.elf64.aslr.pie_enable", + &aslr_pie, &len, NULL, 0) == -1)) { + // We're making things less 'dramatic' here since + // the OID is not necessarily guaranteed to be here + // just yet regarding FreeBSD release + return; + } + + if (aslr_pie > 0) { + Printf("This sanitizer is not compatible with enabled ASLR " + "and binaries compiled with PIE\n"); + Die(); + } +#endif + // there might be 32 bits compat for 64 bits + if (UNLIKELY(internal_sysctlbyname("kern.elf32.aslr.pie_enable", + &aslr_pie, &len, NULL, 0) == -1)) { + return; + } + + if (aslr_pie > 0) { + Printf("This sanitizer is not compatible with enabled ASLR " + "and binaries compiled with PIE\n"); + Die(); + } +#else + // Do nothing +#endif +} + +void CheckMPROTECT() { +#if SANITIZER_NETBSD + int mib[3]; + int paxflags; + uptr len = sizeof(paxflags); + + mib[0] = CTL_PROC; + mib[1] = internal_getpid(); + mib[2] = PROC_PID_PAXFLAGS; + + if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) { + Printf("sysctl failed\n"); + Die(); + } + + if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_MPROTECT)) { + Printf("This sanitizer is not compatible with enabled MPROTECT\n"); + Die(); + } +#else + // Do nothing +#endif +} + +void PrintModuleMap() { } + +void CheckNoDeepBind(const char *filename, int flag) { +#ifdef RTLD_DEEPBIND + if (flag & RTLD_DEEPBIND) { + Report( + "You are trying to dlopen a %s shared library with RTLD_DEEPBIND flag" + " which is incompatibe with sanitizer runtime " + "(see https://github.com/google/sanitizers/issues/611 for details" + "). If you want to run %s library under sanitizers please remove " + "RTLD_DEEPBIND from dlopen flags.\n", + filename, filename); + Die(); + } +#endif +} + +uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, + uptr *largest_gap_found, + uptr *max_occupied_addr) { + UNREACHABLE("FindAvailableMemoryRange is not available"); + return 0; +} + +bool GetRandom(void *buffer, uptr length, bool blocking) { + if (!buffer || !length || length > 256) + return false; +#if SANITIZER_USE_GETENTROPY + uptr rnd = getentropy(buffer, length); + int rverrno = 0; + if (internal_iserror(rnd, &rverrno) && rverrno == EFAULT) + return false; + else if (rnd == 0) + return true; +#endif // SANITIZER_USE_GETENTROPY + +#if SANITIZER_USE_GETRANDOM + static atomic_uint8_t skip_getrandom_syscall; + if (!atomic_load_relaxed(&skip_getrandom_syscall)) { + // Up to 256 bytes, getrandom will not be interrupted. + uptr res = internal_syscall(SYSCALL(getrandom), buffer, length, + blocking ? 0 : GRND_NONBLOCK); + int rverrno = 0; + if (internal_iserror(res, &rverrno) && rverrno == ENOSYS) + atomic_store_relaxed(&skip_getrandom_syscall, 1); + else if (res == length) + return true; + } +#endif // SANITIZER_USE_GETRANDOM + // Up to 256 bytes, a read off /dev/urandom will not be interrupted. + // blocking is moot here, O_NONBLOCK has no effect when opening /dev/urandom. + uptr fd = internal_open("/dev/urandom", O_RDONLY); + if (internal_iserror(fd)) + return false; + uptr res = internal_read(fd, buffer, length); + if (internal_iserror(res)) + return false; + internal_close(fd); + return true; +} + +} // namespace __sanitizer + +#endif diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc deleted file mode 100644 index 0608898a1464..000000000000 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ /dev/null @@ -1,850 +0,0 @@ -//===-- sanitizer_linux_libcdep.cc ----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries and implements linux-specific functions from -// sanitizer_libc.h. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS - -#include "sanitizer_allocator_internal.h" -#include "sanitizer_atomic.h" -#include "sanitizer_common.h" -#include "sanitizer_file.h" -#include "sanitizer_flags.h" -#include "sanitizer_freebsd.h" -#include "sanitizer_getauxval.h" -#include "sanitizer_linux.h" -#include "sanitizer_placement_new.h" -#include "sanitizer_procmaps.h" - -#include // for dlsym() -#include -#include -#include -#include -#include - -#if SANITIZER_FREEBSD -#include -#include -#include -#define pthread_getattr_np pthread_attr_get_np -#endif - -#if SANITIZER_OPENBSD -#include -#include -#endif - -#if SANITIZER_NETBSD -#include -#include -#endif - -#if SANITIZER_SOLARIS -#include -#include -#endif - -#if SANITIZER_ANDROID -#include -#if !defined(CPU_COUNT) && !defined(__aarch64__) -#include -#include -struct __sanitizer::linux_dirent { - long d_ino; - off_t d_off; - unsigned short d_reclen; - char d_name[]; -}; -#endif -#endif - -#if !SANITIZER_ANDROID -#include -#include -#endif - -namespace __sanitizer { - -SANITIZER_WEAK_ATTRIBUTE int -real_sigaction(int signum, const void *act, void *oldact); - -int internal_sigaction(int signum, const void *act, void *oldact) { -#if !SANITIZER_GO - if (&real_sigaction) - return real_sigaction(signum, act, oldact); -#endif - return sigaction(signum, (const struct sigaction *)act, - (struct sigaction *)oldact); -} - -void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, - uptr *stack_bottom) { - CHECK(stack_top); - CHECK(stack_bottom); - if (at_initialization) { - // This is the main thread. Libpthread may not be initialized yet. - struct rlimit rl; - CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0); - - // Find the mapping that contains a stack variable. - MemoryMappingLayout proc_maps(/*cache_enabled*/true); - if (proc_maps.Error()) { - *stack_top = *stack_bottom = 0; - return; - } - MemoryMappedSegment segment; - uptr prev_end = 0; - while (proc_maps.Next(&segment)) { - if ((uptr)&rl < segment.end) break; - prev_end = segment.end; - } - CHECK((uptr)&rl >= segment.start && (uptr)&rl < segment.end); - - // Get stacksize from rlimit, but clip it so that it does not overlap - // with other mappings. - uptr stacksize = rl.rlim_cur; - if (stacksize > segment.end - prev_end) stacksize = segment.end - prev_end; - // When running with unlimited stack size, we still want to set some limit. - // The unlimited stack size is caused by 'ulimit -s unlimited'. - // Also, for some reason, GNU make spawns subprocesses with unlimited stack. - if (stacksize > kMaxThreadStackSize) - stacksize = kMaxThreadStackSize; - *stack_top = segment.end; - *stack_bottom = segment.end - stacksize; - return; - } - uptr stacksize = 0; - void *stackaddr = nullptr; -#if SANITIZER_SOLARIS - stack_t ss; - CHECK_EQ(thr_stksegment(&ss), 0); - stacksize = ss.ss_size; - stackaddr = (char *)ss.ss_sp - stacksize; -#elif SANITIZER_OPENBSD - stack_t sattr; - CHECK_EQ(pthread_stackseg_np(pthread_self(), &sattr), 0); - stackaddr = sattr.ss_sp; - stacksize = sattr.ss_size; -#else // !SANITIZER_SOLARIS - pthread_attr_t attr; - pthread_attr_init(&attr); - CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); - my_pthread_attr_getstack(&attr, &stackaddr, &stacksize); - pthread_attr_destroy(&attr); -#endif // SANITIZER_SOLARIS - - *stack_top = (uptr)stackaddr + stacksize; - *stack_bottom = (uptr)stackaddr; -} - -#if !SANITIZER_GO -bool SetEnv(const char *name, const char *value) { - void *f = dlsym(RTLD_NEXT, "setenv"); - if (!f) - return false; - typedef int(*setenv_ft)(const char *name, const char *value, int overwrite); - setenv_ft setenv_f; - CHECK_EQ(sizeof(setenv_f), sizeof(f)); - internal_memcpy(&setenv_f, &f, sizeof(f)); - return setenv_f(name, value, 1) == 0; -} -#endif - -__attribute__((unused)) static bool GetLibcVersion(int *major, int *minor, - int *patch) { -#ifdef _CS_GNU_LIBC_VERSION - char buf[64]; - uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf)); - if (len >= sizeof(buf)) - return false; - buf[len] = 0; - static const char kGLibC[] = "glibc "; - if (internal_strncmp(buf, kGLibC, sizeof(kGLibC) - 1) != 0) - return false; - const char *p = buf + sizeof(kGLibC) - 1; - *major = internal_simple_strtoll(p, &p, 10); - *minor = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0; - *patch = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0; - return true; -#else - return false; -#endif -} - -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \ - !SANITIZER_NETBSD && !SANITIZER_OPENBSD && !SANITIZER_SOLARIS -static uptr g_tls_size; - -#ifdef __i386__ -# ifndef __GLIBC_PREREQ -# define CHECK_GET_TLS_STATIC_INFO_VERSION 1 -# else -# define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27)) -# endif -#else -# define CHECK_GET_TLS_STATIC_INFO_VERSION 0 -#endif - -#if CHECK_GET_TLS_STATIC_INFO_VERSION -# define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall)) -#else -# define DL_INTERNAL_FUNCTION -#endif - -namespace { -struct GetTlsStaticInfoCall { - typedef void (*get_tls_func)(size_t*, size_t*); -}; -struct GetTlsStaticInfoRegparmCall { - typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION; -}; - -template -void CallGetTls(void* ptr, size_t* size, size_t* align) { - typename T::get_tls_func get_tls; - CHECK_EQ(sizeof(get_tls), sizeof(ptr)); - internal_memcpy(&get_tls, &ptr, sizeof(ptr)); - CHECK_NE(get_tls, 0); - get_tls(size, align); -} - -bool CmpLibcVersion(int major, int minor, int patch) { - int ma; - int mi; - int pa; - if (!GetLibcVersion(&ma, &mi, &pa)) - return false; - if (ma > major) - return true; - if (ma < major) - return false; - if (mi > minor) - return true; - if (mi < minor) - return false; - return pa >= patch; -} - -} // namespace - -void InitTlsSize() { - // all current supported platforms have 16 bytes stack alignment - const size_t kStackAlign = 16; - void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info"); - size_t tls_size = 0; - size_t tls_align = 0; - // On i?86, _dl_get_tls_static_info used to be internal_function, i.e. - // __attribute__((regparm(3), stdcall)) before glibc 2.27 and is normal - // function in 2.27 and later. - if (CHECK_GET_TLS_STATIC_INFO_VERSION && !CmpLibcVersion(2, 27, 0)) - CallGetTls(get_tls_static_info_ptr, - &tls_size, &tls_align); - else - CallGetTls(get_tls_static_info_ptr, - &tls_size, &tls_align); - if (tls_align < kStackAlign) - tls_align = kStackAlign; - g_tls_size = RoundUpTo(tls_size, tls_align); -} -#else -void InitTlsSize() { } -#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && - // !SANITIZER_NETBSD && !SANITIZER_SOLARIS - -#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \ - defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \ - defined(__arm__)) && \ - SANITIZER_LINUX && !SANITIZER_ANDROID -// sizeof(struct pthread) from glibc. -static atomic_uintptr_t thread_descriptor_size; - -uptr ThreadDescriptorSize() { - uptr val = atomic_load_relaxed(&thread_descriptor_size); - if (val) - return val; -#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) - int major; - int minor; - int patch; - if (GetLibcVersion(&major, &minor, &patch) && major == 2) { - /* sizeof(struct pthread) values from various glibc versions. */ - if (SANITIZER_X32) - val = 1728; // Assume only one particular version for x32. - // For ARM sizeof(struct pthread) changed in Glibc 2.23. - else if (SANITIZER_ARM) - val = minor <= 22 ? 1120 : 1216; - else if (minor <= 3) - val = FIRST_32_SECOND_64(1104, 1696); - else if (minor == 4) - val = FIRST_32_SECOND_64(1120, 1728); - else if (minor == 5) - val = FIRST_32_SECOND_64(1136, 1728); - else if (minor <= 9) - val = FIRST_32_SECOND_64(1136, 1712); - else if (minor == 10) - val = FIRST_32_SECOND_64(1168, 1776); - else if (minor == 11 || (minor == 12 && patch == 1)) - val = FIRST_32_SECOND_64(1168, 2288); - else if (minor <= 14) - val = FIRST_32_SECOND_64(1168, 2304); - else - val = FIRST_32_SECOND_64(1216, 2304); - } -#elif defined(__mips__) - // TODO(sagarthakur): add more values as per different glibc versions. - val = FIRST_32_SECOND_64(1152, 1776); -#elif defined(__aarch64__) - // The sizeof (struct pthread) is the same from GLIBC 2.17 to 2.22. - val = 1776; -#elif defined(__powerpc64__) - val = 1776; // from glibc.ppc64le 2.20-8.fc21 -#elif defined(__s390__) - val = FIRST_32_SECOND_64(1152, 1776); // valid for glibc 2.22 -#endif - if (val) - atomic_store_relaxed(&thread_descriptor_size, val); - return val; -} - -// The offset at which pointer to self is located in the thread descriptor. -const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16); - -uptr ThreadSelfOffset() { - return kThreadSelfOffset; -} - -#if defined(__mips__) || defined(__powerpc64__) -// TlsPreTcbSize includes size of struct pthread_descr and size of tcb -// head structure. It lies before the static tls blocks. -static uptr TlsPreTcbSize() { -# if defined(__mips__) - const uptr kTcbHead = 16; // sizeof (tcbhead_t) -# elif defined(__powerpc64__) - const uptr kTcbHead = 88; // sizeof (tcbhead_t) -# endif - const uptr kTlsAlign = 16; - const uptr kTlsPreTcbSize = - RoundUpTo(ThreadDescriptorSize() + kTcbHead, kTlsAlign); - return kTlsPreTcbSize; -} -#endif - -uptr ThreadSelf() { - uptr descr_addr; -# if defined(__i386__) - asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset)); -# elif defined(__x86_64__) - asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset)); -# elif defined(__mips__) - // MIPS uses TLS variant I. The thread pointer (in hardware register $29) - // points to the end of the TCB + 0x7000. The pthread_descr structure is - // immediately in front of the TCB. TlsPreTcbSize() includes the size of the - // TCB and the size of pthread_descr. - const uptr kTlsTcbOffset = 0x7000; - uptr thread_pointer; - asm volatile(".set push;\ - .set mips64r2;\ - rdhwr %0,$29;\ - .set pop" : "=r" (thread_pointer)); - descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize(); -# elif defined(__aarch64__) || defined(__arm__) - descr_addr = reinterpret_cast(__builtin_thread_pointer()) - - ThreadDescriptorSize(); -# elif defined(__s390__) - descr_addr = reinterpret_cast(__builtin_thread_pointer()); -# elif defined(__powerpc64__) - // PPC64LE uses TLS variant I. The thread pointer (in GPR 13) - // points to the end of the TCB + 0x7000. The pthread_descr structure is - // immediately in front of the TCB. TlsPreTcbSize() includes the size of the - // TCB and the size of pthread_descr. - const uptr kTlsTcbOffset = 0x7000; - uptr thread_pointer; - asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset)); - descr_addr = thread_pointer - TlsPreTcbSize(); -# else -# error "unsupported CPU arch" -# endif - return descr_addr; -} -#endif // (x86_64 || i386 || MIPS) && SANITIZER_LINUX - -#if SANITIZER_FREEBSD -static void **ThreadSelfSegbase() { - void **segbase = 0; -# if defined(__i386__) - // sysarch(I386_GET_GSBASE, segbase); - __asm __volatile("mov %%gs:0, %0" : "=r" (segbase)); -# elif defined(__x86_64__) - // sysarch(AMD64_GET_FSBASE, segbase); - __asm __volatile("movq %%fs:0, %0" : "=r" (segbase)); -# else -# error "unsupported CPU arch" -# endif - return segbase; -} - -uptr ThreadSelf() { - return (uptr)ThreadSelfSegbase()[2]; -} -#endif // SANITIZER_FREEBSD - -#if SANITIZER_NETBSD -static struct tls_tcb * ThreadSelfTlsTcb() { - struct tls_tcb * tcb; -# ifdef __HAVE___LWP_GETTCB_FAST - tcb = (struct tls_tcb *)__lwp_gettcb_fast(); -# elif defined(__HAVE___LWP_GETPRIVATE_FAST) - tcb = (struct tls_tcb *)__lwp_getprivate_fast(); -# endif - return tcb; -} - -uptr ThreadSelf() { - return (uptr)ThreadSelfTlsTcb()->tcb_pthread; -} - -int GetSizeFromHdr(struct dl_phdr_info *info, size_t size, void *data) { - const Elf_Phdr *hdr = info->dlpi_phdr; - const Elf_Phdr *last_hdr = hdr + info->dlpi_phnum; - - for (; hdr != last_hdr; ++hdr) { - if (hdr->p_type == PT_TLS && info->dlpi_tls_modid == 1) { - *(uptr*)data = hdr->p_memsz; - break; - } - } - return 0; -} -#endif // SANITIZER_NETBSD - -#if !SANITIZER_GO -static void GetTls(uptr *addr, uptr *size) { -#if SANITIZER_LINUX && !SANITIZER_ANDROID -# if defined(__x86_64__) || defined(__i386__) || defined(__s390__) - *addr = ThreadSelf(); - *size = GetTlsSize(); - *addr -= *size; - *addr += ThreadDescriptorSize(); -# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) \ - || defined(__arm__) - *addr = ThreadSelf(); - *size = GetTlsSize(); -# else - *addr = 0; - *size = 0; -# endif -#elif SANITIZER_FREEBSD - void** segbase = ThreadSelfSegbase(); - *addr = 0; - *size = 0; - if (segbase != 0) { - // tcbalign = 16 - // tls_size = round(tls_static_space, tcbalign); - // dtv = segbase[1]; - // dtv[2] = segbase - tls_static_space; - void **dtv = (void**) segbase[1]; - *addr = (uptr) dtv[2]; - *size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]); - } -#elif SANITIZER_NETBSD - struct tls_tcb * const tcb = ThreadSelfTlsTcb(); - *addr = 0; - *size = 0; - if (tcb != 0) { - // Find size (p_memsz) of dlpi_tls_modid 1 (TLS block of the main program). - // ld.elf_so hardcodes the index 1. - dl_iterate_phdr(GetSizeFromHdr, size); - - if (*size != 0) { - // The block has been found and tcb_dtv[1] contains the base address - *addr = (uptr)tcb->tcb_dtv[1]; - } - } -#elif SANITIZER_OPENBSD - *addr = 0; - *size = 0; -#elif SANITIZER_ANDROID - *addr = 0; - *size = 0; -#elif SANITIZER_SOLARIS - // FIXME - *addr = 0; - *size = 0; -#else -# error "Unknown OS" -#endif -} -#endif - -#if !SANITIZER_GO -uptr GetTlsSize() { -#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS - uptr addr, size; - GetTls(&addr, &size); - return size; -#elif defined(__mips__) || defined(__powerpc64__) - return RoundUpTo(g_tls_size + TlsPreTcbSize(), 16); -#else - return g_tls_size; -#endif -} -#endif - -void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, - uptr *tls_addr, uptr *tls_size) { -#if SANITIZER_GO - // Stub implementation for Go. - *stk_addr = *stk_size = *tls_addr = *tls_size = 0; -#else - GetTls(tls_addr, tls_size); - - uptr stack_top, stack_bottom; - GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); - *stk_addr = stack_bottom; - *stk_size = stack_top - stack_bottom; - - if (!main) { - // If stack and tls intersect, make them non-intersecting. - if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) { - CHECK_GT(*tls_addr + *tls_size, *stk_addr); - CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size); - *stk_size -= *tls_size; - *tls_addr = *stk_addr + *stk_size; - } - } -#endif -} - -#if !SANITIZER_FREEBSD && !SANITIZER_OPENBSD -typedef ElfW(Phdr) Elf_Phdr; -#elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2 -#define Elf_Phdr XElf32_Phdr -#define dl_phdr_info xdl_phdr_info -#define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b)) -#endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD - -struct DlIteratePhdrData { - InternalMmapVectorNoCtor *modules; - bool first; -}; - -static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) { - DlIteratePhdrData *data = (DlIteratePhdrData*)arg; - InternalScopedString module_name(kMaxPathLength); - if (data->first) { - data->first = false; - // First module is the binary itself. - ReadBinaryNameCached(module_name.data(), module_name.size()); - } else if (info->dlpi_name) { - module_name.append("%s", info->dlpi_name); - } - if (module_name[0] == '\0') - return 0; - LoadedModule cur_module; - cur_module.set(module_name.data(), info->dlpi_addr); - for (int i = 0; i < (int)info->dlpi_phnum; i++) { - const Elf_Phdr *phdr = &info->dlpi_phdr[i]; - if (phdr->p_type == PT_LOAD) { - uptr cur_beg = info->dlpi_addr + phdr->p_vaddr; - uptr cur_end = cur_beg + phdr->p_memsz; - bool executable = phdr->p_flags & PF_X; - bool writable = phdr->p_flags & PF_W; - cur_module.addAddressRange(cur_beg, cur_end, executable, - writable); - } - } - data->modules->push_back(cur_module); - return 0; -} - -#if SANITIZER_ANDROID && __ANDROID_API__ < 21 -extern "C" __attribute__((weak)) int dl_iterate_phdr( - int (*)(struct dl_phdr_info *, size_t, void *), void *); -#endif - -static bool requiresProcmaps() { -#if SANITIZER_ANDROID && __ANDROID_API__ <= 22 - // Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken. - // The runtime check allows the same library to work with - // both K and L (and future) Android releases. - return AndroidGetApiLevel() <= ANDROID_LOLLIPOP_MR1; -#else - return false; -#endif -} - -static void procmapsInit(InternalMmapVectorNoCtor *modules) { - MemoryMappingLayout memory_mapping(/*cache_enabled*/true); - memory_mapping.DumpListOfModules(modules); -} - -void ListOfModules::init() { - clearOrInit(); - if (requiresProcmaps()) { - procmapsInit(&modules_); - } else { - DlIteratePhdrData data = {&modules_, true}; - dl_iterate_phdr(dl_iterate_phdr_cb, &data); - } -} - -// When a custom loader is used, dl_iterate_phdr may not contain the full -// list of modules. Allow callers to fall back to using procmaps. -void ListOfModules::fallbackInit() { - if (!requiresProcmaps()) { - clearOrInit(); - procmapsInit(&modules_); - } else { - clear(); - } -} - -// getrusage does not give us the current RSS, only the max RSS. -// Still, this is better than nothing if /proc/self/statm is not available -// for some reason, e.g. due to a sandbox. -static uptr GetRSSFromGetrusage() { - struct rusage usage; - if (getrusage(RUSAGE_SELF, &usage)) // Failed, probably due to a sandbox. - return 0; - return usage.ru_maxrss << 10; // ru_maxrss is in Kb. -} - -uptr GetRSS() { - if (!common_flags()->can_use_proc_maps_statm) - return GetRSSFromGetrusage(); - fd_t fd = OpenFile("/proc/self/statm", RdOnly); - if (fd == kInvalidFd) - return GetRSSFromGetrusage(); - char buf[64]; - uptr len = internal_read(fd, buf, sizeof(buf) - 1); - internal_close(fd); - if ((sptr)len <= 0) - return 0; - buf[len] = 0; - // The format of the file is: - // 1084 89 69 11 0 79 0 - // We need the second number which is RSS in pages. - char *pos = buf; - // Skip the first number. - while (*pos >= '0' && *pos <= '9') - pos++; - // Skip whitespaces. - while (!(*pos >= '0' && *pos <= '9') && *pos != 0) - pos++; - // Read the number. - uptr rss = 0; - while (*pos >= '0' && *pos <= '9') - rss = rss * 10 + *pos++ - '0'; - return rss * GetPageSizeCached(); -} - -// sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used on most platforms as -// they allocate memory. -u32 GetNumberOfCPUs() { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD - u32 ncpu; - int req[2]; - uptr len = sizeof(ncpu); - req[0] = CTL_HW; - req[1] = HW_NCPU; - CHECK_EQ(internal_sysctl(req, 2, &ncpu, &len, NULL, 0), 0); - return ncpu; -#elif SANITIZER_ANDROID && !defined(CPU_COUNT) && !defined(__aarch64__) - // Fall back to /sys/devices/system/cpu on Android when cpu_set_t doesn't - // exist in sched.h. That is the case for toolchains generated with older - // NDKs. - // This code doesn't work on AArch64 because internal_getdents makes use of - // the 64bit getdents syscall, but cpu_set_t seems to always exist on AArch64. - uptr fd = internal_open("/sys/devices/system/cpu", O_RDONLY | O_DIRECTORY); - if (internal_iserror(fd)) - return 0; - InternalMmapVector buffer(4096); - uptr bytes_read = buffer.size(); - uptr n_cpus = 0; - u8 *d_type; - struct linux_dirent *entry = (struct linux_dirent *)&buffer[bytes_read]; - while (true) { - if ((u8 *)entry >= &buffer[bytes_read]) { - bytes_read = internal_getdents(fd, (struct linux_dirent *)buffer.data(), - buffer.size()); - if (internal_iserror(bytes_read) || !bytes_read) - break; - entry = (struct linux_dirent *)buffer.data(); - } - d_type = (u8 *)entry + entry->d_reclen - 1; - if (d_type >= &buffer[bytes_read] || - (u8 *)&entry->d_name[3] >= &buffer[bytes_read]) - break; - if (entry->d_ino != 0 && *d_type == DT_DIR) { - if (entry->d_name[0] == 'c' && entry->d_name[1] == 'p' && - entry->d_name[2] == 'u' && - entry->d_name[3] >= '0' && entry->d_name[3] <= '9') - n_cpus++; - } - entry = (struct linux_dirent *)(((u8 *)entry) + entry->d_reclen); - } - internal_close(fd); - return n_cpus; -#elif SANITIZER_SOLARIS - return sysconf(_SC_NPROCESSORS_ONLN); -#else - cpu_set_t CPUs; - CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0); - return CPU_COUNT(&CPUs); -#endif -} - -#if SANITIZER_LINUX - -# if SANITIZER_ANDROID -static atomic_uint8_t android_log_initialized; - -void AndroidLogInit() { - openlog(GetProcessName(), 0, LOG_USER); - atomic_store(&android_log_initialized, 1, memory_order_release); -} - -static bool ShouldLogAfterPrintf() { - return atomic_load(&android_log_initialized, memory_order_acquire); -} - -extern "C" SANITIZER_WEAK_ATTRIBUTE -int async_safe_write_log(int pri, const char* tag, const char* msg); -extern "C" SANITIZER_WEAK_ATTRIBUTE -int __android_log_write(int prio, const char* tag, const char* msg); - -// ANDROID_LOG_INFO is 4, but can't be resolved at runtime. -#define SANITIZER_ANDROID_LOG_INFO 4 - -// async_safe_write_log is a new public version of __libc_write_log that is -// used behind syslog. It is preferable to syslog as it will not do any dynamic -// memory allocation or formatting. -// If the function is not available, syslog is preferred for L+ (it was broken -// pre-L) as __android_log_write triggers a racey behavior with the strncpy -// interceptor. Fallback to __android_log_write pre-L. -void WriteOneLineToSyslog(const char *s) { - if (&async_safe_write_log) { - async_safe_write_log(SANITIZER_ANDROID_LOG_INFO, GetProcessName(), s); - } else if (AndroidGetApiLevel() > ANDROID_KITKAT) { - syslog(LOG_INFO, "%s", s); - } else { - CHECK(&__android_log_write); - __android_log_write(SANITIZER_ANDROID_LOG_INFO, nullptr, s); - } -} - -extern "C" SANITIZER_WEAK_ATTRIBUTE -void android_set_abort_message(const char *); - -void SetAbortMessage(const char *str) { - if (&android_set_abort_message) - android_set_abort_message(str); -} -# else -void AndroidLogInit() {} - -static bool ShouldLogAfterPrintf() { return true; } - -void WriteOneLineToSyslog(const char *s) { syslog(LOG_INFO, "%s", s); } - -void SetAbortMessage(const char *str) {} -# endif // SANITIZER_ANDROID - -void LogMessageOnPrintf(const char *str) { - if (common_flags()->log_to_syslog && ShouldLogAfterPrintf()) - WriteToSyslog(str); -} - -#endif // SANITIZER_LINUX - -#if SANITIZER_LINUX && !SANITIZER_GO -// glibc crashes when using clock_gettime from a preinit_array function as the -// vDSO function pointers haven't been initialized yet. __progname is -// initialized after the vDSO function pointers, so if it exists, is not null -// and is not empty, we can use clock_gettime. -extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname; -INLINE bool CanUseVDSO() { - // Bionic is safe, it checks for the vDSO function pointers to be initialized. - if (SANITIZER_ANDROID) - return true; - if (&__progname && __progname && *__progname) - return true; - return false; -} - -// MonotonicNanoTime is a timing function that can leverage the vDSO by calling -// clock_gettime. real_clock_gettime only exists if clock_gettime is -// intercepted, so define it weakly and use it if available. -extern "C" SANITIZER_WEAK_ATTRIBUTE -int real_clock_gettime(u32 clk_id, void *tp); -u64 MonotonicNanoTime() { - timespec ts; - if (CanUseVDSO()) { - if (&real_clock_gettime) - real_clock_gettime(CLOCK_MONOTONIC, &ts); - else - clock_gettime(CLOCK_MONOTONIC, &ts); - } else { - internal_clock_gettime(CLOCK_MONOTONIC, &ts); - } - return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec; -} -#else -// Non-Linux & Go always use the syscall. -u64 MonotonicNanoTime() { - timespec ts; - internal_clock_gettime(CLOCK_MONOTONIC, &ts); - return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec; -} -#endif // SANITIZER_LINUX && !SANITIZER_GO - -#if !SANITIZER_OPENBSD -void ReExec() { - const char *pathname = "/proc/self/exe"; - -#if SANITIZER_NETBSD - static const int name[] = { - CTL_KERN, - KERN_PROC_ARGS, - -1, - KERN_PROC_PATHNAME, - }; - char path[400]; - uptr len; - - len = sizeof(path); - if (internal_sysctl(name, ARRAY_SIZE(name), path, &len, NULL, 0) != -1) - pathname = path; -#elif SANITIZER_SOLARIS - pathname = getexecname(); - CHECK_NE(pathname, NULL); -#elif SANITIZER_USE_GETAUXVAL - // Calling execve with /proc/self/exe sets that as $EXEC_ORIGIN. Binaries that - // rely on that will fail to load shared libraries. Query AT_EXECFN instead. - pathname = reinterpret_cast(getauxval(AT_EXECFN)); -#endif - - uptr rv = internal_execve(pathname, GetArgv(), GetEnviron()); - int rverrno; - CHECK_EQ(internal_iserror(rv, &rverrno), true); - Printf("execve failed, errno %d\n", rverrno); - Die(); -} -#endif // !SANITIZER_OPENBSD - -} // namespace __sanitizer - -#endif diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cpp b/lib/sanitizer_common/sanitizer_linux_libcdep.cpp new file mode 100644 index 000000000000..cd503718205a --- /dev/null +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cpp @@ -0,0 +1,847 @@ +//===-- sanitizer_linux_libcdep.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries and implements linux-specific functions from +// sanitizer_libc.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ + SANITIZER_OPENBSD || SANITIZER_SOLARIS + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_atomic.h" +#include "sanitizer_common.h" +#include "sanitizer_file.h" +#include "sanitizer_flags.h" +#include "sanitizer_freebsd.h" +#include "sanitizer_getauxval.h" +#include "sanitizer_glibc_version.h" +#include "sanitizer_linux.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_procmaps.h" + +#include // for dlsym() +#include +#include +#include +#include +#include + +#if SANITIZER_FREEBSD +#include +#include +#include +#define pthread_getattr_np pthread_attr_get_np +#endif + +#if SANITIZER_OPENBSD +#include +#include +#endif + +#if SANITIZER_NETBSD +#include +#include +#endif + +#if SANITIZER_SOLARIS +#include +#include +#endif + +#if SANITIZER_ANDROID +#include +#if !defined(CPU_COUNT) && !defined(__aarch64__) +#include +#include +struct __sanitizer::linux_dirent { + long d_ino; + off_t d_off; + unsigned short d_reclen; + char d_name[]; +}; +#endif +#endif + +#if !SANITIZER_ANDROID +#include +#include +#endif + +namespace __sanitizer { + +SANITIZER_WEAK_ATTRIBUTE int +real_sigaction(int signum, const void *act, void *oldact); + +int internal_sigaction(int signum, const void *act, void *oldact) { +#if !SANITIZER_GO + if (&real_sigaction) + return real_sigaction(signum, act, oldact); +#endif + return sigaction(signum, (const struct sigaction *)act, + (struct sigaction *)oldact); +} + +void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, + uptr *stack_bottom) { + CHECK(stack_top); + CHECK(stack_bottom); + if (at_initialization) { + // This is the main thread. Libpthread may not be initialized yet. + struct rlimit rl; + CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0); + + // Find the mapping that contains a stack variable. + MemoryMappingLayout proc_maps(/*cache_enabled*/true); + if (proc_maps.Error()) { + *stack_top = *stack_bottom = 0; + return; + } + MemoryMappedSegment segment; + uptr prev_end = 0; + while (proc_maps.Next(&segment)) { + if ((uptr)&rl < segment.end) break; + prev_end = segment.end; + } + CHECK((uptr)&rl >= segment.start && (uptr)&rl < segment.end); + + // Get stacksize from rlimit, but clip it so that it does not overlap + // with other mappings. + uptr stacksize = rl.rlim_cur; + if (stacksize > segment.end - prev_end) stacksize = segment.end - prev_end; + // When running with unlimited stack size, we still want to set some limit. + // The unlimited stack size is caused by 'ulimit -s unlimited'. + // Also, for some reason, GNU make spawns subprocesses with unlimited stack. + if (stacksize > kMaxThreadStackSize) + stacksize = kMaxThreadStackSize; + *stack_top = segment.end; + *stack_bottom = segment.end - stacksize; + return; + } + uptr stacksize = 0; + void *stackaddr = nullptr; +#if SANITIZER_SOLARIS + stack_t ss; + CHECK_EQ(thr_stksegment(&ss), 0); + stacksize = ss.ss_size; + stackaddr = (char *)ss.ss_sp - stacksize; +#elif SANITIZER_OPENBSD + stack_t sattr; + CHECK_EQ(pthread_stackseg_np(pthread_self(), &sattr), 0); + stackaddr = sattr.ss_sp; + stacksize = sattr.ss_size; +#else // !SANITIZER_SOLARIS + pthread_attr_t attr; + pthread_attr_init(&attr); + CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); + my_pthread_attr_getstack(&attr, &stackaddr, &stacksize); + pthread_attr_destroy(&attr); +#endif // SANITIZER_SOLARIS + + *stack_top = (uptr)stackaddr + stacksize; + *stack_bottom = (uptr)stackaddr; +} + +#if !SANITIZER_GO +bool SetEnv(const char *name, const char *value) { + void *f = dlsym(RTLD_NEXT, "setenv"); + if (!f) + return false; + typedef int(*setenv_ft)(const char *name, const char *value, int overwrite); + setenv_ft setenv_f; + CHECK_EQ(sizeof(setenv_f), sizeof(f)); + internal_memcpy(&setenv_f, &f, sizeof(f)); + return setenv_f(name, value, 1) == 0; +} +#endif + +__attribute__((unused)) static bool GetLibcVersion(int *major, int *minor, + int *patch) { +#ifdef _CS_GNU_LIBC_VERSION + char buf[64]; + uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf)); + if (len >= sizeof(buf)) + return false; + buf[len] = 0; + static const char kGLibC[] = "glibc "; + if (internal_strncmp(buf, kGLibC, sizeof(kGLibC) - 1) != 0) + return false; + const char *p = buf + sizeof(kGLibC) - 1; + *major = internal_simple_strtoll(p, &p, 10); + *minor = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0; + *patch = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0; + return true; +#else + return false; +#endif +} + +#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \ + !SANITIZER_NETBSD && !SANITIZER_OPENBSD && !SANITIZER_SOLARIS +static uptr g_tls_size; + +#ifdef __i386__ +# define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27)) +#else +# define CHECK_GET_TLS_STATIC_INFO_VERSION 0 +#endif + +#if CHECK_GET_TLS_STATIC_INFO_VERSION +# define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall)) +#else +# define DL_INTERNAL_FUNCTION +#endif + +namespace { +struct GetTlsStaticInfoCall { + typedef void (*get_tls_func)(size_t*, size_t*); +}; +struct GetTlsStaticInfoRegparmCall { + typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION; +}; + +template +void CallGetTls(void* ptr, size_t* size, size_t* align) { + typename T::get_tls_func get_tls; + CHECK_EQ(sizeof(get_tls), sizeof(ptr)); + internal_memcpy(&get_tls, &ptr, sizeof(ptr)); + CHECK_NE(get_tls, 0); + get_tls(size, align); +} + +bool CmpLibcVersion(int major, int minor, int patch) { + int ma; + int mi; + int pa; + if (!GetLibcVersion(&ma, &mi, &pa)) + return false; + if (ma > major) + return true; + if (ma < major) + return false; + if (mi > minor) + return true; + if (mi < minor) + return false; + return pa >= patch; +} + +} // namespace + +void InitTlsSize() { + // all current supported platforms have 16 bytes stack alignment + const size_t kStackAlign = 16; + void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info"); + size_t tls_size = 0; + size_t tls_align = 0; + // On i?86, _dl_get_tls_static_info used to be internal_function, i.e. + // __attribute__((regparm(3), stdcall)) before glibc 2.27 and is normal + // function in 2.27 and later. + if (CHECK_GET_TLS_STATIC_INFO_VERSION && !CmpLibcVersion(2, 27, 0)) + CallGetTls(get_tls_static_info_ptr, + &tls_size, &tls_align); + else + CallGetTls(get_tls_static_info_ptr, + &tls_size, &tls_align); + if (tls_align < kStackAlign) + tls_align = kStackAlign; + g_tls_size = RoundUpTo(tls_size, tls_align); +} +#else +void InitTlsSize() { } +#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && + // !SANITIZER_NETBSD && !SANITIZER_SOLARIS + +#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \ + defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \ + defined(__arm__)) && \ + SANITIZER_LINUX && !SANITIZER_ANDROID +// sizeof(struct pthread) from glibc. +static atomic_uintptr_t thread_descriptor_size; + +uptr ThreadDescriptorSize() { + uptr val = atomic_load_relaxed(&thread_descriptor_size); + if (val) + return val; +#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) + int major; + int minor; + int patch; + if (GetLibcVersion(&major, &minor, &patch) && major == 2) { + /* sizeof(struct pthread) values from various glibc versions. */ + if (SANITIZER_X32) + val = 1728; // Assume only one particular version for x32. + // For ARM sizeof(struct pthread) changed in Glibc 2.23. + else if (SANITIZER_ARM) + val = minor <= 22 ? 1120 : 1216; + else if (minor <= 3) + val = FIRST_32_SECOND_64(1104, 1696); + else if (minor == 4) + val = FIRST_32_SECOND_64(1120, 1728); + else if (minor == 5) + val = FIRST_32_SECOND_64(1136, 1728); + else if (minor <= 9) + val = FIRST_32_SECOND_64(1136, 1712); + else if (minor == 10) + val = FIRST_32_SECOND_64(1168, 1776); + else if (minor == 11 || (minor == 12 && patch == 1)) + val = FIRST_32_SECOND_64(1168, 2288); + else if (minor <= 14) + val = FIRST_32_SECOND_64(1168, 2304); + else + val = FIRST_32_SECOND_64(1216, 2304); + } +#elif defined(__mips__) + // TODO(sagarthakur): add more values as per different glibc versions. + val = FIRST_32_SECOND_64(1152, 1776); +#elif defined(__aarch64__) + // The sizeof (struct pthread) is the same from GLIBC 2.17 to 2.22. + val = 1776; +#elif defined(__powerpc64__) + val = 1776; // from glibc.ppc64le 2.20-8.fc21 +#elif defined(__s390__) + val = FIRST_32_SECOND_64(1152, 1776); // valid for glibc 2.22 +#endif + if (val) + atomic_store_relaxed(&thread_descriptor_size, val); + return val; +} + +// The offset at which pointer to self is located in the thread descriptor. +const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16); + +uptr ThreadSelfOffset() { + return kThreadSelfOffset; +} + +#if defined(__mips__) || defined(__powerpc64__) +// TlsPreTcbSize includes size of struct pthread_descr and size of tcb +// head structure. It lies before the static tls blocks. +static uptr TlsPreTcbSize() { +# if defined(__mips__) + const uptr kTcbHead = 16; // sizeof (tcbhead_t) +# elif defined(__powerpc64__) + const uptr kTcbHead = 88; // sizeof (tcbhead_t) +# endif + const uptr kTlsAlign = 16; + const uptr kTlsPreTcbSize = + RoundUpTo(ThreadDescriptorSize() + kTcbHead, kTlsAlign); + return kTlsPreTcbSize; +} +#endif + +uptr ThreadSelf() { + uptr descr_addr; +# if defined(__i386__) + asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset)); +# elif defined(__x86_64__) + asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset)); +# elif defined(__mips__) + // MIPS uses TLS variant I. The thread pointer (in hardware register $29) + // points to the end of the TCB + 0x7000. The pthread_descr structure is + // immediately in front of the TCB. TlsPreTcbSize() includes the size of the + // TCB and the size of pthread_descr. + const uptr kTlsTcbOffset = 0x7000; + uptr thread_pointer; + asm volatile(".set push;\ + .set mips64r2;\ + rdhwr %0,$29;\ + .set pop" : "=r" (thread_pointer)); + descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize(); +# elif defined(__aarch64__) || defined(__arm__) + descr_addr = reinterpret_cast(__builtin_thread_pointer()) - + ThreadDescriptorSize(); +# elif defined(__s390__) + descr_addr = reinterpret_cast(__builtin_thread_pointer()); +# elif defined(__powerpc64__) + // PPC64LE uses TLS variant I. The thread pointer (in GPR 13) + // points to the end of the TCB + 0x7000. The pthread_descr structure is + // immediately in front of the TCB. TlsPreTcbSize() includes the size of the + // TCB and the size of pthread_descr. + const uptr kTlsTcbOffset = 0x7000; + uptr thread_pointer; + asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset)); + descr_addr = thread_pointer - TlsPreTcbSize(); +# else +# error "unsupported CPU arch" +# endif + return descr_addr; +} +#endif // (x86_64 || i386 || MIPS) && SANITIZER_LINUX + +#if SANITIZER_FREEBSD +static void **ThreadSelfSegbase() { + void **segbase = 0; +# if defined(__i386__) + // sysarch(I386_GET_GSBASE, segbase); + __asm __volatile("mov %%gs:0, %0" : "=r" (segbase)); +# elif defined(__x86_64__) + // sysarch(AMD64_GET_FSBASE, segbase); + __asm __volatile("movq %%fs:0, %0" : "=r" (segbase)); +# else +# error "unsupported CPU arch" +# endif + return segbase; +} + +uptr ThreadSelf() { + return (uptr)ThreadSelfSegbase()[2]; +} +#endif // SANITIZER_FREEBSD + +#if SANITIZER_NETBSD +static struct tls_tcb * ThreadSelfTlsTcb() { + struct tls_tcb * tcb; +# ifdef __HAVE___LWP_GETTCB_FAST + tcb = (struct tls_tcb *)__lwp_gettcb_fast(); +# elif defined(__HAVE___LWP_GETPRIVATE_FAST) + tcb = (struct tls_tcb *)__lwp_getprivate_fast(); +# endif + return tcb; +} + +uptr ThreadSelf() { + return (uptr)ThreadSelfTlsTcb()->tcb_pthread; +} + +int GetSizeFromHdr(struct dl_phdr_info *info, size_t size, void *data) { + const Elf_Phdr *hdr = info->dlpi_phdr; + const Elf_Phdr *last_hdr = hdr + info->dlpi_phnum; + + for (; hdr != last_hdr; ++hdr) { + if (hdr->p_type == PT_TLS && info->dlpi_tls_modid == 1) { + *(uptr*)data = hdr->p_memsz; + break; + } + } + return 0; +} +#endif // SANITIZER_NETBSD + +#if !SANITIZER_GO +static void GetTls(uptr *addr, uptr *size) { +#if SANITIZER_LINUX && !SANITIZER_ANDROID +# if defined(__x86_64__) || defined(__i386__) || defined(__s390__) + *addr = ThreadSelf(); + *size = GetTlsSize(); + *addr -= *size; + *addr += ThreadDescriptorSize(); +# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) \ + || defined(__arm__) + *addr = ThreadSelf(); + *size = GetTlsSize(); +# else + *addr = 0; + *size = 0; +# endif +#elif SANITIZER_FREEBSD + void** segbase = ThreadSelfSegbase(); + *addr = 0; + *size = 0; + if (segbase != 0) { + // tcbalign = 16 + // tls_size = round(tls_static_space, tcbalign); + // dtv = segbase[1]; + // dtv[2] = segbase - tls_static_space; + void **dtv = (void**) segbase[1]; + *addr = (uptr) dtv[2]; + *size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]); + } +#elif SANITIZER_NETBSD + struct tls_tcb * const tcb = ThreadSelfTlsTcb(); + *addr = 0; + *size = 0; + if (tcb != 0) { + // Find size (p_memsz) of dlpi_tls_modid 1 (TLS block of the main program). + // ld.elf_so hardcodes the index 1. + dl_iterate_phdr(GetSizeFromHdr, size); + + if (*size != 0) { + // The block has been found and tcb_dtv[1] contains the base address + *addr = (uptr)tcb->tcb_dtv[1]; + } + } +#elif SANITIZER_OPENBSD + *addr = 0; + *size = 0; +#elif SANITIZER_ANDROID + *addr = 0; + *size = 0; +#elif SANITIZER_SOLARIS + // FIXME + *addr = 0; + *size = 0; +#else +# error "Unknown OS" +#endif +} +#endif + +#if !SANITIZER_GO +uptr GetTlsSize() { +#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \ + SANITIZER_OPENBSD || SANITIZER_SOLARIS + uptr addr, size; + GetTls(&addr, &size); + return size; +#elif defined(__mips__) || defined(__powerpc64__) + return RoundUpTo(g_tls_size + TlsPreTcbSize(), 16); +#else + return g_tls_size; +#endif +} +#endif + +void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, + uptr *tls_addr, uptr *tls_size) { +#if SANITIZER_GO + // Stub implementation for Go. + *stk_addr = *stk_size = *tls_addr = *tls_size = 0; +#else + GetTls(tls_addr, tls_size); + + uptr stack_top, stack_bottom; + GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); + *stk_addr = stack_bottom; + *stk_size = stack_top - stack_bottom; + + if (!main) { + // If stack and tls intersect, make them non-intersecting. + if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) { + CHECK_GT(*tls_addr + *tls_size, *stk_addr); + CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size); + *stk_size -= *tls_size; + *tls_addr = *stk_addr + *stk_size; + } + } +#endif +} + +#if !SANITIZER_FREEBSD && !SANITIZER_OPENBSD +typedef ElfW(Phdr) Elf_Phdr; +#elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2 +#define Elf_Phdr XElf32_Phdr +#define dl_phdr_info xdl_phdr_info +#define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b)) +#endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD + +struct DlIteratePhdrData { + InternalMmapVectorNoCtor *modules; + bool first; +}; + +static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) { + DlIteratePhdrData *data = (DlIteratePhdrData*)arg; + InternalScopedString module_name(kMaxPathLength); + if (data->first) { + data->first = false; + // First module is the binary itself. + ReadBinaryNameCached(module_name.data(), module_name.size()); + } else if (info->dlpi_name) { + module_name.append("%s", info->dlpi_name); + } + if (module_name[0] == '\0') + return 0; + LoadedModule cur_module; + cur_module.set(module_name.data(), info->dlpi_addr); + for (int i = 0; i < (int)info->dlpi_phnum; i++) { + const Elf_Phdr *phdr = &info->dlpi_phdr[i]; + if (phdr->p_type == PT_LOAD) { + uptr cur_beg = info->dlpi_addr + phdr->p_vaddr; + uptr cur_end = cur_beg + phdr->p_memsz; + bool executable = phdr->p_flags & PF_X; + bool writable = phdr->p_flags & PF_W; + cur_module.addAddressRange(cur_beg, cur_end, executable, + writable); + } + } + data->modules->push_back(cur_module); + return 0; +} + +#if SANITIZER_ANDROID && __ANDROID_API__ < 21 +extern "C" __attribute__((weak)) int dl_iterate_phdr( + int (*)(struct dl_phdr_info *, size_t, void *), void *); +#endif + +static bool requiresProcmaps() { +#if SANITIZER_ANDROID && __ANDROID_API__ <= 22 + // Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken. + // The runtime check allows the same library to work with + // both K and L (and future) Android releases. + return AndroidGetApiLevel() <= ANDROID_LOLLIPOP_MR1; +#else + return false; +#endif +} + +static void procmapsInit(InternalMmapVectorNoCtor *modules) { + MemoryMappingLayout memory_mapping(/*cache_enabled*/true); + memory_mapping.DumpListOfModules(modules); +} + +void ListOfModules::init() { + clearOrInit(); + if (requiresProcmaps()) { + procmapsInit(&modules_); + } else { + DlIteratePhdrData data = {&modules_, true}; + dl_iterate_phdr(dl_iterate_phdr_cb, &data); + } +} + +// When a custom loader is used, dl_iterate_phdr may not contain the full +// list of modules. Allow callers to fall back to using procmaps. +void ListOfModules::fallbackInit() { + if (!requiresProcmaps()) { + clearOrInit(); + procmapsInit(&modules_); + } else { + clear(); + } +} + +// getrusage does not give us the current RSS, only the max RSS. +// Still, this is better than nothing if /proc/self/statm is not available +// for some reason, e.g. due to a sandbox. +static uptr GetRSSFromGetrusage() { + struct rusage usage; + if (getrusage(RUSAGE_SELF, &usage)) // Failed, probably due to a sandbox. + return 0; + return usage.ru_maxrss << 10; // ru_maxrss is in Kb. +} + +uptr GetRSS() { + if (!common_flags()->can_use_proc_maps_statm) + return GetRSSFromGetrusage(); + fd_t fd = OpenFile("/proc/self/statm", RdOnly); + if (fd == kInvalidFd) + return GetRSSFromGetrusage(); + char buf[64]; + uptr len = internal_read(fd, buf, sizeof(buf) - 1); + internal_close(fd); + if ((sptr)len <= 0) + return 0; + buf[len] = 0; + // The format of the file is: + // 1084 89 69 11 0 79 0 + // We need the second number which is RSS in pages. + char *pos = buf; + // Skip the first number. + while (*pos >= '0' && *pos <= '9') + pos++; + // Skip whitespaces. + while (!(*pos >= '0' && *pos <= '9') && *pos != 0) + pos++; + // Read the number. + uptr rss = 0; + while (*pos >= '0' && *pos <= '9') + rss = rss * 10 + *pos++ - '0'; + return rss * GetPageSizeCached(); +} + +// sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used on most platforms as +// they allocate memory. +u32 GetNumberOfCPUs() { +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD + u32 ncpu; + int req[2]; + uptr len = sizeof(ncpu); + req[0] = CTL_HW; + req[1] = HW_NCPU; + CHECK_EQ(internal_sysctl(req, 2, &ncpu, &len, NULL, 0), 0); + return ncpu; +#elif SANITIZER_ANDROID && !defined(CPU_COUNT) && !defined(__aarch64__) + // Fall back to /sys/devices/system/cpu on Android when cpu_set_t doesn't + // exist in sched.h. That is the case for toolchains generated with older + // NDKs. + // This code doesn't work on AArch64 because internal_getdents makes use of + // the 64bit getdents syscall, but cpu_set_t seems to always exist on AArch64. + uptr fd = internal_open("/sys/devices/system/cpu", O_RDONLY | O_DIRECTORY); + if (internal_iserror(fd)) + return 0; + InternalMmapVector buffer(4096); + uptr bytes_read = buffer.size(); + uptr n_cpus = 0; + u8 *d_type; + struct linux_dirent *entry = (struct linux_dirent *)&buffer[bytes_read]; + while (true) { + if ((u8 *)entry >= &buffer[bytes_read]) { + bytes_read = internal_getdents(fd, (struct linux_dirent *)buffer.data(), + buffer.size()); + if (internal_iserror(bytes_read) || !bytes_read) + break; + entry = (struct linux_dirent *)buffer.data(); + } + d_type = (u8 *)entry + entry->d_reclen - 1; + if (d_type >= &buffer[bytes_read] || + (u8 *)&entry->d_name[3] >= &buffer[bytes_read]) + break; + if (entry->d_ino != 0 && *d_type == DT_DIR) { + if (entry->d_name[0] == 'c' && entry->d_name[1] == 'p' && + entry->d_name[2] == 'u' && + entry->d_name[3] >= '0' && entry->d_name[3] <= '9') + n_cpus++; + } + entry = (struct linux_dirent *)(((u8 *)entry) + entry->d_reclen); + } + internal_close(fd); + return n_cpus; +#elif SANITIZER_SOLARIS + return sysconf(_SC_NPROCESSORS_ONLN); +#else + cpu_set_t CPUs; + CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0); + return CPU_COUNT(&CPUs); +#endif +} + +#if SANITIZER_LINUX + +# if SANITIZER_ANDROID +static atomic_uint8_t android_log_initialized; + +void AndroidLogInit() { + openlog(GetProcessName(), 0, LOG_USER); + atomic_store(&android_log_initialized, 1, memory_order_release); +} + +static bool ShouldLogAfterPrintf() { + return atomic_load(&android_log_initialized, memory_order_acquire); +} + +extern "C" SANITIZER_WEAK_ATTRIBUTE +int async_safe_write_log(int pri, const char* tag, const char* msg); +extern "C" SANITIZER_WEAK_ATTRIBUTE +int __android_log_write(int prio, const char* tag, const char* msg); + +// ANDROID_LOG_INFO is 4, but can't be resolved at runtime. +#define SANITIZER_ANDROID_LOG_INFO 4 + +// async_safe_write_log is a new public version of __libc_write_log that is +// used behind syslog. It is preferable to syslog as it will not do any dynamic +// memory allocation or formatting. +// If the function is not available, syslog is preferred for L+ (it was broken +// pre-L) as __android_log_write triggers a racey behavior with the strncpy +// interceptor. Fallback to __android_log_write pre-L. +void WriteOneLineToSyslog(const char *s) { + if (&async_safe_write_log) { + async_safe_write_log(SANITIZER_ANDROID_LOG_INFO, GetProcessName(), s); + } else if (AndroidGetApiLevel() > ANDROID_KITKAT) { + syslog(LOG_INFO, "%s", s); + } else { + CHECK(&__android_log_write); + __android_log_write(SANITIZER_ANDROID_LOG_INFO, nullptr, s); + } +} + +extern "C" SANITIZER_WEAK_ATTRIBUTE +void android_set_abort_message(const char *); + +void SetAbortMessage(const char *str) { + if (&android_set_abort_message) + android_set_abort_message(str); +} +# else +void AndroidLogInit() {} + +static bool ShouldLogAfterPrintf() { return true; } + +void WriteOneLineToSyslog(const char *s) { syslog(LOG_INFO, "%s", s); } + +void SetAbortMessage(const char *str) {} +# endif // SANITIZER_ANDROID + +void LogMessageOnPrintf(const char *str) { + if (common_flags()->log_to_syslog && ShouldLogAfterPrintf()) + WriteToSyslog(str); +} + +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX && !SANITIZER_GO +// glibc crashes when using clock_gettime from a preinit_array function as the +// vDSO function pointers haven't been initialized yet. __progname is +// initialized after the vDSO function pointers, so if it exists, is not null +// and is not empty, we can use clock_gettime. +extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname; +INLINE bool CanUseVDSO() { + // Bionic is safe, it checks for the vDSO function pointers to be initialized. + if (SANITIZER_ANDROID) + return true; + if (&__progname && __progname && *__progname) + return true; + return false; +} + +// MonotonicNanoTime is a timing function that can leverage the vDSO by calling +// clock_gettime. real_clock_gettime only exists if clock_gettime is +// intercepted, so define it weakly and use it if available. +extern "C" SANITIZER_WEAK_ATTRIBUTE +int real_clock_gettime(u32 clk_id, void *tp); +u64 MonotonicNanoTime() { + timespec ts; + if (CanUseVDSO()) { + if (&real_clock_gettime) + real_clock_gettime(CLOCK_MONOTONIC, &ts); + else + clock_gettime(CLOCK_MONOTONIC, &ts); + } else { + internal_clock_gettime(CLOCK_MONOTONIC, &ts); + } + return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec; +} +#else +// Non-Linux & Go always use the syscall. +u64 MonotonicNanoTime() { + timespec ts; + internal_clock_gettime(CLOCK_MONOTONIC, &ts); + return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec; +} +#endif // SANITIZER_LINUX && !SANITIZER_GO + +#if !SANITIZER_OPENBSD +void ReExec() { + const char *pathname = "/proc/self/exe"; + +#if SANITIZER_NETBSD + static const int name[] = { + CTL_KERN, + KERN_PROC_ARGS, + -1, + KERN_PROC_PATHNAME, + }; + char path[400]; + uptr len; + + len = sizeof(path); + if (internal_sysctl(name, ARRAY_SIZE(name), path, &len, NULL, 0) != -1) + pathname = path; +#elif SANITIZER_SOLARIS + pathname = getexecname(); + CHECK_NE(pathname, NULL); +#elif SANITIZER_USE_GETAUXVAL + // Calling execve with /proc/self/exe sets that as $EXEC_ORIGIN. Binaries that + // rely on that will fail to load shared libraries. Query AT_EXECFN instead. + pathname = reinterpret_cast(getauxval(AT_EXECFN)); +#endif + + uptr rv = internal_execve(pathname, GetArgv(), GetEnviron()); + int rverrno; + CHECK_EQ(internal_iserror(rv, &rverrno), true); + Printf("execve failed, errno %d\n", rverrno); + Die(); +} +#endif // !SANITIZER_OPENBSD + +} // namespace __sanitizer + +#endif diff --git a/lib/sanitizer_common/sanitizer_linux_s390.cc b/lib/sanitizer_common/sanitizer_linux_s390.cc deleted file mode 100644 index b681bef35b76..000000000000 --- a/lib/sanitizer_common/sanitizer_linux_s390.cc +++ /dev/null @@ -1,221 +0,0 @@ -//===-- sanitizer_linux_s390.cc -------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries and implements s390-linux-specific functions from -// sanitizer_libc.h. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_LINUX && SANITIZER_S390 - -#include "sanitizer_libc.h" -#include "sanitizer_linux.h" - -#include -#include -#include -#include - -namespace __sanitizer { - -// --------------- sanitizer_libc.h -uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, - OFF_T offset) { - struct s390_mmap_params { - unsigned long addr; - unsigned long length; - unsigned long prot; - unsigned long flags; - unsigned long fd; - unsigned long offset; - } params = { - (unsigned long)addr, - (unsigned long)length, - (unsigned long)prot, - (unsigned long)flags, - (unsigned long)fd, -# ifdef __s390x__ - (unsigned long)offset, -# else - (unsigned long)(offset / 4096), -# endif - }; -# ifdef __s390x__ - return syscall(__NR_mmap, ¶ms); -# else - return syscall(__NR_mmap2, ¶ms); -# endif -} - -uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, - int *parent_tidptr, void *newtls, int *child_tidptr) { - if (!fn || !child_stack) - return -EINVAL; - CHECK_EQ(0, (uptr)child_stack % 16); - // Minimum frame size. -#ifdef __s390x__ - child_stack = (char *)child_stack - 160; -#else - child_stack = (char *)child_stack - 96; -#endif - // Terminate unwind chain. - ((unsigned long *)child_stack)[0] = 0; - // And pass parameters. - ((unsigned long *)child_stack)[1] = (uptr)fn; - ((unsigned long *)child_stack)[2] = (uptr)arg; - register long res __asm__("r2"); - register void *__cstack __asm__("r2") = child_stack; - register int __flags __asm__("r3") = flags; - register int * __ptidptr __asm__("r4") = parent_tidptr; - register int * __ctidptr __asm__("r5") = child_tidptr; - register void * __newtls __asm__("r6") = newtls; - - __asm__ __volatile__( - /* Clone. */ - "svc %1\n" - - /* if (%r2 != 0) - * return; - */ -#ifdef __s390x__ - "cghi %%r2, 0\n" -#else - "chi %%r2, 0\n" -#endif - "jne 1f\n" - - /* Call "fn(arg)". */ -#ifdef __s390x__ - "lmg %%r1, %%r2, 8(%%r15)\n" -#else - "lm %%r1, %%r2, 4(%%r15)\n" -#endif - "basr %%r14, %%r1\n" - - /* Call _exit(%r2). */ - "svc %2\n" - - /* Return to parent. */ - "1:\n" - : "=r" (res) - : "i"(__NR_clone), "i"(__NR_exit), - "r"(__cstack), - "r"(__flags), - "r"(__ptidptr), - "r"(__ctidptr), - "r"(__newtls) - : "memory", "cc"); - return res; -} - -#if SANITIZER_S390_64 -static bool FixedCVE_2016_2143() { - // Try to determine if the running kernel has a fix for CVE-2016-2143, - // return false if in doubt (better safe than sorry). Distros may want to - // adjust this for their own kernels. - struct utsname buf; - unsigned int major, minor, patch = 0; - // This should never fail, but just in case... - if (uname(&buf)) - return false; - const char *ptr = buf.release; - major = internal_simple_strtoll(ptr, &ptr, 10); - // At least first 2 should be matched. - if (ptr[0] != '.') - return false; - minor = internal_simple_strtoll(ptr+1, &ptr, 10); - // Third is optional. - if (ptr[0] == '.') - patch = internal_simple_strtoll(ptr+1, &ptr, 10); - if (major < 3) { - if (major == 2 && minor == 6 && patch == 32 && ptr[0] == '-' && - internal_strstr(ptr, ".el6")) { - // Check RHEL6 - int r1 = internal_simple_strtoll(ptr+1, &ptr, 10); - if (r1 >= 657) // 2.6.32-657.el6 or later - return true; - if (r1 == 642 && ptr[0] == '.') { - int r2 = internal_simple_strtoll(ptr+1, &ptr, 10); - if (r2 >= 9) // 2.6.32-642.9.1.el6 or later - return true; - } - } - // <3.0 is bad. - return false; - } else if (major == 3) { - // 3.2.79+ is OK. - if (minor == 2 && patch >= 79) - return true; - // 3.12.58+ is OK. - if (minor == 12 && patch >= 58) - return true; - if (minor == 10 && patch == 0 && ptr[0] == '-' && - internal_strstr(ptr, ".el7")) { - // Check RHEL7 - int r1 = internal_simple_strtoll(ptr+1, &ptr, 10); - if (r1 >= 426) // 3.10.0-426.el7 or later - return true; - if (r1 == 327 && ptr[0] == '.') { - int r2 = internal_simple_strtoll(ptr+1, &ptr, 10); - if (r2 >= 27) // 3.10.0-327.27.1.el7 or later - return true; - } - } - // Otherwise, bad. - return false; - } else if (major == 4) { - // 4.1.21+ is OK. - if (minor == 1 && patch >= 21) - return true; - // 4.4.6+ is OK. - if (minor == 4 && patch >= 6) - return true; - if (minor == 4 && patch == 0 && ptr[0] == '-' && - internal_strstr(buf.version, "Ubuntu")) { - // Check Ubuntu 16.04 - int r1 = internal_simple_strtoll(ptr+1, &ptr, 10); - if (r1 >= 13) // 4.4.0-13 or later - return true; - } - // Otherwise, OK if 4.5+. - return minor >= 5; - } else { - // Linux 5 and up are fine. - return true; - } -} - -void AvoidCVE_2016_2143() { - // Older kernels are affected by CVE-2016-2143 - they will crash hard - // if someone uses 4-level page tables (ie. virtual addresses >= 4TB) - // and fork() in the same process. Unfortunately, sanitizers tend to - // require such addresses. Since this is very likely to crash the whole - // machine (sanitizers themselves use fork() for llvm-symbolizer, for one), - // abort the process at initialization instead. - if (FixedCVE_2016_2143()) - return; - if (GetEnv("SANITIZER_IGNORE_CVE_2016_2143")) - return; - Report( - "ERROR: Your kernel seems to be vulnerable to CVE-2016-2143. Using ASan,\n" - "MSan, TSan, DFSan or LSan with such kernel can and will crash your\n" - "machine, or worse.\n" - "\n" - "If you are certain your kernel is not vulnerable (you have compiled it\n" - "yourself, or are using an unrecognized distribution kernel), you can\n" - "override this safety check by exporting SANITIZER_IGNORE_CVE_2016_2143\n" - "with any value.\n"); - Die(); -} -#endif - -} // namespace __sanitizer - -#endif // SANITIZER_LINUX && SANITIZER_S390 diff --git a/lib/sanitizer_common/sanitizer_linux_s390.cpp b/lib/sanitizer_common/sanitizer_linux_s390.cpp new file mode 100644 index 000000000000..41e187eaf8da --- /dev/null +++ b/lib/sanitizer_common/sanitizer_linux_s390.cpp @@ -0,0 +1,221 @@ +//===-- sanitizer_linux_s390.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries and implements s390-linux-specific functions from +// sanitizer_libc.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_LINUX && SANITIZER_S390 + +#include "sanitizer_libc.h" +#include "sanitizer_linux.h" + +#include +#include +#include +#include + +namespace __sanitizer { + +// --------------- sanitizer_libc.h +uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, + OFF_T offset) { + struct s390_mmap_params { + unsigned long addr; + unsigned long length; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; + } params = { + (unsigned long)addr, + (unsigned long)length, + (unsigned long)prot, + (unsigned long)flags, + (unsigned long)fd, +# ifdef __s390x__ + (unsigned long)offset, +# else + (unsigned long)(offset / 4096), +# endif + }; +# ifdef __s390x__ + return syscall(__NR_mmap, ¶ms); +# else + return syscall(__NR_mmap2, ¶ms); +# endif +} + +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + if (!fn || !child_stack) + return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); + // Minimum frame size. +#ifdef __s390x__ + child_stack = (char *)child_stack - 160; +#else + child_stack = (char *)child_stack - 96; +#endif + // Terminate unwind chain. + ((unsigned long *)child_stack)[0] = 0; + // And pass parameters. + ((unsigned long *)child_stack)[1] = (uptr)fn; + ((unsigned long *)child_stack)[2] = (uptr)arg; + register long res __asm__("r2"); + register void *__cstack __asm__("r2") = child_stack; + register int __flags __asm__("r3") = flags; + register int * __ptidptr __asm__("r4") = parent_tidptr; + register int * __ctidptr __asm__("r5") = child_tidptr; + register void * __newtls __asm__("r6") = newtls; + + __asm__ __volatile__( + /* Clone. */ + "svc %1\n" + + /* if (%r2 != 0) + * return; + */ +#ifdef __s390x__ + "cghi %%r2, 0\n" +#else + "chi %%r2, 0\n" +#endif + "jne 1f\n" + + /* Call "fn(arg)". */ +#ifdef __s390x__ + "lmg %%r1, %%r2, 8(%%r15)\n" +#else + "lm %%r1, %%r2, 4(%%r15)\n" +#endif + "basr %%r14, %%r1\n" + + /* Call _exit(%r2). */ + "svc %2\n" + + /* Return to parent. */ + "1:\n" + : "=r" (res) + : "i"(__NR_clone), "i"(__NR_exit), + "r"(__cstack), + "r"(__flags), + "r"(__ptidptr), + "r"(__ctidptr), + "r"(__newtls) + : "memory", "cc"); + return res; +} + +#if SANITIZER_S390_64 +static bool FixedCVE_2016_2143() { + // Try to determine if the running kernel has a fix for CVE-2016-2143, + // return false if in doubt (better safe than sorry). Distros may want to + // adjust this for their own kernels. + struct utsname buf; + unsigned int major, minor, patch = 0; + // This should never fail, but just in case... + if (uname(&buf)) + return false; + const char *ptr = buf.release; + major = internal_simple_strtoll(ptr, &ptr, 10); + // At least first 2 should be matched. + if (ptr[0] != '.') + return false; + minor = internal_simple_strtoll(ptr+1, &ptr, 10); + // Third is optional. + if (ptr[0] == '.') + patch = internal_simple_strtoll(ptr+1, &ptr, 10); + if (major < 3) { + if (major == 2 && minor == 6 && patch == 32 && ptr[0] == '-' && + internal_strstr(ptr, ".el6")) { + // Check RHEL6 + int r1 = internal_simple_strtoll(ptr+1, &ptr, 10); + if (r1 >= 657) // 2.6.32-657.el6 or later + return true; + if (r1 == 642 && ptr[0] == '.') { + int r2 = internal_simple_strtoll(ptr+1, &ptr, 10); + if (r2 >= 9) // 2.6.32-642.9.1.el6 or later + return true; + } + } + // <3.0 is bad. + return false; + } else if (major == 3) { + // 3.2.79+ is OK. + if (minor == 2 && patch >= 79) + return true; + // 3.12.58+ is OK. + if (minor == 12 && patch >= 58) + return true; + if (minor == 10 && patch == 0 && ptr[0] == '-' && + internal_strstr(ptr, ".el7")) { + // Check RHEL7 + int r1 = internal_simple_strtoll(ptr+1, &ptr, 10); + if (r1 >= 426) // 3.10.0-426.el7 or later + return true; + if (r1 == 327 && ptr[0] == '.') { + int r2 = internal_simple_strtoll(ptr+1, &ptr, 10); + if (r2 >= 27) // 3.10.0-327.27.1.el7 or later + return true; + } + } + // Otherwise, bad. + return false; + } else if (major == 4) { + // 4.1.21+ is OK. + if (minor == 1 && patch >= 21) + return true; + // 4.4.6+ is OK. + if (minor == 4 && patch >= 6) + return true; + if (minor == 4 && patch == 0 && ptr[0] == '-' && + internal_strstr(buf.version, "Ubuntu")) { + // Check Ubuntu 16.04 + int r1 = internal_simple_strtoll(ptr+1, &ptr, 10); + if (r1 >= 13) // 4.4.0-13 or later + return true; + } + // Otherwise, OK if 4.5+. + return minor >= 5; + } else { + // Linux 5 and up are fine. + return true; + } +} + +void AvoidCVE_2016_2143() { + // Older kernels are affected by CVE-2016-2143 - they will crash hard + // if someone uses 4-level page tables (ie. virtual addresses >= 4TB) + // and fork() in the same process. Unfortunately, sanitizers tend to + // require such addresses. Since this is very likely to crash the whole + // machine (sanitizers themselves use fork() for llvm-symbolizer, for one), + // abort the process at initialization instead. + if (FixedCVE_2016_2143()) + return; + if (GetEnv("SANITIZER_IGNORE_CVE_2016_2143")) + return; + Report( + "ERROR: Your kernel seems to be vulnerable to CVE-2016-2143. Using ASan,\n" + "MSan, TSan, DFSan or LSan with such kernel can and will crash your\n" + "machine, or worse.\n" + "\n" + "If you are certain your kernel is not vulnerable (you have compiled it\n" + "yourself, or are using an unrecognized distribution kernel), you can\n" + "override this safety check by exporting SANITIZER_IGNORE_CVE_2016_2143\n" + "with any value.\n"); + Die(); +} +#endif + +} // namespace __sanitizer + +#endif // SANITIZER_LINUX && SANITIZER_S390 diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc deleted file mode 100644 index d9b7c4b12926..000000000000 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ /dev/null @@ -1,1135 +0,0 @@ -//===-- sanitizer_mac.cc --------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between various sanitizers' runtime libraries and -// implements OSX-specific functions. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_MAC -#include "sanitizer_mac.h" - -// Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so -// the clients will most certainly use 64-bit ones as well. -#ifndef _DARWIN_USE_64_BIT_INODE -#define _DARWIN_USE_64_BIT_INODE 1 -#endif -#include - -#include "sanitizer_common.h" -#include "sanitizer_file.h" -#include "sanitizer_flags.h" -#include "sanitizer_internal_defs.h" -#include "sanitizer_libc.h" -#include "sanitizer_placement_new.h" -#include "sanitizer_platform_limits_posix.h" -#include "sanitizer_procmaps.h" - -#if !SANITIZER_IOS -#include // for _NSGetEnviron -#else -extern char **environ; -#endif - -#if defined(__has_include) && __has_include() -#define SANITIZER_OS_TRACE 1 -#include -#else -#define SANITIZER_OS_TRACE 0 -#endif - -#if !SANITIZER_IOS -#include // for _NSGetArgv and _NSGetEnviron -#else -extern "C" { - extern char ***_NSGetArgv(void); -} -#endif - -#include -#include // for dladdr() -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// From , but we don't have that file on iOS. -extern "C" { - extern char ***_NSGetArgv(void); - extern char ***_NSGetEnviron(void); -} - -// From , but we don't have that file on iOS. -extern "C" { - extern kern_return_t mach_vm_region_recurse( - vm_map_t target_task, - mach_vm_address_t *address, - mach_vm_size_t *size, - natural_t *nesting_depth, - vm_region_recurse_info_t info, - mach_msg_type_number_t *infoCnt); -} - -namespace __sanitizer { - -#include "sanitizer_syscall_generic.inc" - -// Direct syscalls, don't call libmalloc hooks (but not available on 10.6). -extern "C" void *__mmap(void *addr, size_t len, int prot, int flags, int fildes, - off_t off) SANITIZER_WEAK_ATTRIBUTE; -extern "C" int __munmap(void *, size_t) SANITIZER_WEAK_ATTRIBUTE; - -// ---------------------- sanitizer_libc.h - -// From , but not on older OSs. -#ifndef VM_MEMORY_SANITIZER -#define VM_MEMORY_SANITIZER 99 -#endif - -// XNU on Darwin provides a mmap flag that optimizes allocation/deallocation of -// giant memory regions (i.e. shadow memory regions). -#define kXnuFastMmapFd 0x4 -static size_t kXnuFastMmapThreshold = 2 << 30; // 2 GB -static bool use_xnu_fast_mmap = false; - -uptr internal_mmap(void *addr, size_t length, int prot, int flags, - int fd, u64 offset) { - if (fd == -1) { - fd = VM_MAKE_TAG(VM_MEMORY_SANITIZER); - if (length >= kXnuFastMmapThreshold) { - if (use_xnu_fast_mmap) fd |= kXnuFastMmapFd; - } - } - if (&__mmap) return (uptr)__mmap(addr, length, prot, flags, fd, offset); - return (uptr)mmap(addr, length, prot, flags, fd, offset); -} - -uptr internal_munmap(void *addr, uptr length) { - if (&__munmap) return __munmap(addr, length); - return munmap(addr, length); -} - -int internal_mprotect(void *addr, uptr length, int prot) { - return mprotect(addr, length, prot); -} - -uptr internal_close(fd_t fd) { - return close(fd); -} - -uptr internal_open(const char *filename, int flags) { - return open(filename, flags); -} - -uptr internal_open(const char *filename, int flags, u32 mode) { - return open(filename, flags, mode); -} - -uptr internal_read(fd_t fd, void *buf, uptr count) { - return read(fd, buf, count); -} - -uptr internal_write(fd_t fd, const void *buf, uptr count) { - return write(fd, buf, count); -} - -uptr internal_stat(const char *path, void *buf) { - return stat(path, (struct stat *)buf); -} - -uptr internal_lstat(const char *path, void *buf) { - return lstat(path, (struct stat *)buf); -} - -uptr internal_fstat(fd_t fd, void *buf) { - return fstat(fd, (struct stat *)buf); -} - -uptr internal_filesize(fd_t fd) { - struct stat st; - if (internal_fstat(fd, &st)) - return -1; - return (uptr)st.st_size; -} - -uptr internal_dup(int oldfd) { - return dup(oldfd); -} - -uptr internal_dup2(int oldfd, int newfd) { - return dup2(oldfd, newfd); -} - -uptr internal_readlink(const char *path, char *buf, uptr bufsize) { - return readlink(path, buf, bufsize); -} - -uptr internal_unlink(const char *path) { - return unlink(path); -} - -uptr internal_sched_yield() { - return sched_yield(); -} - -void internal__exit(int exitcode) { - _exit(exitcode); -} - -unsigned int internal_sleep(unsigned int seconds) { - return sleep(seconds); -} - -uptr internal_getpid() { - return getpid(); -} - -int internal_sigaction(int signum, const void *act, void *oldact) { - return sigaction(signum, - (const struct sigaction *)act, (struct sigaction *)oldact); -} - -void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); } - -uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, - __sanitizer_sigset_t *oldset) { - // Don't use sigprocmask here, because it affects all threads. - return pthread_sigmask(how, set, oldset); -} - -// Doesn't call pthread_atfork() handlers (but not available on 10.6). -extern "C" pid_t __fork(void) SANITIZER_WEAK_ATTRIBUTE; - -int internal_fork() { - if (&__fork) - return __fork(); - return fork(); -} - -int internal_sysctl(const int *name, unsigned int namelen, void *oldp, - uptr *oldlenp, const void *newp, uptr newlen) { - return sysctl(const_cast(name), namelen, oldp, (size_t *)oldlenp, - const_cast(newp), (size_t)newlen); -} - -int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, - const void *newp, uptr newlen) { - return sysctlbyname(sname, oldp, (size_t *)oldlenp, const_cast(newp), - (size_t)newlen); -} - -int internal_forkpty(int *aparent) { - int parent, worker; - if (openpty(&parent, &worker, nullptr, nullptr, nullptr) == -1) return -1; - int pid = internal_fork(); - if (pid == -1) { - close(parent); - close(worker); - return -1; - } - if (pid == 0) { - close(parent); - if (login_tty(worker) != 0) { - // We already forked, there's not much we can do. Let's quit. - Report("login_tty failed (errno %d)\n", errno); - internal__exit(1); - } - } else { - *aparent = parent; - close(worker); - } - return pid; -} - -uptr internal_rename(const char *oldpath, const char *newpath) { - return rename(oldpath, newpath); -} - -uptr internal_ftruncate(fd_t fd, uptr size) { - return ftruncate(fd, size); -} - -uptr internal_execve(const char *filename, char *const argv[], - char *const envp[]) { - return execve(filename, argv, envp); -} - -uptr internal_waitpid(int pid, int *status, int options) { - return waitpid(pid, status, options); -} - -// ----------------- sanitizer_common.h -bool FileExists(const char *filename) { - if (ShouldMockFailureToOpen(filename)) - return false; - struct stat st; - if (stat(filename, &st)) - return false; - // Sanity check: filename is a regular file. - return S_ISREG(st.st_mode); -} - -tid_t GetTid() { - tid_t tid; - pthread_threadid_np(nullptr, &tid); - return tid; -} - -void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, - uptr *stack_bottom) { - CHECK(stack_top); - CHECK(stack_bottom); - uptr stacksize = pthread_get_stacksize_np(pthread_self()); - // pthread_get_stacksize_np() returns an incorrect stack size for the main - // thread on Mavericks. See - // https://github.com/google/sanitizers/issues/261 - if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization && - stacksize == (1 << 19)) { - struct rlimit rl; - CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0); - // Most often rl.rlim_cur will be the desired 8M. - if (rl.rlim_cur < kMaxThreadStackSize) { - stacksize = rl.rlim_cur; - } else { - stacksize = kMaxThreadStackSize; - } - } - void *stackaddr = pthread_get_stackaddr_np(pthread_self()); - *stack_top = (uptr)stackaddr; - *stack_bottom = *stack_top - stacksize; -} - -char **GetEnviron() { -#if !SANITIZER_IOS - char ***env_ptr = _NSGetEnviron(); - if (!env_ptr) { - Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is " - "called after libSystem_initializer().\n"); - CHECK(env_ptr); - } - char **environ = *env_ptr; -#endif - CHECK(environ); - return environ; -} - -const char *GetEnv(const char *name) { - char **env = GetEnviron(); - uptr name_len = internal_strlen(name); - while (*env != 0) { - uptr len = internal_strlen(*env); - if (len > name_len) { - const char *p = *env; - if (!internal_memcmp(p, name, name_len) && - p[name_len] == '=') { // Match. - return *env + name_len + 1; // String starting after =. - } - } - env++; - } - return 0; -} - -uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { - CHECK_LE(kMaxPathLength, buf_len); - - // On OS X the executable path is saved to the stack by dyld. Reading it - // from there is much faster than calling dladdr, especially for large - // binaries with symbols. - InternalScopedString exe_path(kMaxPathLength); - uint32_t size = exe_path.size(); - if (_NSGetExecutablePath(exe_path.data(), &size) == 0 && - realpath(exe_path.data(), buf) != 0) { - return internal_strlen(buf); - } - return 0; -} - -uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { - return ReadBinaryName(buf, buf_len); -} - -void ReExec() { - UNIMPLEMENTED(); -} - -void CheckASLR() { - // Do nothing -} - -void CheckMPROTECT() { - // Do nothing -} - -uptr GetPageSize() { - return sysconf(_SC_PAGESIZE); -} - -extern "C" unsigned malloc_num_zones; -extern "C" malloc_zone_t **malloc_zones; -malloc_zone_t sanitizer_zone; - -// We need to make sure that sanitizer_zone is registered as malloc_zones[0]. If -// libmalloc tries to set up a different zone as malloc_zones[0], it will call -// mprotect(malloc_zones, ..., PROT_READ). This interceptor will catch that and -// make sure we are still the first (default) zone. -void MprotectMallocZones(void *addr, int prot) { - if (addr == malloc_zones && prot == PROT_READ) { - if (malloc_num_zones > 1 && malloc_zones[0] != &sanitizer_zone) { - for (unsigned i = 1; i < malloc_num_zones; i++) { - if (malloc_zones[i] == &sanitizer_zone) { - // Swap malloc_zones[0] and malloc_zones[i]. - malloc_zones[i] = malloc_zones[0]; - malloc_zones[0] = &sanitizer_zone; - break; - } - } - } - } -} - -BlockingMutex::BlockingMutex() { - internal_memset(this, 0, sizeof(*this)); -} - -void BlockingMutex::Lock() { - CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_)); - CHECK_EQ(OS_SPINLOCK_INIT, 0); - CHECK_EQ(owner_, 0); - OSSpinLockLock((OSSpinLock*)&opaque_storage_); -} - -void BlockingMutex::Unlock() { - OSSpinLockUnlock((OSSpinLock*)&opaque_storage_); -} - -void BlockingMutex::CheckLocked() { - CHECK_NE(*(OSSpinLock*)&opaque_storage_, 0); -} - -u64 NanoTime() { - timeval tv; - internal_memset(&tv, 0, sizeof(tv)); - gettimeofday(&tv, 0); - return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000; -} - -// This needs to be called during initialization to avoid being racy. -u64 MonotonicNanoTime() { - static mach_timebase_info_data_t timebase_info; - if (timebase_info.denom == 0) mach_timebase_info(&timebase_info); - return (mach_absolute_time() * timebase_info.numer) / timebase_info.denom; -} - -uptr GetTlsSize() { - return 0; -} - -void InitTlsSize() { -} - -uptr TlsBaseAddr() { - uptr segbase = 0; -#if defined(__x86_64__) - asm("movq %%gs:0,%0" : "=r"(segbase)); -#elif defined(__i386__) - asm("movl %%gs:0,%0" : "=r"(segbase)); -#endif - return segbase; -} - -// The size of the tls on darwin does not appear to be well documented, -// however the vm memory map suggests that it is 1024 uptrs in size, -// with a size of 0x2000 bytes on x86_64 and 0x1000 bytes on i386. -uptr TlsSize() { -#if defined(__x86_64__) || defined(__i386__) - return 1024 * sizeof(uptr); -#else - return 0; -#endif -} - -void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, - uptr *tls_addr, uptr *tls_size) { -#if !SANITIZER_GO - uptr stack_top, stack_bottom; - GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); - *stk_addr = stack_bottom; - *stk_size = stack_top - stack_bottom; - *tls_addr = TlsBaseAddr(); - *tls_size = TlsSize(); -#else - *stk_addr = 0; - *stk_size = 0; - *tls_addr = 0; - *tls_size = 0; -#endif -} - -void ListOfModules::init() { - clearOrInit(); - MemoryMappingLayout memory_mapping(false); - memory_mapping.DumpListOfModules(&modules_); -} - -void ListOfModules::fallbackInit() { clear(); } - -static HandleSignalMode GetHandleSignalModeImpl(int signum) { - switch (signum) { - case SIGABRT: - return common_flags()->handle_abort; - case SIGILL: - return common_flags()->handle_sigill; - case SIGTRAP: - return common_flags()->handle_sigtrap; - case SIGFPE: - return common_flags()->handle_sigfpe; - case SIGSEGV: - return common_flags()->handle_segv; - case SIGBUS: - return common_flags()->handle_sigbus; - } - return kHandleSignalNo; -} - -HandleSignalMode GetHandleSignalMode(int signum) { - // Handling fatal signals on watchOS and tvOS devices is disallowed. - if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM)) - return kHandleSignalNo; - HandleSignalMode result = GetHandleSignalModeImpl(signum); - if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler) - return kHandleSignalExclusive; - return result; -} - -MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED; - -MacosVersion GetMacosVersionInternal() { - int mib[2] = { CTL_KERN, KERN_OSRELEASE }; - char version[100]; - uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]); - for (uptr i = 0; i < maxlen; i++) version[i] = '\0'; - // Get the version length. - CHECK_NE(internal_sysctl(mib, 2, 0, &len, 0, 0), -1); - CHECK_LT(len, maxlen); - CHECK_NE(internal_sysctl(mib, 2, version, &len, 0, 0), -1); - - // Expect .(.) - CHECK_GE(len, 3); - const char *p = version; - int major = internal_simple_strtoll(p, &p, /*base=*/10); - if (*p != '.') return MACOS_VERSION_UNKNOWN; - p += 1; - int minor = internal_simple_strtoll(p, &p, /*base=*/10); - if (*p != '.') return MACOS_VERSION_UNKNOWN; - - switch (major) { - case 9: return MACOS_VERSION_LEOPARD; - case 10: return MACOS_VERSION_SNOW_LEOPARD; - case 11: return MACOS_VERSION_LION; - case 12: return MACOS_VERSION_MOUNTAIN_LION; - case 13: return MACOS_VERSION_MAVERICKS; - case 14: return MACOS_VERSION_YOSEMITE; - case 15: return MACOS_VERSION_EL_CAPITAN; - case 16: return MACOS_VERSION_SIERRA; - case 17: - // Not a typo, 17.5 Darwin Kernel Version maps to High Sierra 10.13.4. - if (minor >= 5) - return MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4; - return MACOS_VERSION_HIGH_SIERRA; - case 18: return MACOS_VERSION_MOJAVE; - case 19: return MACOS_VERSION_CATALINA; - default: - if (major < 9) return MACOS_VERSION_UNKNOWN; - return MACOS_VERSION_UNKNOWN_NEWER; - } -} - -MacosVersion GetMacosVersion() { - atomic_uint32_t *cache = - reinterpret_cast(&cached_macos_version); - MacosVersion result = - static_cast(atomic_load(cache, memory_order_acquire)); - if (result == MACOS_VERSION_UNINITIALIZED) { - result = GetMacosVersionInternal(); - atomic_store(cache, result, memory_order_release); - } - return result; -} - -bool PlatformHasDifferentMemcpyAndMemmove() { - // On OS X 10.7 memcpy() and memmove() are both resolved - // into memmove$VARIANT$sse42. - // See also https://github.com/google/sanitizers/issues/34. - // TODO(glider): need to check dynamically that memcpy() and memmove() are - // actually the same function. - return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD; -} - -uptr GetRSS() { - struct task_basic_info info; - unsigned count = TASK_BASIC_INFO_COUNT; - kern_return_t result = - task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count); - if (UNLIKELY(result != KERN_SUCCESS)) { - Report("Cannot get task info. Error: %d\n", result); - Die(); - } - return info.resident_size; -} - -void *internal_start_thread(void(*func)(void *arg), void *arg) { - // Start the thread with signals blocked, otherwise it can steal user signals. - __sanitizer_sigset_t set, old; - internal_sigfillset(&set); - internal_sigprocmask(SIG_SETMASK, &set, &old); - pthread_t th; - pthread_create(&th, 0, (void*(*)(void *arg))func, arg); - internal_sigprocmask(SIG_SETMASK, &old, 0); - return th; -} - -void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); } - -#if !SANITIZER_GO -static BlockingMutex syslog_lock(LINKER_INITIALIZED); -#endif - -void WriteOneLineToSyslog(const char *s) { -#if !SANITIZER_GO - syslog_lock.CheckLocked(); - asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s); -#endif -} - -void LogMessageOnPrintf(const char *str) { - // Log all printf output to CrashLog. - if (common_flags()->abort_on_error) - CRAppendCrashLogMessage(str); -} - -void LogFullErrorReport(const char *buffer) { -#if !SANITIZER_GO - // Log with os_trace. This will make it into the crash log. -#if SANITIZER_OS_TRACE - if (GetMacosVersion() >= MACOS_VERSION_YOSEMITE) { - // os_trace requires the message (format parameter) to be a string literal. - if (internal_strncmp(SanitizerToolName, "AddressSanitizer", - sizeof("AddressSanitizer") - 1) == 0) - os_trace("Address Sanitizer reported a failure."); - else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer", - sizeof("UndefinedBehaviorSanitizer") - 1) == 0) - os_trace("Undefined Behavior Sanitizer reported a failure."); - else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer", - sizeof("ThreadSanitizer") - 1) == 0) - os_trace("Thread Sanitizer reported a failure."); - else - os_trace("Sanitizer tool reported a failure."); - - if (common_flags()->log_to_syslog) - os_trace("Consult syslog for more information."); - } -#endif - - // Log to syslog. - // The logging on OS X may call pthread_create so we need the threading - // environment to be fully initialized. Also, this should never be called when - // holding the thread registry lock since that may result in a deadlock. If - // the reporting thread holds the thread registry mutex, and asl_log waits - // for GCD to dispatch a new thread, the process will deadlock, because the - // pthread_create wrapper needs to acquire the lock as well. - BlockingMutexLock l(&syslog_lock); - if (common_flags()->log_to_syslog) - WriteToSyslog(buffer); - - // The report is added to CrashLog as part of logging all of Printf output. -#endif -} - -SignalContext::WriteFlag SignalContext::GetWriteFlag() const { -#if defined(__x86_64__) || defined(__i386__) - ucontext_t *ucontext = static_cast(context); - return ucontext->uc_mcontext->__es.__err & 2 /*T_PF_WRITE*/ ? WRITE : READ; -#else - return UNKNOWN; -#endif -} - -static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { - ucontext_t *ucontext = (ucontext_t*)context; -# if defined(__aarch64__) - *pc = ucontext->uc_mcontext->__ss.__pc; -# if defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0 - *bp = ucontext->uc_mcontext->__ss.__fp; -# else - *bp = ucontext->uc_mcontext->__ss.__lr; -# endif - *sp = ucontext->uc_mcontext->__ss.__sp; -# elif defined(__x86_64__) - *pc = ucontext->uc_mcontext->__ss.__rip; - *bp = ucontext->uc_mcontext->__ss.__rbp; - *sp = ucontext->uc_mcontext->__ss.__rsp; -# elif defined(__arm__) - *pc = ucontext->uc_mcontext->__ss.__pc; - *bp = ucontext->uc_mcontext->__ss.__r[7]; - *sp = ucontext->uc_mcontext->__ss.__sp; -# elif defined(__i386__) - *pc = ucontext->uc_mcontext->__ss.__eip; - *bp = ucontext->uc_mcontext->__ss.__ebp; - *sp = ucontext->uc_mcontext->__ss.__esp; -# else -# error "Unknown architecture" -# endif -} - -void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } - -void InitializePlatformEarly() { - // Only use xnu_fast_mmap when on x86_64 and the OS supports it. - use_xnu_fast_mmap = -#if defined(__x86_64__) - GetMacosVersion() >= MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4; -#else - false; -#endif -} - -#if !SANITIZER_GO -static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES"; -LowLevelAllocator allocator_for_env; - -// Change the value of the env var |name|, leaking the original value. -// If |name_value| is NULL, the variable is deleted from the environment, -// otherwise the corresponding "NAME=value" string is replaced with -// |name_value|. -void LeakyResetEnv(const char *name, const char *name_value) { - char **env = GetEnviron(); - uptr name_len = internal_strlen(name); - while (*env != 0) { - uptr len = internal_strlen(*env); - if (len > name_len) { - const char *p = *env; - if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') { - // Match. - if (name_value) { - // Replace the old value with the new one. - *env = const_cast(name_value); - } else { - // Shift the subsequent pointers back. - char **del = env; - do { - del[0] = del[1]; - } while (*del++); - } - } - } - env++; - } -} - -SANITIZER_WEAK_CXX_DEFAULT_IMPL -bool ReexecDisabled() { - return false; -} - -extern "C" SANITIZER_WEAK_ATTRIBUTE double dyldVersionNumber; -static const double kMinDyldVersionWithAutoInterposition = 360.0; - -bool DyldNeedsEnvVariable() { - // Although sanitizer support was added to LLVM on OS X 10.7+, GCC users - // still may want use them on older systems. On older Darwin platforms, dyld - // doesn't export dyldVersionNumber symbol and we simply return true. - if (!&dyldVersionNumber) return true; - // If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if - // DYLD_INSERT_LIBRARIES is not set. However, checking OS version via - // GetMacosVersion() doesn't work for the simulator. Let's instead check - // `dyldVersionNumber`, which is exported by dyld, against a known version - // number from the first OS release where this appeared. - return dyldVersionNumber < kMinDyldVersionWithAutoInterposition; -} - -void MaybeReexec() { - // FIXME: This should really live in some "InitializePlatform" method. - MonotonicNanoTime(); - - if (ReexecDisabled()) return; - - // Make sure the dynamic runtime library is preloaded so that the - // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec - // ourselves. - Dl_info info; - RAW_CHECK(dladdr((void*)((uptr)&__sanitizer_report_error_summary), &info)); - char *dyld_insert_libraries = - const_cast(GetEnv(kDyldInsertLibraries)); - uptr old_env_len = dyld_insert_libraries ? - internal_strlen(dyld_insert_libraries) : 0; - uptr fname_len = internal_strlen(info.dli_fname); - const char *dylib_name = StripModuleName(info.dli_fname); - uptr dylib_name_len = internal_strlen(dylib_name); - - bool lib_is_in_env = dyld_insert_libraries && - internal_strstr(dyld_insert_libraries, dylib_name); - if (DyldNeedsEnvVariable() && !lib_is_in_env) { - // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime - // library. - InternalScopedString program_name(1024); - uint32_t buf_size = program_name.size(); - _NSGetExecutablePath(program_name.data(), &buf_size); - char *new_env = const_cast(info.dli_fname); - if (dyld_insert_libraries) { - // Append the runtime dylib name to the existing value of - // DYLD_INSERT_LIBRARIES. - new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2); - internal_strncpy(new_env, dyld_insert_libraries, old_env_len); - new_env[old_env_len] = ':'; - // Copy fname_len and add a trailing zero. - internal_strncpy(new_env + old_env_len + 1, info.dli_fname, - fname_len + 1); - // Ok to use setenv() since the wrappers don't depend on the value of - // asan_inited. - setenv(kDyldInsertLibraries, new_env, /*overwrite*/1); - } else { - // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name. - setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0); - } - VReport(1, "exec()-ing the program with\n"); - VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env); - VReport(1, "to enable wrappers.\n"); - execv(program_name.data(), *_NSGetArgv()); - - // We get here only if execv() failed. - Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, " - "which is required for the sanitizer to work. We tried to set the " - "environment variable and re-execute itself, but execv() failed, " - "possibly because of sandbox restrictions. Make sure to launch the " - "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env); - RAW_CHECK("execv failed" && 0); - } - - // Verify that interceptors really work. We'll use dlsym to locate - // "pthread_create", if interceptors are working, it should really point to - // "wrap_pthread_create" within our own dylib. - Dl_info info_pthread_create; - void *dlopen_addr = dlsym(RTLD_DEFAULT, "pthread_create"); - RAW_CHECK(dladdr(dlopen_addr, &info_pthread_create)); - if (internal_strcmp(info.dli_fname, info_pthread_create.dli_fname) != 0) { - Report( - "ERROR: Interceptors are not working. This may be because %s is " - "loaded too late (e.g. via dlopen). Please launch the executable " - "with:\n%s=%s\n", - SanitizerToolName, kDyldInsertLibraries, info.dli_fname); - RAW_CHECK("interceptors not installed" && 0); - } - - if (!lib_is_in_env) - return; - - if (!common_flags()->strip_env) - return; - - // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove - // the dylib from the environment variable, because interceptors are installed - // and we don't want our children to inherit the variable. - - uptr env_name_len = internal_strlen(kDyldInsertLibraries); - // Allocate memory to hold the previous env var name, its value, the '=' - // sign and the '\0' char. - char *new_env = (char*)allocator_for_env.Allocate( - old_env_len + 2 + env_name_len); - RAW_CHECK(new_env); - internal_memset(new_env, '\0', old_env_len + 2 + env_name_len); - internal_strncpy(new_env, kDyldInsertLibraries, env_name_len); - new_env[env_name_len] = '='; - char *new_env_pos = new_env + env_name_len + 1; - - // Iterate over colon-separated pieces of |dyld_insert_libraries|. - char *piece_start = dyld_insert_libraries; - char *piece_end = NULL; - char *old_env_end = dyld_insert_libraries + old_env_len; - do { - if (piece_start[0] == ':') piece_start++; - piece_end = internal_strchr(piece_start, ':'); - if (!piece_end) piece_end = dyld_insert_libraries + old_env_len; - if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break; - uptr piece_len = piece_end - piece_start; - - char *filename_start = - (char *)internal_memrchr(piece_start, '/', piece_len); - uptr filename_len = piece_len; - if (filename_start) { - filename_start += 1; - filename_len = piece_len - (filename_start - piece_start); - } else { - filename_start = piece_start; - } - - // If the current piece isn't the runtime library name, - // append it to new_env. - if ((dylib_name_len != filename_len) || - (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) { - if (new_env_pos != new_env + env_name_len + 1) { - new_env_pos[0] = ':'; - new_env_pos++; - } - internal_strncpy(new_env_pos, piece_start, piece_len); - new_env_pos += piece_len; - } - // Move on to the next piece. - piece_start = piece_end; - } while (piece_start < old_env_end); - - // Can't use setenv() here, because it requires the allocator to be - // initialized. - // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in - // a separate function called after InitializeAllocator(). - if (new_env_pos == new_env + env_name_len + 1) new_env = NULL; - LeakyResetEnv(kDyldInsertLibraries, new_env); -} -#endif // SANITIZER_GO - -char **GetArgv() { - return *_NSGetArgv(); -} - -#if SANITIZER_IOS -// The task_vm_info struct is normally provided by the macOS SDK, but we need -// fields only available in 10.12+. Declare the struct manually to be able to -// build against older SDKs. -struct __sanitizer_task_vm_info { - mach_vm_size_t virtual_size; - integer_t region_count; - integer_t page_size; - mach_vm_size_t resident_size; - mach_vm_size_t resident_size_peak; - mach_vm_size_t device; - mach_vm_size_t device_peak; - mach_vm_size_t internal; - mach_vm_size_t internal_peak; - mach_vm_size_t external; - mach_vm_size_t external_peak; - mach_vm_size_t reusable; - mach_vm_size_t reusable_peak; - mach_vm_size_t purgeable_volatile_pmap; - mach_vm_size_t purgeable_volatile_resident; - mach_vm_size_t purgeable_volatile_virtual; - mach_vm_size_t compressed; - mach_vm_size_t compressed_peak; - mach_vm_size_t compressed_lifetime; - mach_vm_size_t phys_footprint; - mach_vm_address_t min_address; - mach_vm_address_t max_address; -}; -#define __SANITIZER_TASK_VM_INFO_COUNT ((mach_msg_type_number_t) \ - (sizeof(__sanitizer_task_vm_info) / sizeof(natural_t))) - -static uptr GetTaskInfoMaxAddress() { - __sanitizer_task_vm_info vm_info = {} /* zero initialize */; - mach_msg_type_number_t count = __SANITIZER_TASK_VM_INFO_COUNT; - int err = task_info(mach_task_self(), TASK_VM_INFO, (int *)&vm_info, &count); - return err ? 0 : vm_info.max_address; -} - -uptr GetMaxUserVirtualAddress() { - static uptr max_vm = GetTaskInfoMaxAddress(); - if (max_vm != 0) - return max_vm - 1; - - // xnu cannot provide vm address limit -# if SANITIZER_WORDSIZE == 32 - return 0xffe00000 - 1; -# else - return 0x200000000 - 1; -# endif -} - -#else // !SANITIZER_IOS - -uptr GetMaxUserVirtualAddress() { -# if SANITIZER_WORDSIZE == 64 - return (1ULL << 47) - 1; // 0x00007fffffffffffUL; -# else // SANITIZER_WORDSIZE == 32 - static_assert(SANITIZER_WORDSIZE == 32, "Wrong wordsize"); - return (1ULL << 32) - 1; // 0xffffffff; -# endif -} -#endif - -uptr GetMaxVirtualAddress() { - return GetMaxUserVirtualAddress(); -} - -uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, - uptr *largest_gap_found, - uptr *max_occupied_addr) { - typedef vm_region_submap_short_info_data_64_t RegionInfo; - enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 }; - // Start searching for available memory region past PAGEZERO, which is - // 4KB on 32-bit and 4GB on 64-bit. - mach_vm_address_t start_address = - (SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000; - - mach_vm_address_t address = start_address; - mach_vm_address_t free_begin = start_address; - kern_return_t kr = KERN_SUCCESS; - if (largest_gap_found) *largest_gap_found = 0; - if (max_occupied_addr) *max_occupied_addr = 0; - while (kr == KERN_SUCCESS) { - mach_vm_size_t vmsize = 0; - natural_t depth = 0; - RegionInfo vminfo; - mach_msg_type_number_t count = kRegionInfoSize; - kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth, - (vm_region_info_t)&vminfo, &count); - if (kr == KERN_INVALID_ADDRESS) { - // No more regions beyond "address", consider the gap at the end of VM. - address = GetMaxVirtualAddress() + 1; - vmsize = 0; - } else { - if (max_occupied_addr) *max_occupied_addr = address + vmsize; - } - if (free_begin != address) { - // We found a free region [free_begin..address-1]. - uptr gap_start = RoundUpTo((uptr)free_begin + left_padding, alignment); - uptr gap_end = RoundDownTo((uptr)address, alignment); - uptr gap_size = gap_end > gap_start ? gap_end - gap_start : 0; - if (size < gap_size) { - return gap_start; - } - - if (largest_gap_found && *largest_gap_found < gap_size) { - *largest_gap_found = gap_size; - } - } - // Move to the next region. - address += vmsize; - free_begin = address; - } - - // We looked at all free regions and could not find one large enough. - return 0; -} - -// FIXME implement on this platform. -void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { } - -void SignalContext::DumpAllRegisters(void *context) { - Report("Register values:\n"); - - ucontext_t *ucontext = (ucontext_t*)context; -# define DUMPREG64(r) \ - Printf("%s = 0x%016llx ", #r, ucontext->uc_mcontext->__ss.__ ## r); -# define DUMPREG32(r) \ - Printf("%s = 0x%08x ", #r, ucontext->uc_mcontext->__ss.__ ## r); -# define DUMPREG_(r) Printf(" "); DUMPREG(r); -# define DUMPREG__(r) Printf(" "); DUMPREG(r); -# define DUMPREG___(r) Printf(" "); DUMPREG(r); - -# if defined(__x86_64__) -# define DUMPREG(r) DUMPREG64(r) - DUMPREG(rax); DUMPREG(rbx); DUMPREG(rcx); DUMPREG(rdx); Printf("\n"); - DUMPREG(rdi); DUMPREG(rsi); DUMPREG(rbp); DUMPREG(rsp); Printf("\n"); - DUMPREG_(r8); DUMPREG_(r9); DUMPREG(r10); DUMPREG(r11); Printf("\n"); - DUMPREG(r12); DUMPREG(r13); DUMPREG(r14); DUMPREG(r15); Printf("\n"); -# elif defined(__i386__) -# define DUMPREG(r) DUMPREG32(r) - DUMPREG(eax); DUMPREG(ebx); DUMPREG(ecx); DUMPREG(edx); Printf("\n"); - DUMPREG(edi); DUMPREG(esi); DUMPREG(ebp); DUMPREG(esp); Printf("\n"); -# elif defined(__aarch64__) -# define DUMPREG(r) DUMPREG64(r) - DUMPREG_(x[0]); DUMPREG_(x[1]); DUMPREG_(x[2]); DUMPREG_(x[3]); Printf("\n"); - DUMPREG_(x[4]); DUMPREG_(x[5]); DUMPREG_(x[6]); DUMPREG_(x[7]); Printf("\n"); - DUMPREG_(x[8]); DUMPREG_(x[9]); DUMPREG(x[10]); DUMPREG(x[11]); Printf("\n"); - DUMPREG(x[12]); DUMPREG(x[13]); DUMPREG(x[14]); DUMPREG(x[15]); Printf("\n"); - DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]); Printf("\n"); - DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]); Printf("\n"); - DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]); Printf("\n"); - DUMPREG(x[28]); DUMPREG___(fp); DUMPREG___(lr); DUMPREG___(sp); Printf("\n"); -# elif defined(__arm__) -# define DUMPREG(r) DUMPREG32(r) - DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]); Printf("\n"); - DUMPREG_(r[4]); DUMPREG_(r[5]); DUMPREG_(r[6]); DUMPREG_(r[7]); Printf("\n"); - DUMPREG_(r[8]); DUMPREG_(r[9]); DUMPREG(r[10]); DUMPREG(r[11]); Printf("\n"); - DUMPREG(r[12]); DUMPREG___(sp); DUMPREG___(lr); DUMPREG___(pc); Printf("\n"); -# else -# error "Unknown architecture" -# endif - -# undef DUMPREG64 -# undef DUMPREG32 -# undef DUMPREG_ -# undef DUMPREG__ -# undef DUMPREG___ -# undef DUMPREG -} - -static inline bool CompareBaseAddress(const LoadedModule &a, - const LoadedModule &b) { - return a.base_address() < b.base_address(); -} - -void FormatUUID(char *out, uptr size, const u8 *uuid) { - internal_snprintf(out, size, - "<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-" - "%02X%02X%02X%02X%02X%02X>", - uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], - uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], - uuid[12], uuid[13], uuid[14], uuid[15]); -} - -void PrintModuleMap() { - Printf("Process module map:\n"); - MemoryMappingLayout memory_mapping(false); - InternalMmapVector modules; - modules.reserve(128); - memory_mapping.DumpListOfModules(&modules); - Sort(modules.data(), modules.size(), CompareBaseAddress); - for (uptr i = 0; i < modules.size(); ++i) { - char uuid_str[128]; - FormatUUID(uuid_str, sizeof(uuid_str), modules[i].uuid()); - Printf("0x%zx-0x%zx %s (%s) %s\n", modules[i].base_address(), - modules[i].max_executable_address(), modules[i].full_name(), - ModuleArchToString(modules[i].arch()), uuid_str); - } - Printf("End of module map.\n"); -} - -void CheckNoDeepBind(const char *filename, int flag) { - // Do nothing. -} - -bool GetRandom(void *buffer, uptr length, bool blocking) { - if (!buffer || !length || length > 256) - return false; - // arc4random never fails. - arc4random_buf(buffer, length); - return true; -} - -u32 GetNumberOfCPUs() { - return (u32)sysconf(_SC_NPROCESSORS_ONLN); -} - -} // namespace __sanitizer - -#endif // SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_mac.cpp b/lib/sanitizer_common/sanitizer_mac.cpp new file mode 100644 index 000000000000..ea4bd02aa92e --- /dev/null +++ b/lib/sanitizer_common/sanitizer_mac.cpp @@ -0,0 +1,1219 @@ +//===-- sanitizer_mac.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries and +// implements OSX-specific functions. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_MAC +#include "sanitizer_mac.h" +#include "interception/interception.h" + +// Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so +// the clients will most certainly use 64-bit ones as well. +#ifndef _DARWIN_USE_64_BIT_INODE +#define _DARWIN_USE_64_BIT_INODE 1 +#endif +#include + +#include "sanitizer_common.h" +#include "sanitizer_file.h" +#include "sanitizer_flags.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_platform_limits_posix.h" +#include "sanitizer_procmaps.h" + +#if !SANITIZER_IOS +#include // for _NSGetEnviron +#else +extern char **environ; +#endif + +#if defined(__has_include) && __has_include() +#define SANITIZER_OS_TRACE 1 +#include +#else +#define SANITIZER_OS_TRACE 0 +#endif + +#if !SANITIZER_IOS +#include // for _NSGetArgv and _NSGetEnviron +#else +extern "C" { + extern char ***_NSGetArgv(void); +} +#endif + +#include +#include // for dladdr() +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// From , but we don't have that file on iOS. +extern "C" { + extern char ***_NSGetArgv(void); + extern char ***_NSGetEnviron(void); +} + +// From , but we don't have that file on iOS. +extern "C" { + extern kern_return_t mach_vm_region_recurse( + vm_map_t target_task, + mach_vm_address_t *address, + mach_vm_size_t *size, + natural_t *nesting_depth, + vm_region_recurse_info_t info, + mach_msg_type_number_t *infoCnt); +} + +namespace __sanitizer { + +#include "sanitizer_syscall_generic.inc" + +// Direct syscalls, don't call libmalloc hooks (but not available on 10.6). +extern "C" void *__mmap(void *addr, size_t len, int prot, int flags, int fildes, + off_t off) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int __munmap(void *, size_t) SANITIZER_WEAK_ATTRIBUTE; + +// ---------------------- sanitizer_libc.h + +// From , but not on older OSs. +#ifndef VM_MEMORY_SANITIZER +#define VM_MEMORY_SANITIZER 99 +#endif + +// XNU on Darwin provides a mmap flag that optimizes allocation/deallocation of +// giant memory regions (i.e. shadow memory regions). +#define kXnuFastMmapFd 0x4 +static size_t kXnuFastMmapThreshold = 2 << 30; // 2 GB +static bool use_xnu_fast_mmap = false; + +uptr internal_mmap(void *addr, size_t length, int prot, int flags, + int fd, u64 offset) { + if (fd == -1) { + fd = VM_MAKE_TAG(VM_MEMORY_SANITIZER); + if (length >= kXnuFastMmapThreshold) { + if (use_xnu_fast_mmap) fd |= kXnuFastMmapFd; + } + } + if (&__mmap) return (uptr)__mmap(addr, length, prot, flags, fd, offset); + return (uptr)mmap(addr, length, prot, flags, fd, offset); +} + +uptr internal_munmap(void *addr, uptr length) { + if (&__munmap) return __munmap(addr, length); + return munmap(addr, length); +} + +int internal_mprotect(void *addr, uptr length, int prot) { + return mprotect(addr, length, prot); +} + +uptr internal_close(fd_t fd) { + return close(fd); +} + +uptr internal_open(const char *filename, int flags) { + return open(filename, flags); +} + +uptr internal_open(const char *filename, int flags, u32 mode) { + return open(filename, flags, mode); +} + +uptr internal_read(fd_t fd, void *buf, uptr count) { + return read(fd, buf, count); +} + +uptr internal_write(fd_t fd, const void *buf, uptr count) { + return write(fd, buf, count); +} + +uptr internal_stat(const char *path, void *buf) { + return stat(path, (struct stat *)buf); +} + +uptr internal_lstat(const char *path, void *buf) { + return lstat(path, (struct stat *)buf); +} + +uptr internal_fstat(fd_t fd, void *buf) { + return fstat(fd, (struct stat *)buf); +} + +uptr internal_filesize(fd_t fd) { + struct stat st; + if (internal_fstat(fd, &st)) + return -1; + return (uptr)st.st_size; +} + +uptr internal_dup(int oldfd) { + return dup(oldfd); +} + +uptr internal_dup2(int oldfd, int newfd) { + return dup2(oldfd, newfd); +} + +uptr internal_readlink(const char *path, char *buf, uptr bufsize) { + return readlink(path, buf, bufsize); +} + +uptr internal_unlink(const char *path) { + return unlink(path); +} + +uptr internal_sched_yield() { + return sched_yield(); +} + +void internal__exit(int exitcode) { + _exit(exitcode); +} + +unsigned int internal_sleep(unsigned int seconds) { + return sleep(seconds); +} + +uptr internal_getpid() { + return getpid(); +} + +int internal_sigaction(int signum, const void *act, void *oldact) { + return sigaction(signum, + (const struct sigaction *)act, (struct sigaction *)oldact); +} + +void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); } + +uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset) { + // Don't use sigprocmask here, because it affects all threads. + return pthread_sigmask(how, set, oldset); +} + +// Doesn't call pthread_atfork() handlers (but not available on 10.6). +extern "C" pid_t __fork(void) SANITIZER_WEAK_ATTRIBUTE; + +int internal_fork() { + if (&__fork) + return __fork(); + return fork(); +} + +int internal_sysctl(const int *name, unsigned int namelen, void *oldp, + uptr *oldlenp, const void *newp, uptr newlen) { + return sysctl(const_cast(name), namelen, oldp, (size_t *)oldlenp, + const_cast(newp), (size_t)newlen); +} + +int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, + const void *newp, uptr newlen) { + return sysctlbyname(sname, oldp, (size_t *)oldlenp, const_cast(newp), + (size_t)newlen); +} + +static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) { + fd_t master_fd = kInvalidFd; + fd_t slave_fd = kInvalidFd; + + auto fd_closer = at_scope_exit([&] { + internal_close(master_fd); + internal_close(slave_fd); + }); + + // We need a new pseudoterminal to avoid buffering problems. The 'atos' tool + // in particular detects when it's talking to a pipe and forgets to flush the + // output stream after sending a response. + master_fd = posix_openpt(O_RDWR); + if (master_fd == kInvalidFd) return kInvalidFd; + + int res = grantpt(master_fd) || unlockpt(master_fd); + if (res != 0) return kInvalidFd; + + // Use TIOCPTYGNAME instead of ptsname() to avoid threading problems. + char slave_pty_name[128]; + res = ioctl(master_fd, TIOCPTYGNAME, slave_pty_name); + if (res == -1) return kInvalidFd; + + slave_fd = internal_open(slave_pty_name, O_RDWR); + if (slave_fd == kInvalidFd) return kInvalidFd; + + // File descriptor actions + posix_spawn_file_actions_t acts; + res = posix_spawn_file_actions_init(&acts); + if (res != 0) return kInvalidFd; + + auto acts_cleanup = at_scope_exit([&] { + posix_spawn_file_actions_destroy(&acts); + }); + + res = posix_spawn_file_actions_adddup2(&acts, slave_fd, STDIN_FILENO) || + posix_spawn_file_actions_adddup2(&acts, slave_fd, STDOUT_FILENO) || + posix_spawn_file_actions_addclose(&acts, slave_fd); + if (res != 0) return kInvalidFd; + + // Spawn attributes + posix_spawnattr_t attrs; + res = posix_spawnattr_init(&attrs); + if (res != 0) return kInvalidFd; + + auto attrs_cleanup = at_scope_exit([&] { + posix_spawnattr_destroy(&attrs); + }); + + // In the spawned process, close all file descriptors that are not explicitly + // described by the file actions object. This is Darwin-specific extension. + res = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_CLOEXEC_DEFAULT); + if (res != 0) return kInvalidFd; + + // posix_spawn + char **argv_casted = const_cast(argv); + char **env = GetEnviron(); + res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, env); + if (res != 0) return kInvalidFd; + + // Disable echo in the new terminal, disable CR. + struct termios termflags; + tcgetattr(master_fd, &termflags); + termflags.c_oflag &= ~ONLCR; + termflags.c_lflag &= ~ECHO; + tcsetattr(master_fd, TCSANOW, &termflags); + + // On success, do not close master_fd on scope exit. + fd_t fd = master_fd; + master_fd = kInvalidFd; + + return fd; +} + +fd_t internal_spawn(const char *argv[], pid_t *pid) { + // The client program may close its stdin and/or stdout and/or stderr thus + // allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this + // case the communication is broken if either the parent or the child tries to + // close or duplicate these descriptors. We temporarily reserve these + // descriptors here to prevent this. + fd_t low_fds[3]; + size_t count = 0; + + for (; count < 3; count++) { + low_fds[count] = posix_openpt(O_RDWR); + if (low_fds[count] >= STDERR_FILENO) + break; + } + + fd_t fd = internal_spawn_impl(argv, pid); + + for (; count > 0; count--) { + internal_close(low_fds[count]); + } + + return fd; +} + +uptr internal_rename(const char *oldpath, const char *newpath) { + return rename(oldpath, newpath); +} + +uptr internal_ftruncate(fd_t fd, uptr size) { + return ftruncate(fd, size); +} + +uptr internal_execve(const char *filename, char *const argv[], + char *const envp[]) { + return execve(filename, argv, envp); +} + +uptr internal_waitpid(int pid, int *status, int options) { + return waitpid(pid, status, options); +} + +// ----------------- sanitizer_common.h +bool FileExists(const char *filename) { + if (ShouldMockFailureToOpen(filename)) + return false; + struct stat st; + if (stat(filename, &st)) + return false; + // Sanity check: filename is a regular file. + return S_ISREG(st.st_mode); +} + +tid_t GetTid() { + tid_t tid; + pthread_threadid_np(nullptr, &tid); + return tid; +} + +void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, + uptr *stack_bottom) { + CHECK(stack_top); + CHECK(stack_bottom); + uptr stacksize = pthread_get_stacksize_np(pthread_self()); + // pthread_get_stacksize_np() returns an incorrect stack size for the main + // thread on Mavericks. See + // https://github.com/google/sanitizers/issues/261 + if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization && + stacksize == (1 << 19)) { + struct rlimit rl; + CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0); + // Most often rl.rlim_cur will be the desired 8M. + if (rl.rlim_cur < kMaxThreadStackSize) { + stacksize = rl.rlim_cur; + } else { + stacksize = kMaxThreadStackSize; + } + } + void *stackaddr = pthread_get_stackaddr_np(pthread_self()); + *stack_top = (uptr)stackaddr; + *stack_bottom = *stack_top - stacksize; +} + +char **GetEnviron() { +#if !SANITIZER_IOS + char ***env_ptr = _NSGetEnviron(); + if (!env_ptr) { + Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is " + "called after libSystem_initializer().\n"); + CHECK(env_ptr); + } + char **environ = *env_ptr; +#endif + CHECK(environ); + return environ; +} + +const char *GetEnv(const char *name) { + char **env = GetEnviron(); + uptr name_len = internal_strlen(name); + while (*env != 0) { + uptr len = internal_strlen(*env); + if (len > name_len) { + const char *p = *env; + if (!internal_memcmp(p, name, name_len) && + p[name_len] == '=') { // Match. + return *env + name_len + 1; // String starting after =. + } + } + env++; + } + return 0; +} + +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { + CHECK_LE(kMaxPathLength, buf_len); + + // On OS X the executable path is saved to the stack by dyld. Reading it + // from there is much faster than calling dladdr, especially for large + // binaries with symbols. + InternalScopedString exe_path(kMaxPathLength); + uint32_t size = exe_path.size(); + if (_NSGetExecutablePath(exe_path.data(), &size) == 0 && + realpath(exe_path.data(), buf) != 0) { + return internal_strlen(buf); + } + return 0; +} + +uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { + return ReadBinaryName(buf, buf_len); +} + +void ReExec() { + UNIMPLEMENTED(); +} + +void CheckASLR() { + // Do nothing +} + +void CheckMPROTECT() { + // Do nothing +} + +uptr GetPageSize() { + return sysconf(_SC_PAGESIZE); +} + +extern "C" unsigned malloc_num_zones; +extern "C" malloc_zone_t **malloc_zones; +malloc_zone_t sanitizer_zone; + +// We need to make sure that sanitizer_zone is registered as malloc_zones[0]. If +// libmalloc tries to set up a different zone as malloc_zones[0], it will call +// mprotect(malloc_zones, ..., PROT_READ). This interceptor will catch that and +// make sure we are still the first (default) zone. +void MprotectMallocZones(void *addr, int prot) { + if (addr == malloc_zones && prot == PROT_READ) { + if (malloc_num_zones > 1 && malloc_zones[0] != &sanitizer_zone) { + for (unsigned i = 1; i < malloc_num_zones; i++) { + if (malloc_zones[i] == &sanitizer_zone) { + // Swap malloc_zones[0] and malloc_zones[i]. + malloc_zones[i] = malloc_zones[0]; + malloc_zones[0] = &sanitizer_zone; + break; + } + } + } + } +} + +BlockingMutex::BlockingMutex() { + internal_memset(this, 0, sizeof(*this)); +} + +void BlockingMutex::Lock() { + CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_)); + CHECK_EQ(OS_SPINLOCK_INIT, 0); + CHECK_EQ(owner_, 0); + OSSpinLockLock((OSSpinLock*)&opaque_storage_); +} + +void BlockingMutex::Unlock() { + OSSpinLockUnlock((OSSpinLock*)&opaque_storage_); +} + +void BlockingMutex::CheckLocked() { + CHECK_NE(*(OSSpinLock*)&opaque_storage_, 0); +} + +u64 NanoTime() { + timeval tv; + internal_memset(&tv, 0, sizeof(tv)); + gettimeofday(&tv, 0); + return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000; +} + +// This needs to be called during initialization to avoid being racy. +u64 MonotonicNanoTime() { + static mach_timebase_info_data_t timebase_info; + if (timebase_info.denom == 0) mach_timebase_info(&timebase_info); + return (mach_absolute_time() * timebase_info.numer) / timebase_info.denom; +} + +uptr GetTlsSize() { + return 0; +} + +void InitTlsSize() { +} + +uptr TlsBaseAddr() { + uptr segbase = 0; +#if defined(__x86_64__) + asm("movq %%gs:0,%0" : "=r"(segbase)); +#elif defined(__i386__) + asm("movl %%gs:0,%0" : "=r"(segbase)); +#endif + return segbase; +} + +// The size of the tls on darwin does not appear to be well documented, +// however the vm memory map suggests that it is 1024 uptrs in size, +// with a size of 0x2000 bytes on x86_64 and 0x1000 bytes on i386. +uptr TlsSize() { +#if defined(__x86_64__) || defined(__i386__) + return 1024 * sizeof(uptr); +#else + return 0; +#endif +} + +void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, + uptr *tls_addr, uptr *tls_size) { +#if !SANITIZER_GO + uptr stack_top, stack_bottom; + GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); + *stk_addr = stack_bottom; + *stk_size = stack_top - stack_bottom; + *tls_addr = TlsBaseAddr(); + *tls_size = TlsSize(); +#else + *stk_addr = 0; + *stk_size = 0; + *tls_addr = 0; + *tls_size = 0; +#endif +} + +void ListOfModules::init() { + clearOrInit(); + MemoryMappingLayout memory_mapping(false); + memory_mapping.DumpListOfModules(&modules_); +} + +void ListOfModules::fallbackInit() { clear(); } + +static HandleSignalMode GetHandleSignalModeImpl(int signum) { + switch (signum) { + case SIGABRT: + return common_flags()->handle_abort; + case SIGILL: + return common_flags()->handle_sigill; + case SIGTRAP: + return common_flags()->handle_sigtrap; + case SIGFPE: + return common_flags()->handle_sigfpe; + case SIGSEGV: + return common_flags()->handle_segv; + case SIGBUS: + return common_flags()->handle_sigbus; + } + return kHandleSignalNo; +} + +HandleSignalMode GetHandleSignalMode(int signum) { + // Handling fatal signals on watchOS and tvOS devices is disallowed. + if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM)) + return kHandleSignalNo; + HandleSignalMode result = GetHandleSignalModeImpl(signum); + if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler) + return kHandleSignalExclusive; + return result; +} + +MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED; + +MacosVersion GetMacosVersionInternal() { + int mib[2] = { CTL_KERN, KERN_OSRELEASE }; + char version[100]; + uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]); + for (uptr i = 0; i < maxlen; i++) version[i] = '\0'; + // Get the version length. + CHECK_NE(internal_sysctl(mib, 2, 0, &len, 0, 0), -1); + CHECK_LT(len, maxlen); + CHECK_NE(internal_sysctl(mib, 2, version, &len, 0, 0), -1); + + // Expect .(.) + CHECK_GE(len, 3); + const char *p = version; + int major = internal_simple_strtoll(p, &p, /*base=*/10); + if (*p != '.') return MACOS_VERSION_UNKNOWN; + p += 1; + int minor = internal_simple_strtoll(p, &p, /*base=*/10); + if (*p != '.') return MACOS_VERSION_UNKNOWN; + + switch (major) { + case 9: return MACOS_VERSION_LEOPARD; + case 10: return MACOS_VERSION_SNOW_LEOPARD; + case 11: return MACOS_VERSION_LION; + case 12: return MACOS_VERSION_MOUNTAIN_LION; + case 13: return MACOS_VERSION_MAVERICKS; + case 14: return MACOS_VERSION_YOSEMITE; + case 15: return MACOS_VERSION_EL_CAPITAN; + case 16: return MACOS_VERSION_SIERRA; + case 17: + // Not a typo, 17.5 Darwin Kernel Version maps to High Sierra 10.13.4. + if (minor >= 5) + return MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4; + return MACOS_VERSION_HIGH_SIERRA; + case 18: return MACOS_VERSION_MOJAVE; + case 19: return MACOS_VERSION_CATALINA; + default: + if (major < 9) return MACOS_VERSION_UNKNOWN; + return MACOS_VERSION_UNKNOWN_NEWER; + } +} + +MacosVersion GetMacosVersion() { + atomic_uint32_t *cache = + reinterpret_cast(&cached_macos_version); + MacosVersion result = + static_cast(atomic_load(cache, memory_order_acquire)); + if (result == MACOS_VERSION_UNINITIALIZED) { + result = GetMacosVersionInternal(); + atomic_store(cache, result, memory_order_release); + } + return result; +} + +bool PlatformHasDifferentMemcpyAndMemmove() { + // On OS X 10.7 memcpy() and memmove() are both resolved + // into memmove$VARIANT$sse42. + // See also https://github.com/google/sanitizers/issues/34. + // TODO(glider): need to check dynamically that memcpy() and memmove() are + // actually the same function. + return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD; +} + +uptr GetRSS() { + struct task_basic_info info; + unsigned count = TASK_BASIC_INFO_COUNT; + kern_return_t result = + task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count); + if (UNLIKELY(result != KERN_SUCCESS)) { + Report("Cannot get task info. Error: %d\n", result); + Die(); + } + return info.resident_size; +} + +void *internal_start_thread(void(*func)(void *arg), void *arg) { + // Start the thread with signals blocked, otherwise it can steal user signals. + __sanitizer_sigset_t set, old; + internal_sigfillset(&set); + internal_sigprocmask(SIG_SETMASK, &set, &old); + pthread_t th; + pthread_create(&th, 0, (void*(*)(void *arg))func, arg); + internal_sigprocmask(SIG_SETMASK, &old, 0); + return th; +} + +void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); } + +#if !SANITIZER_GO +static BlockingMutex syslog_lock(LINKER_INITIALIZED); +#endif + +void WriteOneLineToSyslog(const char *s) { +#if !SANITIZER_GO + syslog_lock.CheckLocked(); + asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s); +#endif +} + +void LogMessageOnPrintf(const char *str) { + // Log all printf output to CrashLog. + if (common_flags()->abort_on_error) + CRAppendCrashLogMessage(str); +} + +void LogFullErrorReport(const char *buffer) { +#if !SANITIZER_GO + // Log with os_trace. This will make it into the crash log. +#if SANITIZER_OS_TRACE + if (GetMacosVersion() >= MACOS_VERSION_YOSEMITE) { + // os_trace requires the message (format parameter) to be a string literal. + if (internal_strncmp(SanitizerToolName, "AddressSanitizer", + sizeof("AddressSanitizer") - 1) == 0) + os_trace("Address Sanitizer reported a failure."); + else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer", + sizeof("UndefinedBehaviorSanitizer") - 1) == 0) + os_trace("Undefined Behavior Sanitizer reported a failure."); + else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer", + sizeof("ThreadSanitizer") - 1) == 0) + os_trace("Thread Sanitizer reported a failure."); + else + os_trace("Sanitizer tool reported a failure."); + + if (common_flags()->log_to_syslog) + os_trace("Consult syslog for more information."); + } +#endif + + // Log to syslog. + // The logging on OS X may call pthread_create so we need the threading + // environment to be fully initialized. Also, this should never be called when + // holding the thread registry lock since that may result in a deadlock. If + // the reporting thread holds the thread registry mutex, and asl_log waits + // for GCD to dispatch a new thread, the process will deadlock, because the + // pthread_create wrapper needs to acquire the lock as well. + BlockingMutexLock l(&syslog_lock); + if (common_flags()->log_to_syslog) + WriteToSyslog(buffer); + + // The report is added to CrashLog as part of logging all of Printf output. +#endif +} + +SignalContext::WriteFlag SignalContext::GetWriteFlag() const { +#if defined(__x86_64__) || defined(__i386__) + ucontext_t *ucontext = static_cast(context); + return ucontext->uc_mcontext->__es.__err & 2 /*T_PF_WRITE*/ ? WRITE : READ; +#else + return UNKNOWN; +#endif +} + +bool SignalContext::IsTrueFaultingAddress() const { + auto si = static_cast(siginfo); + // "Real" SIGSEGV codes (e.g., SEGV_MAPERR, SEGV_MAPERR) are non-zero. + return si->si_signo == SIGSEGV && si->si_code != 0; +} + +static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { + ucontext_t *ucontext = (ucontext_t*)context; +# if defined(__aarch64__) + *pc = ucontext->uc_mcontext->__ss.__pc; +# if defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0 + *bp = ucontext->uc_mcontext->__ss.__fp; +# else + *bp = ucontext->uc_mcontext->__ss.__lr; +# endif + *sp = ucontext->uc_mcontext->__ss.__sp; +# elif defined(__x86_64__) + *pc = ucontext->uc_mcontext->__ss.__rip; + *bp = ucontext->uc_mcontext->__ss.__rbp; + *sp = ucontext->uc_mcontext->__ss.__rsp; +# elif defined(__arm__) + *pc = ucontext->uc_mcontext->__ss.__pc; + *bp = ucontext->uc_mcontext->__ss.__r[7]; + *sp = ucontext->uc_mcontext->__ss.__sp; +# elif defined(__i386__) + *pc = ucontext->uc_mcontext->__ss.__eip; + *bp = ucontext->uc_mcontext->__ss.__ebp; + *sp = ucontext->uc_mcontext->__ss.__esp; +# else +# error "Unknown architecture" +# endif +} + +void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } + +void InitializePlatformEarly() { + // Only use xnu_fast_mmap when on x86_64 and the OS supports it. + use_xnu_fast_mmap = +#if defined(__x86_64__) + GetMacosVersion() >= MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4; +#else + false; +#endif +} + +#if !SANITIZER_GO +static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES"; +LowLevelAllocator allocator_for_env; + +// Change the value of the env var |name|, leaking the original value. +// If |name_value| is NULL, the variable is deleted from the environment, +// otherwise the corresponding "NAME=value" string is replaced with +// |name_value|. +void LeakyResetEnv(const char *name, const char *name_value) { + char **env = GetEnviron(); + uptr name_len = internal_strlen(name); + while (*env != 0) { + uptr len = internal_strlen(*env); + if (len > name_len) { + const char *p = *env; + if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') { + // Match. + if (name_value) { + // Replace the old value with the new one. + *env = const_cast(name_value); + } else { + // Shift the subsequent pointers back. + char **del = env; + do { + del[0] = del[1]; + } while (*del++); + } + } + } + env++; + } +} + +SANITIZER_WEAK_CXX_DEFAULT_IMPL +bool ReexecDisabled() { + return false; +} + +extern "C" SANITIZER_WEAK_ATTRIBUTE double dyldVersionNumber; +static const double kMinDyldVersionWithAutoInterposition = 360.0; + +bool DyldNeedsEnvVariable() { + // Although sanitizer support was added to LLVM on OS X 10.7+, GCC users + // still may want use them on older systems. On older Darwin platforms, dyld + // doesn't export dyldVersionNumber symbol and we simply return true. + if (!&dyldVersionNumber) return true; + // If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if + // DYLD_INSERT_LIBRARIES is not set. However, checking OS version via + // GetMacosVersion() doesn't work for the simulator. Let's instead check + // `dyldVersionNumber`, which is exported by dyld, against a known version + // number from the first OS release where this appeared. + return dyldVersionNumber < kMinDyldVersionWithAutoInterposition; +} + +void MaybeReexec() { + // FIXME: This should really live in some "InitializePlatform" method. + MonotonicNanoTime(); + + if (ReexecDisabled()) return; + + // Make sure the dynamic runtime library is preloaded so that the + // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec + // ourselves. + Dl_info info; + RAW_CHECK(dladdr((void*)((uptr)&__sanitizer_report_error_summary), &info)); + char *dyld_insert_libraries = + const_cast(GetEnv(kDyldInsertLibraries)); + uptr old_env_len = dyld_insert_libraries ? + internal_strlen(dyld_insert_libraries) : 0; + uptr fname_len = internal_strlen(info.dli_fname); + const char *dylib_name = StripModuleName(info.dli_fname); + uptr dylib_name_len = internal_strlen(dylib_name); + + bool lib_is_in_env = dyld_insert_libraries && + internal_strstr(dyld_insert_libraries, dylib_name); + if (DyldNeedsEnvVariable() && !lib_is_in_env) { + // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime + // library. + InternalScopedString program_name(1024); + uint32_t buf_size = program_name.size(); + _NSGetExecutablePath(program_name.data(), &buf_size); + char *new_env = const_cast(info.dli_fname); + if (dyld_insert_libraries) { + // Append the runtime dylib name to the existing value of + // DYLD_INSERT_LIBRARIES. + new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2); + internal_strncpy(new_env, dyld_insert_libraries, old_env_len); + new_env[old_env_len] = ':'; + // Copy fname_len and add a trailing zero. + internal_strncpy(new_env + old_env_len + 1, info.dli_fname, + fname_len + 1); + // Ok to use setenv() since the wrappers don't depend on the value of + // asan_inited. + setenv(kDyldInsertLibraries, new_env, /*overwrite*/1); + } else { + // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name. + setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0); + } + VReport(1, "exec()-ing the program with\n"); + VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env); + VReport(1, "to enable wrappers.\n"); + execv(program_name.data(), *_NSGetArgv()); + + // We get here only if execv() failed. + Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, " + "which is required for the sanitizer to work. We tried to set the " + "environment variable and re-execute itself, but execv() failed, " + "possibly because of sandbox restrictions. Make sure to launch the " + "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env); + RAW_CHECK("execv failed" && 0); + } + + // Verify that interceptors really work. We'll use dlsym to locate + // "pthread_create", if interceptors are working, it should really point to + // "wrap_pthread_create" within our own dylib. + Dl_info info_pthread_create; + void *dlopen_addr = dlsym(RTLD_DEFAULT, "pthread_create"); + RAW_CHECK(dladdr(dlopen_addr, &info_pthread_create)); + if (internal_strcmp(info.dli_fname, info_pthread_create.dli_fname) != 0) { + Report( + "ERROR: Interceptors are not working. This may be because %s is " + "loaded too late (e.g. via dlopen). Please launch the executable " + "with:\n%s=%s\n", + SanitizerToolName, kDyldInsertLibraries, info.dli_fname); + RAW_CHECK("interceptors not installed" && 0); + } + + if (!lib_is_in_env) + return; + + if (!common_flags()->strip_env) + return; + + // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove + // the dylib from the environment variable, because interceptors are installed + // and we don't want our children to inherit the variable. + + uptr env_name_len = internal_strlen(kDyldInsertLibraries); + // Allocate memory to hold the previous env var name, its value, the '=' + // sign and the '\0' char. + char *new_env = (char*)allocator_for_env.Allocate( + old_env_len + 2 + env_name_len); + RAW_CHECK(new_env); + internal_memset(new_env, '\0', old_env_len + 2 + env_name_len); + internal_strncpy(new_env, kDyldInsertLibraries, env_name_len); + new_env[env_name_len] = '='; + char *new_env_pos = new_env + env_name_len + 1; + + // Iterate over colon-separated pieces of |dyld_insert_libraries|. + char *piece_start = dyld_insert_libraries; + char *piece_end = NULL; + char *old_env_end = dyld_insert_libraries + old_env_len; + do { + if (piece_start[0] == ':') piece_start++; + piece_end = internal_strchr(piece_start, ':'); + if (!piece_end) piece_end = dyld_insert_libraries + old_env_len; + if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break; + uptr piece_len = piece_end - piece_start; + + char *filename_start = + (char *)internal_memrchr(piece_start, '/', piece_len); + uptr filename_len = piece_len; + if (filename_start) { + filename_start += 1; + filename_len = piece_len - (filename_start - piece_start); + } else { + filename_start = piece_start; + } + + // If the current piece isn't the runtime library name, + // append it to new_env. + if ((dylib_name_len != filename_len) || + (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) { + if (new_env_pos != new_env + env_name_len + 1) { + new_env_pos[0] = ':'; + new_env_pos++; + } + internal_strncpy(new_env_pos, piece_start, piece_len); + new_env_pos += piece_len; + } + // Move on to the next piece. + piece_start = piece_end; + } while (piece_start < old_env_end); + + // Can't use setenv() here, because it requires the allocator to be + // initialized. + // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in + // a separate function called after InitializeAllocator(). + if (new_env_pos == new_env + env_name_len + 1) new_env = NULL; + LeakyResetEnv(kDyldInsertLibraries, new_env); +} +#endif // SANITIZER_GO + +char **GetArgv() { + return *_NSGetArgv(); +} + +#if SANITIZER_IOS +// The task_vm_info struct is normally provided by the macOS SDK, but we need +// fields only available in 10.12+. Declare the struct manually to be able to +// build against older SDKs. +struct __sanitizer_task_vm_info { + mach_vm_size_t virtual_size; + integer_t region_count; + integer_t page_size; + mach_vm_size_t resident_size; + mach_vm_size_t resident_size_peak; + mach_vm_size_t device; + mach_vm_size_t device_peak; + mach_vm_size_t internal; + mach_vm_size_t internal_peak; + mach_vm_size_t external; + mach_vm_size_t external_peak; + mach_vm_size_t reusable; + mach_vm_size_t reusable_peak; + mach_vm_size_t purgeable_volatile_pmap; + mach_vm_size_t purgeable_volatile_resident; + mach_vm_size_t purgeable_volatile_virtual; + mach_vm_size_t compressed; + mach_vm_size_t compressed_peak; + mach_vm_size_t compressed_lifetime; + mach_vm_size_t phys_footprint; + mach_vm_address_t min_address; + mach_vm_address_t max_address; +}; +#define __SANITIZER_TASK_VM_INFO_COUNT ((mach_msg_type_number_t) \ + (sizeof(__sanitizer_task_vm_info) / sizeof(natural_t))) + +static uptr GetTaskInfoMaxAddress() { + __sanitizer_task_vm_info vm_info = {} /* zero initialize */; + mach_msg_type_number_t count = __SANITIZER_TASK_VM_INFO_COUNT; + int err = task_info(mach_task_self(), TASK_VM_INFO, (int *)&vm_info, &count); + return err ? 0 : vm_info.max_address; +} + +uptr GetMaxUserVirtualAddress() { + static uptr max_vm = GetTaskInfoMaxAddress(); + if (max_vm != 0) + return max_vm - 1; + + // xnu cannot provide vm address limit +# if SANITIZER_WORDSIZE == 32 + return 0xffe00000 - 1; +# else + return 0x200000000 - 1; +# endif +} + +#else // !SANITIZER_IOS + +uptr GetMaxUserVirtualAddress() { +# if SANITIZER_WORDSIZE == 64 + return (1ULL << 47) - 1; // 0x00007fffffffffffUL; +# else // SANITIZER_WORDSIZE == 32 + static_assert(SANITIZER_WORDSIZE == 32, "Wrong wordsize"); + return (1ULL << 32) - 1; // 0xffffffff; +# endif +} +#endif + +uptr GetMaxVirtualAddress() { + return GetMaxUserVirtualAddress(); +} + +uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, + uptr *largest_gap_found, + uptr *max_occupied_addr) { + typedef vm_region_submap_short_info_data_64_t RegionInfo; + enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 }; + // Start searching for available memory region past PAGEZERO, which is + // 4KB on 32-bit and 4GB on 64-bit. + mach_vm_address_t start_address = + (SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000; + + mach_vm_address_t address = start_address; + mach_vm_address_t free_begin = start_address; + kern_return_t kr = KERN_SUCCESS; + if (largest_gap_found) *largest_gap_found = 0; + if (max_occupied_addr) *max_occupied_addr = 0; + while (kr == KERN_SUCCESS) { + mach_vm_size_t vmsize = 0; + natural_t depth = 0; + RegionInfo vminfo; + mach_msg_type_number_t count = kRegionInfoSize; + kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth, + (vm_region_info_t)&vminfo, &count); + if (kr == KERN_INVALID_ADDRESS) { + // No more regions beyond "address", consider the gap at the end of VM. + address = GetMaxVirtualAddress() + 1; + vmsize = 0; + } else { + if (max_occupied_addr) *max_occupied_addr = address + vmsize; + } + if (free_begin != address) { + // We found a free region [free_begin..address-1]. + uptr gap_start = RoundUpTo((uptr)free_begin + left_padding, alignment); + uptr gap_end = RoundDownTo((uptr)address, alignment); + uptr gap_size = gap_end > gap_start ? gap_end - gap_start : 0; + if (size < gap_size) { + return gap_start; + } + + if (largest_gap_found && *largest_gap_found < gap_size) { + *largest_gap_found = gap_size; + } + } + // Move to the next region. + address += vmsize; + free_begin = address; + } + + // We looked at all free regions and could not find one large enough. + return 0; +} + +// FIXME implement on this platform. +void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { } + +void SignalContext::DumpAllRegisters(void *context) { + Report("Register values:\n"); + + ucontext_t *ucontext = (ucontext_t*)context; +# define DUMPREG64(r) \ + Printf("%s = 0x%016llx ", #r, ucontext->uc_mcontext->__ss.__ ## r); +# define DUMPREG32(r) \ + Printf("%s = 0x%08x ", #r, ucontext->uc_mcontext->__ss.__ ## r); +# define DUMPREG_(r) Printf(" "); DUMPREG(r); +# define DUMPREG__(r) Printf(" "); DUMPREG(r); +# define DUMPREG___(r) Printf(" "); DUMPREG(r); + +# if defined(__x86_64__) +# define DUMPREG(r) DUMPREG64(r) + DUMPREG(rax); DUMPREG(rbx); DUMPREG(rcx); DUMPREG(rdx); Printf("\n"); + DUMPREG(rdi); DUMPREG(rsi); DUMPREG(rbp); DUMPREG(rsp); Printf("\n"); + DUMPREG_(r8); DUMPREG_(r9); DUMPREG(r10); DUMPREG(r11); Printf("\n"); + DUMPREG(r12); DUMPREG(r13); DUMPREG(r14); DUMPREG(r15); Printf("\n"); +# elif defined(__i386__) +# define DUMPREG(r) DUMPREG32(r) + DUMPREG(eax); DUMPREG(ebx); DUMPREG(ecx); DUMPREG(edx); Printf("\n"); + DUMPREG(edi); DUMPREG(esi); DUMPREG(ebp); DUMPREG(esp); Printf("\n"); +# elif defined(__aarch64__) +# define DUMPREG(r) DUMPREG64(r) + DUMPREG_(x[0]); DUMPREG_(x[1]); DUMPREG_(x[2]); DUMPREG_(x[3]); Printf("\n"); + DUMPREG_(x[4]); DUMPREG_(x[5]); DUMPREG_(x[6]); DUMPREG_(x[7]); Printf("\n"); + DUMPREG_(x[8]); DUMPREG_(x[9]); DUMPREG(x[10]); DUMPREG(x[11]); Printf("\n"); + DUMPREG(x[12]); DUMPREG(x[13]); DUMPREG(x[14]); DUMPREG(x[15]); Printf("\n"); + DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]); Printf("\n"); + DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]); Printf("\n"); + DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]); Printf("\n"); + DUMPREG(x[28]); DUMPREG___(fp); DUMPREG___(lr); DUMPREG___(sp); Printf("\n"); +# elif defined(__arm__) +# define DUMPREG(r) DUMPREG32(r) + DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]); Printf("\n"); + DUMPREG_(r[4]); DUMPREG_(r[5]); DUMPREG_(r[6]); DUMPREG_(r[7]); Printf("\n"); + DUMPREG_(r[8]); DUMPREG_(r[9]); DUMPREG(r[10]); DUMPREG(r[11]); Printf("\n"); + DUMPREG(r[12]); DUMPREG___(sp); DUMPREG___(lr); DUMPREG___(pc); Printf("\n"); +# else +# error "Unknown architecture" +# endif + +# undef DUMPREG64 +# undef DUMPREG32 +# undef DUMPREG_ +# undef DUMPREG__ +# undef DUMPREG___ +# undef DUMPREG +} + +static inline bool CompareBaseAddress(const LoadedModule &a, + const LoadedModule &b) { + return a.base_address() < b.base_address(); +} + +void FormatUUID(char *out, uptr size, const u8 *uuid) { + internal_snprintf(out, size, + "<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-" + "%02X%02X%02X%02X%02X%02X>", + uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], + uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); +} + +void PrintModuleMap() { + Printf("Process module map:\n"); + MemoryMappingLayout memory_mapping(false); + InternalMmapVector modules; + modules.reserve(128); + memory_mapping.DumpListOfModules(&modules); + Sort(modules.data(), modules.size(), CompareBaseAddress); + for (uptr i = 0; i < modules.size(); ++i) { + char uuid_str[128]; + FormatUUID(uuid_str, sizeof(uuid_str), modules[i].uuid()); + Printf("0x%zx-0x%zx %s (%s) %s\n", modules[i].base_address(), + modules[i].max_executable_address(), modules[i].full_name(), + ModuleArchToString(modules[i].arch()), uuid_str); + } + Printf("End of module map.\n"); +} + +void CheckNoDeepBind(const char *filename, int flag) { + // Do nothing. +} + +bool GetRandom(void *buffer, uptr length, bool blocking) { + if (!buffer || !length || length > 256) + return false; + // arc4random never fails. + REAL(arc4random_buf)(buffer, length); + return true; +} + +u32 GetNumberOfCPUs() { + return (u32)sysconf(_SC_NPROCESSORS_ONLN); +} + +} // namespace __sanitizer + +#endif // SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_mac_libcdep.cc b/lib/sanitizer_common/sanitizer_mac_libcdep.cc deleted file mode 100644 index 93fb5b2f96c6..000000000000 --- a/lib/sanitizer_common/sanitizer_mac_libcdep.cc +++ /dev/null @@ -1,29 +0,0 @@ -//===-- sanitizer_mac_libcdep.cc ------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between various sanitizers' runtime libraries and -// implements OSX-specific functions. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_MAC -#include "sanitizer_mac.h" - -#include - -namespace __sanitizer { - -void RestrictMemoryToMaxAddress(uptr max_address) { - uptr size_to_mmap = GetMaxUserVirtualAddress() + 1 - max_address; - void *res = MmapFixedNoAccess(max_address, size_to_mmap, "high gap"); - CHECK(res != MAP_FAILED); -} - -} // namespace __sanitizer - -#endif // SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_mac_libcdep.cpp b/lib/sanitizer_common/sanitizer_mac_libcdep.cpp new file mode 100644 index 000000000000..ac7e328946bf --- /dev/null +++ b/lib/sanitizer_common/sanitizer_mac_libcdep.cpp @@ -0,0 +1,29 @@ +//===-- sanitizer_mac_libcdep.cpp -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries and +// implements OSX-specific functions. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_MAC +#include "sanitizer_mac.h" + +#include + +namespace __sanitizer { + +void RestrictMemoryToMaxAddress(uptr max_address) { + uptr size_to_mmap = GetMaxUserVirtualAddress() + 1 - max_address; + void *res = MmapFixedNoAccess(max_address, size_to_mmap, "high gap"); + CHECK(res != MAP_FAILED); +} + +} // namespace __sanitizer + +#endif // SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_malloc_mac.inc b/lib/sanitizer_common/sanitizer_malloc_mac.inc index 3f3581eeb484..11adbe5c25b4 100644 --- a/lib/sanitizer_common/sanitizer_malloc_mac.inc +++ b/lib/sanitizer_common/sanitizer_malloc_mac.inc @@ -91,6 +91,15 @@ INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) { return &sanitizer_zone; } +INTERCEPTOR(malloc_zone_t *, malloc_zone_from_ptr, const void *ptr) { + COMMON_MALLOC_ENTER(); + size_t size = sanitizer_zone.size(&sanitizer_zone, ptr); + if (size) { // Claimed by sanitizer zone? + return &sanitizer_zone; + } + return REAL(malloc_zone_from_ptr)(ptr); +} + INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) { // FIXME: ASan should support purgeable allocations. // https://github.com/google/sanitizers/issues/139 @@ -226,7 +235,7 @@ void __sanitizer_mz_free(malloc_zone_t *zone, void *ptr) { } #define GET_ZONE_FOR_PTR(ptr) \ - malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \ + malloc_zone_t *zone_ptr = WRAP(malloc_zone_from_ptr)(ptr); \ const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name extern "C" diff --git a/lib/sanitizer_common/sanitizer_netbsd.cc b/lib/sanitizer_common/sanitizer_netbsd.cc deleted file mode 100644 index 385008e4c95a..000000000000 --- a/lib/sanitizer_common/sanitizer_netbsd.cc +++ /dev/null @@ -1,338 +0,0 @@ -//===-- sanitizer_netbsd.cc -----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between Sanitizer run-time libraries and implements -// NetBSD-specific functions from sanitizer_libc.h. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_NETBSD - -#include "sanitizer_common.h" -#include "sanitizer_flags.h" -#include "sanitizer_getauxval.h" -#include "sanitizer_internal_defs.h" -#include "sanitizer_libc.h" -#include "sanitizer_linux.h" -#include "sanitizer_mutex.h" -#include "sanitizer_placement_new.h" -#include "sanitizer_procmaps.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern "C" void *__mmap(void *, size_t, int, int, int, int, - off_t) SANITIZER_WEAK_ATTRIBUTE; -extern "C" int __sysctl(const int *, unsigned int, void *, size_t *, - const void *, size_t) SANITIZER_WEAK_ATTRIBUTE; -extern "C" int _sys_close(int) SANITIZER_WEAK_ATTRIBUTE; -extern "C" int _sys_open(const char *, int, ...) SANITIZER_WEAK_ATTRIBUTE; -extern "C" ssize_t _sys_read(int, void *, size_t) SANITIZER_WEAK_ATTRIBUTE; -extern "C" ssize_t _sys_write(int, const void *, - size_t) SANITIZER_WEAK_ATTRIBUTE; -extern "C" int __ftruncate(int, int, off_t) SANITIZER_WEAK_ATTRIBUTE; -extern "C" ssize_t _sys_readlink(const char *, char *, - size_t) SANITIZER_WEAK_ATTRIBUTE; -extern "C" int _sys_sched_yield() SANITIZER_WEAK_ATTRIBUTE; -extern "C" int _sys___nanosleep50(const void *, - void *) SANITIZER_WEAK_ATTRIBUTE; -extern "C" int _sys_execve(const char *, char *const[], - char *const[]) SANITIZER_WEAK_ATTRIBUTE; -extern "C" off_t __lseek(int, int, off_t, int) SANITIZER_WEAK_ATTRIBUTE; -extern "C" int __fork() SANITIZER_WEAK_ATTRIBUTE; -extern "C" int _sys___sigprocmask14(int, const void *, - void *) SANITIZER_WEAK_ATTRIBUTE; -extern "C" int _sys___wait450(int wpid, int *, int, - void *) SANITIZER_WEAK_ATTRIBUTE; - -namespace __sanitizer { - -static void *GetRealLibcAddress(const char *symbol) { - void *real = dlsym(RTLD_NEXT, symbol); - if (!real) - real = dlsym(RTLD_DEFAULT, symbol); - if (!real) { - Printf("GetRealLibcAddress failed for symbol=%s", symbol); - Die(); - } - return real; -} - -#define _REAL(func, ...) real##_##func(__VA_ARGS__) -#define DEFINE__REAL(ret_type, func, ...) \ - static ret_type (*real_##func)(__VA_ARGS__) = NULL; \ - if (!real_##func) { \ - real_##func = (ret_type(*)(__VA_ARGS__))GetRealLibcAddress(#func); \ - } \ - CHECK(real_##func); - -// --------------- sanitizer_libc.h -uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, - OFF_T offset) { - CHECK(&__mmap); - return (uptr)__mmap(addr, length, prot, flags, fd, 0, offset); -} - -uptr internal_munmap(void *addr, uptr length) { - DEFINE__REAL(int, munmap, void *a, uptr b); - return _REAL(munmap, addr, length); -} - -int internal_mprotect(void *addr, uptr length, int prot) { - DEFINE__REAL(int, mprotect, void *a, uptr b, int c); - return _REAL(mprotect, addr, length, prot); -} - -uptr internal_close(fd_t fd) { - CHECK(&_sys_close); - return _sys_close(fd); -} - -uptr internal_open(const char *filename, int flags) { - CHECK(&_sys_open); - return _sys_open(filename, flags); -} - -uptr internal_open(const char *filename, int flags, u32 mode) { - CHECK(&_sys_open); - return _sys_open(filename, flags, mode); -} - -uptr internal_read(fd_t fd, void *buf, uptr count) { - sptr res; - CHECK(&_sys_read); - HANDLE_EINTR(res, (sptr)_sys_read(fd, buf, (size_t)count)); - return res; -} - -uptr internal_write(fd_t fd, const void *buf, uptr count) { - sptr res; - CHECK(&_sys_write); - HANDLE_EINTR(res, (sptr)_sys_write(fd, buf, count)); - return res; -} - -uptr internal_ftruncate(fd_t fd, uptr size) { - sptr res; - CHECK(&__ftruncate); - HANDLE_EINTR(res, __ftruncate(fd, 0, (s64)size)); - return res; -} - -uptr internal_stat(const char *path, void *buf) { - DEFINE__REAL(int, __stat50, const char *a, void *b); - return _REAL(__stat50, path, buf); -} - -uptr internal_lstat(const char *path, void *buf) { - DEFINE__REAL(int, __lstat50, const char *a, void *b); - return _REAL(__lstat50, path, buf); -} - -uptr internal_fstat(fd_t fd, void *buf) { - DEFINE__REAL(int, __fstat50, int a, void *b); - return _REAL(__fstat50, fd, buf); -} - -uptr internal_filesize(fd_t fd) { - struct stat st; - if (internal_fstat(fd, &st)) - return -1; - return (uptr)st.st_size; -} - -uptr internal_dup(int oldfd) { - DEFINE__REAL(int, dup, int a); - return _REAL(dup, oldfd); -} - -uptr internal_dup2(int oldfd, int newfd) { - DEFINE__REAL(int, dup2, int a, int b); - return _REAL(dup2, oldfd, newfd); -} - -uptr internal_readlink(const char *path, char *buf, uptr bufsize) { - CHECK(&_sys_readlink); - return (uptr)_sys_readlink(path, buf, bufsize); -} - -uptr internal_unlink(const char *path) { - DEFINE__REAL(int, unlink, const char *a); - return _REAL(unlink, path); -} - -uptr internal_rename(const char *oldpath, const char *newpath) { - DEFINE__REAL(int, rename, const char *a, const char *b); - return _REAL(rename, oldpath, newpath); -} - -uptr internal_sched_yield() { - CHECK(&_sys_sched_yield); - return _sys_sched_yield(); -} - -void internal__exit(int exitcode) { - DEFINE__REAL(void, _exit, int a); - _REAL(_exit, exitcode); - Die(); // Unreachable. -} - -unsigned int internal_sleep(unsigned int seconds) { - struct timespec ts; - ts.tv_sec = seconds; - ts.tv_nsec = 0; - CHECK(&_sys___nanosleep50); - int res = _sys___nanosleep50(&ts, &ts); - if (res) - return ts.tv_sec; - return 0; -} - -uptr internal_execve(const char *filename, char *const argv[], - char *const envp[]) { - CHECK(&_sys_execve); - return _sys_execve(filename, argv, envp); -} - -tid_t GetTid() { - DEFINE__REAL(int, _lwp_self); - return _REAL(_lwp_self); -} - -int TgKill(pid_t pid, tid_t tid, int sig) { - DEFINE__REAL(int, _lwp_kill, int a, int b); - (void)pid; - return _REAL(_lwp_kill, tid, sig); -} - -u64 NanoTime() { - timeval tv; - DEFINE__REAL(int, __gettimeofday50, void *a, void *b); - internal_memset(&tv, 0, sizeof(tv)); - _REAL(__gettimeofday50, &tv, 0); - return (u64)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000; -} - -uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { - DEFINE__REAL(int, __clock_gettime50, __sanitizer_clockid_t a, void *b); - return _REAL(__clock_gettime50, clk_id, tp); -} - -uptr internal_ptrace(int request, int pid, void *addr, int data) { - DEFINE__REAL(int, ptrace, int a, int b, void *c, int d); - return _REAL(ptrace, request, pid, addr, data); -} - -uptr internal_waitpid(int pid, int *status, int options) { - CHECK(&_sys___wait450); - return _sys___wait450(pid, status, options, 0 /* rusage */); -} - -uptr internal_getpid() { - DEFINE__REAL(int, getpid); - return _REAL(getpid); -} - -uptr internal_getppid() { - DEFINE__REAL(int, getppid); - return _REAL(getppid); -} - -uptr internal_getdents(fd_t fd, void *dirp, unsigned int count) { - DEFINE__REAL(int, __getdents30, int a, void *b, size_t c); - return _REAL(__getdents30, fd, dirp, count); -} - -uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { - CHECK(&__lseek); - return __lseek(fd, 0, offset, whence); -} - -uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { - Printf("internal_prctl not implemented for NetBSD"); - Die(); - return 0; -} - -uptr internal_sigaltstack(const void *ss, void *oss) { - DEFINE__REAL(int, __sigaltstack14, const void *a, void *b); - return _REAL(__sigaltstack14, ss, oss); -} - -int internal_fork() { - CHECK(&__fork); - return __fork(); -} - -int internal_sysctl(const int *name, unsigned int namelen, void *oldp, - uptr *oldlenp, const void *newp, uptr newlen) { - CHECK(&__sysctl); - return __sysctl(name, namelen, oldp, (size_t *)oldlenp, newp, (size_t)newlen); -} - -int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, - const void *newp, uptr newlen) { - DEFINE__REAL(int, sysctlbyname, const char *a, void *b, size_t *c, - const void *d, size_t e); - return _REAL(sysctlbyname, sname, oldp, (size_t *)oldlenp, newp, - (size_t)newlen); -} - -uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, - __sanitizer_sigset_t *oldset) { - CHECK(&_sys___sigprocmask14); - return _sys___sigprocmask14(how, set, oldset); -} - -void internal_sigfillset(__sanitizer_sigset_t *set) { - DEFINE__REAL(int, __sigfillset14, const void *a); - (void)_REAL(__sigfillset14, set); -} - -void internal_sigemptyset(__sanitizer_sigset_t *set) { - DEFINE__REAL(int, __sigemptyset14, const void *a); - (void)_REAL(__sigemptyset14, set); -} - -void internal_sigdelset(__sanitizer_sigset_t *set, int signo) { - DEFINE__REAL(int, __sigdelset14, const void *a, int b); - (void)_REAL(__sigdelset14, set, signo); -} - -uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, - void *arg) { - DEFINE__REAL(int, clone, int (*a)(void *b), void *c, int d, void *e); - - return _REAL(clone, fn, child_stack, flags, arg); -} - -} // namespace __sanitizer - -#endif diff --git a/lib/sanitizer_common/sanitizer_netbsd.cpp b/lib/sanitizer_common/sanitizer_netbsd.cpp new file mode 100644 index 000000000000..4e74f6a3b516 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_netbsd.cpp @@ -0,0 +1,338 @@ +//===-- sanitizer_netbsd.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between Sanitizer run-time libraries and implements +// NetBSD-specific functions from sanitizer_libc.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_NETBSD + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_getauxval.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_linux.h" +#include "sanitizer_mutex.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_procmaps.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" void *__mmap(void *, size_t, int, int, int, int, + off_t) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int __sysctl(const int *, unsigned int, void *, size_t *, + const void *, size_t) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int _sys_close(int) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int _sys_open(const char *, int, ...) SANITIZER_WEAK_ATTRIBUTE; +extern "C" ssize_t _sys_read(int, void *, size_t) SANITIZER_WEAK_ATTRIBUTE; +extern "C" ssize_t _sys_write(int, const void *, + size_t) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int __ftruncate(int, int, off_t) SANITIZER_WEAK_ATTRIBUTE; +extern "C" ssize_t _sys_readlink(const char *, char *, + size_t) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int _sys_sched_yield() SANITIZER_WEAK_ATTRIBUTE; +extern "C" int _sys___nanosleep50(const void *, + void *) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int _sys_execve(const char *, char *const[], + char *const[]) SANITIZER_WEAK_ATTRIBUTE; +extern "C" off_t __lseek(int, int, off_t, int) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int __fork() SANITIZER_WEAK_ATTRIBUTE; +extern "C" int _sys___sigprocmask14(int, const void *, + void *) SANITIZER_WEAK_ATTRIBUTE; +extern "C" int _sys___wait450(int wpid, int *, int, + void *) SANITIZER_WEAK_ATTRIBUTE; + +namespace __sanitizer { + +static void *GetRealLibcAddress(const char *symbol) { + void *real = dlsym(RTLD_NEXT, symbol); + if (!real) + real = dlsym(RTLD_DEFAULT, symbol); + if (!real) { + Printf("GetRealLibcAddress failed for symbol=%s", symbol); + Die(); + } + return real; +} + +#define _REAL(func, ...) real##_##func(__VA_ARGS__) +#define DEFINE__REAL(ret_type, func, ...) \ + static ret_type (*real_##func)(__VA_ARGS__) = NULL; \ + if (!real_##func) { \ + real_##func = (ret_type(*)(__VA_ARGS__))GetRealLibcAddress(#func); \ + } \ + CHECK(real_##func); + +// --------------- sanitizer_libc.h +uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, + OFF_T offset) { + CHECK(&__mmap); + return (uptr)__mmap(addr, length, prot, flags, fd, 0, offset); +} + +uptr internal_munmap(void *addr, uptr length) { + DEFINE__REAL(int, munmap, void *a, uptr b); + return _REAL(munmap, addr, length); +} + +int internal_mprotect(void *addr, uptr length, int prot) { + DEFINE__REAL(int, mprotect, void *a, uptr b, int c); + return _REAL(mprotect, addr, length, prot); +} + +uptr internal_close(fd_t fd) { + CHECK(&_sys_close); + return _sys_close(fd); +} + +uptr internal_open(const char *filename, int flags) { + CHECK(&_sys_open); + return _sys_open(filename, flags); +} + +uptr internal_open(const char *filename, int flags, u32 mode) { + CHECK(&_sys_open); + return _sys_open(filename, flags, mode); +} + +uptr internal_read(fd_t fd, void *buf, uptr count) { + sptr res; + CHECK(&_sys_read); + HANDLE_EINTR(res, (sptr)_sys_read(fd, buf, (size_t)count)); + return res; +} + +uptr internal_write(fd_t fd, const void *buf, uptr count) { + sptr res; + CHECK(&_sys_write); + HANDLE_EINTR(res, (sptr)_sys_write(fd, buf, count)); + return res; +} + +uptr internal_ftruncate(fd_t fd, uptr size) { + sptr res; + CHECK(&__ftruncate); + HANDLE_EINTR(res, __ftruncate(fd, 0, (s64)size)); + return res; +} + +uptr internal_stat(const char *path, void *buf) { + DEFINE__REAL(int, __stat50, const char *a, void *b); + return _REAL(__stat50, path, buf); +} + +uptr internal_lstat(const char *path, void *buf) { + DEFINE__REAL(int, __lstat50, const char *a, void *b); + return _REAL(__lstat50, path, buf); +} + +uptr internal_fstat(fd_t fd, void *buf) { + DEFINE__REAL(int, __fstat50, int a, void *b); + return _REAL(__fstat50, fd, buf); +} + +uptr internal_filesize(fd_t fd) { + struct stat st; + if (internal_fstat(fd, &st)) + return -1; + return (uptr)st.st_size; +} + +uptr internal_dup(int oldfd) { + DEFINE__REAL(int, dup, int a); + return _REAL(dup, oldfd); +} + +uptr internal_dup2(int oldfd, int newfd) { + DEFINE__REAL(int, dup2, int a, int b); + return _REAL(dup2, oldfd, newfd); +} + +uptr internal_readlink(const char *path, char *buf, uptr bufsize) { + CHECK(&_sys_readlink); + return (uptr)_sys_readlink(path, buf, bufsize); +} + +uptr internal_unlink(const char *path) { + DEFINE__REAL(int, unlink, const char *a); + return _REAL(unlink, path); +} + +uptr internal_rename(const char *oldpath, const char *newpath) { + DEFINE__REAL(int, rename, const char *a, const char *b); + return _REAL(rename, oldpath, newpath); +} + +uptr internal_sched_yield() { + CHECK(&_sys_sched_yield); + return _sys_sched_yield(); +} + +void internal__exit(int exitcode) { + DEFINE__REAL(void, _exit, int a); + _REAL(_exit, exitcode); + Die(); // Unreachable. +} + +unsigned int internal_sleep(unsigned int seconds) { + struct timespec ts; + ts.tv_sec = seconds; + ts.tv_nsec = 0; + CHECK(&_sys___nanosleep50); + int res = _sys___nanosleep50(&ts, &ts); + if (res) + return ts.tv_sec; + return 0; +} + +uptr internal_execve(const char *filename, char *const argv[], + char *const envp[]) { + CHECK(&_sys_execve); + return _sys_execve(filename, argv, envp); +} + +tid_t GetTid() { + DEFINE__REAL(int, _lwp_self); + return _REAL(_lwp_self); +} + +int TgKill(pid_t pid, tid_t tid, int sig) { + DEFINE__REAL(int, _lwp_kill, int a, int b); + (void)pid; + return _REAL(_lwp_kill, tid, sig); +} + +u64 NanoTime() { + timeval tv; + DEFINE__REAL(int, __gettimeofday50, void *a, void *b); + internal_memset(&tv, 0, sizeof(tv)); + _REAL(__gettimeofday50, &tv, 0); + return (u64)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000; +} + +uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { + DEFINE__REAL(int, __clock_gettime50, __sanitizer_clockid_t a, void *b); + return _REAL(__clock_gettime50, clk_id, tp); +} + +uptr internal_ptrace(int request, int pid, void *addr, int data) { + DEFINE__REAL(int, ptrace, int a, int b, void *c, int d); + return _REAL(ptrace, request, pid, addr, data); +} + +uptr internal_waitpid(int pid, int *status, int options) { + CHECK(&_sys___wait450); + return _sys___wait450(pid, status, options, 0 /* rusage */); +} + +uptr internal_getpid() { + DEFINE__REAL(int, getpid); + return _REAL(getpid); +} + +uptr internal_getppid() { + DEFINE__REAL(int, getppid); + return _REAL(getppid); +} + +uptr internal_getdents(fd_t fd, void *dirp, unsigned int count) { + DEFINE__REAL(int, __getdents30, int a, void *b, size_t c); + return _REAL(__getdents30, fd, dirp, count); +} + +uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { + CHECK(&__lseek); + return __lseek(fd, 0, offset, whence); +} + +uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { + Printf("internal_prctl not implemented for NetBSD"); + Die(); + return 0; +} + +uptr internal_sigaltstack(const void *ss, void *oss) { + DEFINE__REAL(int, __sigaltstack14, const void *a, void *b); + return _REAL(__sigaltstack14, ss, oss); +} + +int internal_fork() { + CHECK(&__fork); + return __fork(); +} + +int internal_sysctl(const int *name, unsigned int namelen, void *oldp, + uptr *oldlenp, const void *newp, uptr newlen) { + CHECK(&__sysctl); + return __sysctl(name, namelen, oldp, (size_t *)oldlenp, newp, (size_t)newlen); +} + +int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, + const void *newp, uptr newlen) { + DEFINE__REAL(int, sysctlbyname, const char *a, void *b, size_t *c, + const void *d, size_t e); + return _REAL(sysctlbyname, sname, oldp, (size_t *)oldlenp, newp, + (size_t)newlen); +} + +uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset) { + CHECK(&_sys___sigprocmask14); + return _sys___sigprocmask14(how, set, oldset); +} + +void internal_sigfillset(__sanitizer_sigset_t *set) { + DEFINE__REAL(int, __sigfillset14, const void *a); + (void)_REAL(__sigfillset14, set); +} + +void internal_sigemptyset(__sanitizer_sigset_t *set) { + DEFINE__REAL(int, __sigemptyset14, const void *a); + (void)_REAL(__sigemptyset14, set); +} + +void internal_sigdelset(__sanitizer_sigset_t *set, int signo) { + DEFINE__REAL(int, __sigdelset14, const void *a, int b); + (void)_REAL(__sigdelset14, set, signo); +} + +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, + void *arg) { + DEFINE__REAL(int, clone, int (*a)(void *b), void *c, int d, void *e); + + return _REAL(clone, fn, child_stack, flags, arg); +} + +} // namespace __sanitizer + +#endif diff --git a/lib/sanitizer_common/sanitizer_openbsd.cc b/lib/sanitizer_common/sanitizer_openbsd.cc deleted file mode 100644 index b6e9bdfa87e5..000000000000 --- a/lib/sanitizer_common/sanitizer_openbsd.cc +++ /dev/null @@ -1,115 +0,0 @@ -//===-- sanitizer_openbsd.cc ----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between various sanitizers' runtime libraries and -// implements Solaris-specific functions. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_OPENBSD - -#include - -#include "sanitizer_common.h" -#include "sanitizer_flags.h" -#include "sanitizer_internal_defs.h" -#include "sanitizer_libc.h" -#include "sanitizer_placement_new.h" -#include "sanitizer_platform_limits_posix.h" -#include "sanitizer_procmaps.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern char **environ; - -namespace __sanitizer { - -uptr internal_mmap(void *addr, size_t length, int prot, int flags, int fd, - u64 offset) { - return (uptr)mmap(addr, length, prot, flags, fd, offset); -} - -uptr internal_munmap(void *addr, uptr length) { return munmap(addr, length); } - -int internal_mprotect(void *addr, uptr length, int prot) { - return mprotect(addr, length, prot); -} - -int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, - const void *newp, uptr newlen) { - Printf("internal_sysctlbyname not implemented for OpenBSD"); - Die(); - return 0; -} - -uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { - // On OpenBSD we cannot get the full path - struct kinfo_proc kp; - uptr kl; - const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()}; - if (internal_sysctl(Mib, ARRAY_SIZE(Mib), &kp, &kl, NULL, 0) != -1) - return internal_snprintf(buf, - (KI_MAXCOMLEN < buf_len ? KI_MAXCOMLEN : buf_len), - "%s", kp.p_comm); - return (uptr)0; -} - -static void GetArgsAndEnv(char ***argv, char ***envp) { - uptr nargv; - uptr nenv; - int argvmib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV}; - int envmib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ENV}; - if (internal_sysctl(argvmib, 4, NULL, &nargv, NULL, 0) == -1) { - Printf("sysctl KERN_PROC_NARGV failed\n"); - Die(); - } - if (internal_sysctl(envmib, 4, NULL, &nenv, NULL, 0) == -1) { - Printf("sysctl KERN_PROC_NENV failed\n"); - Die(); - } - if (internal_sysctl(argvmib, 4, &argv, &nargv, NULL, 0) == -1) { - Printf("sysctl KERN_PROC_ARGV failed\n"); - Die(); - } - if (internal_sysctl(envmib, 4, &envp, &nenv, NULL, 0) == -1) { - Printf("sysctl KERN_PROC_ENV failed\n"); - Die(); - } -} - -char **GetArgv() { - char **argv, **envp; - GetArgsAndEnv(&argv, &envp); - return argv; -} - -char **GetEnviron() { - char **argv, **envp; - GetArgsAndEnv(&argv, &envp); - return envp; -} - -void ReExec() { - UNIMPLEMENTED(); -} - -} // namespace __sanitizer - -#endif // SANITIZER_OPENBSD diff --git a/lib/sanitizer_common/sanitizer_openbsd.cpp b/lib/sanitizer_common/sanitizer_openbsd.cpp new file mode 100644 index 000000000000..ed2d8edeb7a2 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_openbsd.cpp @@ -0,0 +1,115 @@ +//===-- sanitizer_openbsd.cpp ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries and +// implements Solaris-specific functions. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_OPENBSD + +#include + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_platform_limits_posix.h" +#include "sanitizer_procmaps.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char **environ; + +namespace __sanitizer { + +uptr internal_mmap(void *addr, size_t length, int prot, int flags, int fd, + u64 offset) { + return (uptr)mmap(addr, length, prot, flags, fd, offset); +} + +uptr internal_munmap(void *addr, uptr length) { return munmap(addr, length); } + +int internal_mprotect(void *addr, uptr length, int prot) { + return mprotect(addr, length, prot); +} + +int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, + const void *newp, uptr newlen) { + Printf("internal_sysctlbyname not implemented for OpenBSD"); + Die(); + return 0; +} + +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { + // On OpenBSD we cannot get the full path + struct kinfo_proc kp; + uptr kl; + const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()}; + if (internal_sysctl(Mib, ARRAY_SIZE(Mib), &kp, &kl, NULL, 0) != -1) + return internal_snprintf(buf, + (KI_MAXCOMLEN < buf_len ? KI_MAXCOMLEN : buf_len), + "%s", kp.p_comm); + return (uptr)0; +} + +static void GetArgsAndEnv(char ***argv, char ***envp) { + uptr nargv; + uptr nenv; + int argvmib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV}; + int envmib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ENV}; + if (internal_sysctl(argvmib, 4, NULL, &nargv, NULL, 0) == -1) { + Printf("sysctl KERN_PROC_NARGV failed\n"); + Die(); + } + if (internal_sysctl(envmib, 4, NULL, &nenv, NULL, 0) == -1) { + Printf("sysctl KERN_PROC_NENV failed\n"); + Die(); + } + if (internal_sysctl(argvmib, 4, &argv, &nargv, NULL, 0) == -1) { + Printf("sysctl KERN_PROC_ARGV failed\n"); + Die(); + } + if (internal_sysctl(envmib, 4, &envp, &nenv, NULL, 0) == -1) { + Printf("sysctl KERN_PROC_ENV failed\n"); + Die(); + } +} + +char **GetArgv() { + char **argv, **envp; + GetArgsAndEnv(&argv, &envp); + return argv; +} + +char **GetEnviron() { + char **argv, **envp; + GetArgsAndEnv(&argv, &envp); + return envp; +} + +void ReExec() { + UNIMPLEMENTED(); +} + +} // namespace __sanitizer + +#endif // SANITIZER_OPENBSD diff --git a/lib/sanitizer_common/sanitizer_persistent_allocator.cc b/lib/sanitizer_common/sanitizer_persistent_allocator.cc deleted file mode 100644 index ddd9ae9ec64d..000000000000 --- a/lib/sanitizer_common/sanitizer_persistent_allocator.cc +++ /dev/null @@ -1,18 +0,0 @@ -//===-- sanitizer_persistent_allocator.cc -----------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. -//===----------------------------------------------------------------------===// -#include "sanitizer_persistent_allocator.h" - -namespace __sanitizer { - -PersistentAllocator thePersistentAllocator; - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_persistent_allocator.cpp b/lib/sanitizer_common/sanitizer_persistent_allocator.cpp new file mode 100644 index 000000000000..1ca0375b8a54 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_persistent_allocator.cpp @@ -0,0 +1,18 @@ +//===-- sanitizer_persistent_allocator.cpp ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// +#include "sanitizer_persistent_allocator.h" + +namespace __sanitizer { + +PersistentAllocator thePersistentAllocator; + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index 817d24b3492f..61a6b82ef818 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -13,6 +13,7 @@ #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H #define SANITIZER_PLATFORM_INTERCEPTORS_H +#include "sanitizer_glibc_version.h" #include "sanitizer_internal_defs.h" #if SANITIZER_POSIX @@ -331,10 +332,9 @@ #define SANITIZER_INTERCEPT_ETHER_HOST \ (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_ETHER_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID) -#define SANITIZER_INTERCEPT_SHMCTL \ - (SI_NETBSD || SI_OPENBSD || SI_SOLARIS || \ - ((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && \ - SANITIZER_WORDSIZE == 64)) // NOLINT +#define SANITIZER_INTERCEPT_SHMCTL \ + (((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) || \ + SI_NETBSD || SI_OPENBSD || SI_SOLARIS) // NOLINT #define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_POSIX #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \ @@ -489,7 +489,8 @@ SI_NOT_RTEMS) #define SANITIZER_INTERCEPT_REALLOCARRAY SI_POSIX #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC && SI_NOT_RTEMS) -#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_OPENBSD) +#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE \ + (!SI_MAC && !SI_OPENBSD && !SI_NETBSD) #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WCSCAT SI_POSIX #define SANITIZER_INTERCEPT_WCSDUP SI_POSIX @@ -561,9 +562,18 @@ #define SANITIZER_INTERCEPT_FUNOPEN (SI_NETBSD || SI_FREEBSD) #define SANITIZER_INTERCEPT_FUNOPEN2 SI_NETBSD #define SANITIZER_INTERCEPT_GETFSENT (SI_FREEBSD || SI_NETBSD || SI_MAC) -#define SANITIZER_INTERCEPT_ARC4RANDOM (SI_FREEBSD || SI_NETBSD) +#define SANITIZER_INTERCEPT_ARC4RANDOM (SI_FREEBSD || SI_NETBSD || SI_MAC) #define SANITIZER_INTERCEPT_FDEVNAME SI_FREEBSD -#define SANITIZER_INTERCEPT_GETUSERSHELL (SI_POSIX && !SI_POSIX) +#define SANITIZER_INTERCEPT_GETUSERSHELL (SI_POSIX && !SI_ANDROID) #define SANITIZER_INTERCEPT_SL_INIT (SI_FREEBSD || SI_NETBSD) +#define SANITIZER_INTERCEPT_CRYPT (SI_POSIX && !SI_ANDROID) +#define SANITIZER_INTERCEPT_CRYPT_R (SI_LINUX && !SI_ANDROID) + +#define SANITIZER_INTERCEPT_GETRANDOM \ + ((SI_LINUX && __GLIBC_PREREQ(2, 25)) || SI_FREEBSD) +#define SANITIZER_INTERCEPT___CXA_ATEXIT SI_NETBSD +#define SANITIZER_INTERCEPT_ATEXIT SI_NETBSD +#define SANITIZER_INTERCEPT_PTHREAD_ATFORK SI_NETBSD +#define SANITIZER_INTERCEPT_GETENTROPY SI_FREEBSD #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cc b/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cc deleted file mode 100644 index 034848742697..000000000000 --- a/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cc +++ /dev/null @@ -1,525 +0,0 @@ -//===-- sanitizer_platform_limits_freebsd.cc ------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of Sanitizer common code. -// -// Sizes and layouts of platform-specific FreeBSD data structures. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_FREEBSD - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define _KERNEL // to declare 'shminfo' structure -# include -#undef _KERNEL - -#undef INLINE // to avoid clashes with sanitizers' definitions - -#undef IOC_DIRMASK - -# include -# include -# include - -#include -#include -#include - -// Include these after system headers to avoid name clashes and ambiguities. -#include "sanitizer_internal_defs.h" -#include "sanitizer_platform_limits_freebsd.h" - -namespace __sanitizer { - unsigned struct_cap_rights_sz = sizeof(cap_rights_t); - unsigned struct_utsname_sz = sizeof(struct utsname); - unsigned struct_stat_sz = sizeof(struct stat); - unsigned struct_rusage_sz = sizeof(struct rusage); - unsigned struct_tm_sz = sizeof(struct tm); - unsigned struct_passwd_sz = sizeof(struct passwd); - unsigned struct_group_sz = sizeof(struct group); - unsigned siginfo_t_sz = sizeof(siginfo_t); - unsigned struct_sigaction_sz = sizeof(struct sigaction); - unsigned struct_itimerval_sz = sizeof(struct itimerval); - unsigned pthread_t_sz = sizeof(pthread_t); - unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); - unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); - unsigned pid_t_sz = sizeof(pid_t); - unsigned timeval_sz = sizeof(timeval); - unsigned uid_t_sz = sizeof(uid_t); - unsigned gid_t_sz = sizeof(gid_t); - unsigned fpos_t_sz = sizeof(fpos_t); - unsigned mbstate_t_sz = sizeof(mbstate_t); - unsigned sigset_t_sz = sizeof(sigset_t); - unsigned struct_timezone_sz = sizeof(struct timezone); - unsigned struct_tms_sz = sizeof(struct tms); - unsigned struct_sigevent_sz = sizeof(struct sigevent); - unsigned struct_sched_param_sz = sizeof(struct sched_param); - unsigned struct_statfs_sz = sizeof(struct statfs); - unsigned struct_sockaddr_sz = sizeof(struct sockaddr); - unsigned ucontext_t_sz = sizeof(ucontext_t); - unsigned struct_rlimit_sz = sizeof(struct rlimit); - unsigned struct_timespec_sz = sizeof(struct timespec); - unsigned struct_utimbuf_sz = sizeof(struct utimbuf); - unsigned struct_itimerspec_sz = sizeof(struct itimerspec); - unsigned struct_timeb_sz = sizeof(struct timeb); - unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); - unsigned struct_mq_attr_sz = sizeof(struct mq_attr); - unsigned struct_statvfs_sz = sizeof(struct statvfs); - unsigned struct_shminfo_sz = sizeof(struct shminfo); - unsigned struct_shm_info_sz = sizeof(struct shm_info); - unsigned struct_regmatch_sz = sizeof(regmatch_t); - unsigned struct_regex_sz = sizeof(regex_t); - unsigned struct_fstab_sz = sizeof(struct fstab); - unsigned struct_FTS_sz = sizeof(FTS); - unsigned struct_FTSENT_sz = sizeof(FTSENT); - unsigned struct_StringList_sz = sizeof(StringList); - - const uptr sig_ign = (uptr)SIG_IGN; - const uptr sig_dfl = (uptr)SIG_DFL; - const uptr sig_err = (uptr)SIG_ERR; - const uptr sa_siginfo = (uptr)SA_SIGINFO; - - int shmctl_ipc_stat = (int)IPC_STAT; - int shmctl_ipc_info = (int)IPC_INFO; - int shmctl_shm_info = (int)SHM_INFO; - int shmctl_shm_stat = (int)SHM_STAT; - unsigned struct_utmpx_sz = sizeof(struct utmpx); - - int map_fixed = MAP_FIXED; - - int af_inet = (int)AF_INET; - int af_inet6 = (int)AF_INET6; - - uptr __sanitizer_in_addr_sz(int af) { - if (af == AF_INET) - return sizeof(struct in_addr); - else if (af == AF_INET6) - return sizeof(struct in6_addr); - else - return 0; - } - - unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); - int glob_nomatch = GLOB_NOMATCH; - int glob_altdirfunc = GLOB_ALTDIRFUNC; - - unsigned path_max = PATH_MAX; - - // ioctl arguments - unsigned struct_ifreq_sz = sizeof(struct ifreq); - unsigned struct_termios_sz = sizeof(struct termios); - unsigned struct_winsize_sz = sizeof(struct winsize); -#if SOUND_VERSION >= 0x040000 - unsigned struct_copr_buffer_sz = 0; - unsigned struct_copr_debug_buf_sz = 0; - unsigned struct_copr_msg_sz = 0; -#else - unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer); - unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf); - unsigned struct_copr_msg_sz = sizeof(struct copr_msg); -#endif - unsigned struct_midi_info_sz = sizeof(struct midi_info); - unsigned struct_mtget_sz = sizeof(struct mtget); - unsigned struct_mtop_sz = sizeof(struct mtop); - unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument); - unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec); - unsigned struct_synth_info_sz = sizeof(struct synth_info); - unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); - unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); - unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); - unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); - const unsigned long __sanitizer_bufsiz = BUFSIZ; - - const unsigned IOCTL_NOT_PRESENT = 0; - - unsigned IOCTL_FIOASYNC = FIOASYNC; - unsigned IOCTL_FIOCLEX = FIOCLEX; - unsigned IOCTL_FIOGETOWN = FIOGETOWN; - unsigned IOCTL_FIONBIO = FIONBIO; - unsigned IOCTL_FIONCLEX = FIONCLEX; - unsigned IOCTL_FIOSETOWN = FIOSETOWN; - unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; - unsigned IOCTL_SIOCATMARK = SIOCATMARK; - unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; - unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; - unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; - unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; - unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; - unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; - unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; - unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; - unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; - unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; - unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; - unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; - unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; - unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; - unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; - unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; - unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; - unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; - unsigned IOCTL_TIOCCONS = TIOCCONS; - unsigned IOCTL_TIOCEXCL = TIOCEXCL; - unsigned IOCTL_TIOCGETD = TIOCGETD; - unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; - unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; - unsigned IOCTL_TIOCMBIC = TIOCMBIC; - unsigned IOCTL_TIOCMBIS = TIOCMBIS; - unsigned IOCTL_TIOCMGET = TIOCMGET; - unsigned IOCTL_TIOCMSET = TIOCMSET; - unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; - unsigned IOCTL_TIOCNXCL = TIOCNXCL; - unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; - unsigned IOCTL_TIOCPKT = TIOCPKT; - unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; - unsigned IOCTL_TIOCSETD = TIOCSETD; - unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; - unsigned IOCTL_TIOCSTI = TIOCSTI; - unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; - unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; - unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; - unsigned IOCTL_MTIOCGET = MTIOCGET; - unsigned IOCTL_MTIOCTOP = MTIOCTOP; - unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; - unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; - unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; - unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; - unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; - unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; - unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; - unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; - unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; - unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; - unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; - unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE; - unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR; - unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO; - unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME; - unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE; - unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT; - unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT; - unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS; - unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS; - unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND; - unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC; - unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE; - unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET; - unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES; - unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC; - unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI; - unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD; - unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO; - unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL; - unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE; - unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME; - unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT; - unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE; - unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START; - unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP; - unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO; - unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE; - unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM; - unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS; - unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS; - unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD; - unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK; - unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE; - unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN; - unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX; - unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE; - unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1; - unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2; - unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3; - unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD; - unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC; - unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE; - unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN; - unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM; - unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV; - unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK; - unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC; - unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER; - unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS; - unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH; - unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE; - unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME; - unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM; - unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS; - unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD; - unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE; - unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN; - unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3; - unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD; - unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC; - unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE; - unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN; - unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM; - unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV; - unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC; - unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER; - unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH; - unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE; - unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME; - unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; - unsigned IOCTL_VT_GETMODE = VT_GETMODE; - unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; - unsigned IOCTL_VT_RELDISP = VT_RELDISP; - unsigned IOCTL_VT_SETMODE = VT_SETMODE; - unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; - unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP; - unsigned IOCTL_KDDISABIO = KDDISABIO; - unsigned IOCTL_KDENABIO = KDENABIO; - unsigned IOCTL_KDGETLED = KDGETLED; - unsigned IOCTL_KDGETMODE = KDGETMODE; - unsigned IOCTL_KDGKBMODE = KDGKBMODE; - unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; - unsigned IOCTL_KDMKTONE = KDMKTONE; - unsigned IOCTL_KDSETLED = KDSETLED; - unsigned IOCTL_KDSETMODE = KDSETMODE; - unsigned IOCTL_KDSKBMODE = KDSKBMODE; - unsigned IOCTL_KIOCSOUND = KIOCSOUND; - unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP; - unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; - - const int si_SEGV_MAPERR = SEGV_MAPERR; - const int si_SEGV_ACCERR = SEGV_ACCERR; - const int unvis_valid = UNVIS_VALID; - const int unvis_validpush = UNVIS_VALIDPUSH; -} // namespace __sanitizer - -using namespace __sanitizer; - -COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); - -COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); -CHECK_TYPE_SIZE(pthread_key_t); - -// There are more undocumented fields in dl_phdr_info that we are not interested -// in. -COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); - -CHECK_TYPE_SIZE(glob_t); -CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); -CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); -CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); -CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); -CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); -CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); -CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); -CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); -CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); - -CHECK_TYPE_SIZE(addrinfo); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); - -CHECK_TYPE_SIZE(hostent); -CHECK_SIZE_AND_OFFSET(hostent, h_name); -CHECK_SIZE_AND_OFFSET(hostent, h_aliases); -CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); -CHECK_SIZE_AND_OFFSET(hostent, h_length); -CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); - -CHECK_TYPE_SIZE(iovec); -CHECK_SIZE_AND_OFFSET(iovec, iov_base); -CHECK_SIZE_AND_OFFSET(iovec, iov_len); - -CHECK_TYPE_SIZE(msghdr); -CHECK_SIZE_AND_OFFSET(msghdr, msg_name); -CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); -CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_control); -CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); - -CHECK_TYPE_SIZE(cmsghdr); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); - -COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); -CHECK_SIZE_AND_OFFSET(dirent, d_ino); -CHECK_SIZE_AND_OFFSET(dirent, d_reclen); - -CHECK_TYPE_SIZE(ifconf); -CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); -CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); - -CHECK_TYPE_SIZE(pollfd); -CHECK_SIZE_AND_OFFSET(pollfd, fd); -CHECK_SIZE_AND_OFFSET(pollfd, events); -CHECK_SIZE_AND_OFFSET(pollfd, revents); - -CHECK_TYPE_SIZE(nfds_t); - -CHECK_TYPE_SIZE(sigset_t); - -COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); -// Can't write checks for sa_handler and sa_sigaction due to them being -// preprocessor macros. -CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); - -CHECK_TYPE_SIZE(wordexp_t); -CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); -CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); -CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); - -CHECK_TYPE_SIZE(tm); -CHECK_SIZE_AND_OFFSET(tm, tm_sec); -CHECK_SIZE_AND_OFFSET(tm, tm_min); -CHECK_SIZE_AND_OFFSET(tm, tm_hour); -CHECK_SIZE_AND_OFFSET(tm, tm_mday); -CHECK_SIZE_AND_OFFSET(tm, tm_mon); -CHECK_SIZE_AND_OFFSET(tm, tm_year); -CHECK_SIZE_AND_OFFSET(tm, tm_wday); -CHECK_SIZE_AND_OFFSET(tm, tm_yday); -CHECK_SIZE_AND_OFFSET(tm, tm_isdst); -CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); -CHECK_SIZE_AND_OFFSET(tm, tm_zone); - -CHECK_TYPE_SIZE(ether_addr); - -CHECK_TYPE_SIZE(ipc_perm); -CHECK_SIZE_AND_OFFSET(ipc_perm, key); -CHECK_SIZE_AND_OFFSET(ipc_perm, seq); -CHECK_SIZE_AND_OFFSET(ipc_perm, uid); -CHECK_SIZE_AND_OFFSET(ipc_perm, gid); -CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); -CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); - -CHECK_TYPE_SIZE(shmid_ds); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); - -CHECK_TYPE_SIZE(clock_t); - -CHECK_TYPE_SIZE(ifaddrs); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); -#undef ifa_dstaddr -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); - -CHECK_TYPE_SIZE(timeb); -CHECK_SIZE_AND_OFFSET(timeb, time); -CHECK_SIZE_AND_OFFSET(timeb, millitm); -CHECK_SIZE_AND_OFFSET(timeb, timezone); -CHECK_SIZE_AND_OFFSET(timeb, dstflag); - -CHECK_TYPE_SIZE(passwd); -CHECK_SIZE_AND_OFFSET(passwd, pw_name); -CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); -CHECK_SIZE_AND_OFFSET(passwd, pw_uid); -CHECK_SIZE_AND_OFFSET(passwd, pw_gid); -CHECK_SIZE_AND_OFFSET(passwd, pw_dir); -CHECK_SIZE_AND_OFFSET(passwd, pw_shell); - -CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); - -CHECK_TYPE_SIZE(group); -CHECK_SIZE_AND_OFFSET(group, gr_name); -CHECK_SIZE_AND_OFFSET(group, gr_passwd); -CHECK_SIZE_AND_OFFSET(group, gr_gid); -CHECK_SIZE_AND_OFFSET(group, gr_mem); - -#if HAVE_RPC_XDR_H -CHECK_TYPE_SIZE(XDR); -CHECK_SIZE_AND_OFFSET(XDR, x_op); -CHECK_SIZE_AND_OFFSET(XDR, x_ops); -CHECK_SIZE_AND_OFFSET(XDR, x_public); -CHECK_SIZE_AND_OFFSET(XDR, x_private); -CHECK_SIZE_AND_OFFSET(XDR, x_base); -CHECK_SIZE_AND_OFFSET(XDR, x_handy); -COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE); -COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); -COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); -#endif - -CHECK_TYPE_SIZE(sem_t); - -COMPILER_CHECK(sizeof(__sanitizer_cap_rights_t) >= sizeof(cap_rights_t)); -#endif // SANITIZER_FREEBSD diff --git a/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp b/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp new file mode 100644 index 000000000000..2d1bb1a12da6 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp @@ -0,0 +1,525 @@ +//===-- sanitizer_platform_limits_freebsd.cpp -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific FreeBSD data structures. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_FREEBSD + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _KERNEL // to declare 'shminfo' structure +# include +#undef _KERNEL + +#undef INLINE // to avoid clashes with sanitizers' definitions + +#undef IOC_DIRMASK + +# include +# include +# include + +#include +#include +#include + +// Include these after system headers to avoid name clashes and ambiguities. +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform_limits_freebsd.h" + +namespace __sanitizer { + unsigned struct_cap_rights_sz = sizeof(cap_rights_t); + unsigned struct_utsname_sz = sizeof(struct utsname); + unsigned struct_stat_sz = sizeof(struct stat); + unsigned struct_rusage_sz = sizeof(struct rusage); + unsigned struct_tm_sz = sizeof(struct tm); + unsigned struct_passwd_sz = sizeof(struct passwd); + unsigned struct_group_sz = sizeof(struct group); + unsigned siginfo_t_sz = sizeof(siginfo_t); + unsigned struct_sigaction_sz = sizeof(struct sigaction); + unsigned struct_itimerval_sz = sizeof(struct itimerval); + unsigned pthread_t_sz = sizeof(pthread_t); + unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); + unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); + unsigned pid_t_sz = sizeof(pid_t); + unsigned timeval_sz = sizeof(timeval); + unsigned uid_t_sz = sizeof(uid_t); + unsigned gid_t_sz = sizeof(gid_t); + unsigned fpos_t_sz = sizeof(fpos_t); + unsigned mbstate_t_sz = sizeof(mbstate_t); + unsigned sigset_t_sz = sizeof(sigset_t); + unsigned struct_timezone_sz = sizeof(struct timezone); + unsigned struct_tms_sz = sizeof(struct tms); + unsigned struct_sigevent_sz = sizeof(struct sigevent); + unsigned struct_sched_param_sz = sizeof(struct sched_param); + unsigned struct_statfs_sz = sizeof(struct statfs); + unsigned struct_sockaddr_sz = sizeof(struct sockaddr); + unsigned ucontext_t_sz = sizeof(ucontext_t); + unsigned struct_rlimit_sz = sizeof(struct rlimit); + unsigned struct_timespec_sz = sizeof(struct timespec); + unsigned struct_utimbuf_sz = sizeof(struct utimbuf); + unsigned struct_itimerspec_sz = sizeof(struct itimerspec); + unsigned struct_timeb_sz = sizeof(struct timeb); + unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); + unsigned struct_mq_attr_sz = sizeof(struct mq_attr); + unsigned struct_statvfs_sz = sizeof(struct statvfs); + unsigned struct_shminfo_sz = sizeof(struct shminfo); + unsigned struct_shm_info_sz = sizeof(struct shm_info); + unsigned struct_regmatch_sz = sizeof(regmatch_t); + unsigned struct_regex_sz = sizeof(regex_t); + unsigned struct_fstab_sz = sizeof(struct fstab); + unsigned struct_FTS_sz = sizeof(FTS); + unsigned struct_FTSENT_sz = sizeof(FTSENT); + unsigned struct_StringList_sz = sizeof(StringList); + + const uptr sig_ign = (uptr)SIG_IGN; + const uptr sig_dfl = (uptr)SIG_DFL; + const uptr sig_err = (uptr)SIG_ERR; + const uptr sa_siginfo = (uptr)SA_SIGINFO; + + int shmctl_ipc_stat = (int)IPC_STAT; + int shmctl_ipc_info = (int)IPC_INFO; + int shmctl_shm_info = (int)SHM_INFO; + int shmctl_shm_stat = (int)SHM_STAT; + unsigned struct_utmpx_sz = sizeof(struct utmpx); + + int map_fixed = MAP_FIXED; + + int af_inet = (int)AF_INET; + int af_inet6 = (int)AF_INET6; + + uptr __sanitizer_in_addr_sz(int af) { + if (af == AF_INET) + return sizeof(struct in_addr); + else if (af == AF_INET6) + return sizeof(struct in6_addr); + else + return 0; + } + + unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); + int glob_nomatch = GLOB_NOMATCH; + int glob_altdirfunc = GLOB_ALTDIRFUNC; + + unsigned path_max = PATH_MAX; + + // ioctl arguments + unsigned struct_ifreq_sz = sizeof(struct ifreq); + unsigned struct_termios_sz = sizeof(struct termios); + unsigned struct_winsize_sz = sizeof(struct winsize); +#if SOUND_VERSION >= 0x040000 + unsigned struct_copr_buffer_sz = 0; + unsigned struct_copr_debug_buf_sz = 0; + unsigned struct_copr_msg_sz = 0; +#else + unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer); + unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf); + unsigned struct_copr_msg_sz = sizeof(struct copr_msg); +#endif + unsigned struct_midi_info_sz = sizeof(struct midi_info); + unsigned struct_mtget_sz = sizeof(struct mtget); + unsigned struct_mtop_sz = sizeof(struct mtop); + unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument); + unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec); + unsigned struct_synth_info_sz = sizeof(struct synth_info); + unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); + unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); + unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); + unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); + const unsigned long __sanitizer_bufsiz = BUFSIZ; + + const unsigned IOCTL_NOT_PRESENT = 0; + + unsigned IOCTL_FIOASYNC = FIOASYNC; + unsigned IOCTL_FIOCLEX = FIOCLEX; + unsigned IOCTL_FIOGETOWN = FIOGETOWN; + unsigned IOCTL_FIONBIO = FIONBIO; + unsigned IOCTL_FIONCLEX = FIONCLEX; + unsigned IOCTL_FIOSETOWN = FIOSETOWN; + unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; + unsigned IOCTL_SIOCATMARK = SIOCATMARK; + unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; + unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; + unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; + unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; + unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; + unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; + unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; + unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; + unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; + unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; + unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; + unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; + unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; + unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; + unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; + unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; + unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; + unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; + unsigned IOCTL_TIOCCONS = TIOCCONS; + unsigned IOCTL_TIOCEXCL = TIOCEXCL; + unsigned IOCTL_TIOCGETD = TIOCGETD; + unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; + unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; + unsigned IOCTL_TIOCMBIC = TIOCMBIC; + unsigned IOCTL_TIOCMBIS = TIOCMBIS; + unsigned IOCTL_TIOCMGET = TIOCMGET; + unsigned IOCTL_TIOCMSET = TIOCMSET; + unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; + unsigned IOCTL_TIOCNXCL = TIOCNXCL; + unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; + unsigned IOCTL_TIOCPKT = TIOCPKT; + unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; + unsigned IOCTL_TIOCSETD = TIOCSETD; + unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; + unsigned IOCTL_TIOCSTI = TIOCSTI; + unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; + unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; + unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; + unsigned IOCTL_MTIOCGET = MTIOCGET; + unsigned IOCTL_MTIOCTOP = MTIOCTOP; + unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; + unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; + unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; + unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; + unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; + unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; + unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; + unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; + unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; + unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; + unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; + unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE; + unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR; + unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO; + unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME; + unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE; + unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT; + unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT; + unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS; + unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS; + unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND; + unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC; + unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE; + unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET; + unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES; + unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC; + unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI; + unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD; + unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO; + unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL; + unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE; + unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME; + unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT; + unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE; + unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START; + unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP; + unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO; + unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE; + unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM; + unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS; + unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS; + unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD; + unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK; + unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE; + unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN; + unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX; + unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE; + unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1; + unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2; + unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3; + unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD; + unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC; + unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE; + unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN; + unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM; + unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV; + unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK; + unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC; + unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER; + unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS; + unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH; + unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE; + unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME; + unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM; + unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS; + unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD; + unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE; + unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN; + unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX; + unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE; + unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1; + unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2; + unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3; + unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD; + unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC; + unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE; + unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN; + unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM; + unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV; + unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC; + unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER; + unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH; + unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE; + unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME; + unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; + unsigned IOCTL_VT_GETMODE = VT_GETMODE; + unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; + unsigned IOCTL_VT_RELDISP = VT_RELDISP; + unsigned IOCTL_VT_SETMODE = VT_SETMODE; + unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; + unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP; + unsigned IOCTL_KDDISABIO = KDDISABIO; + unsigned IOCTL_KDENABIO = KDENABIO; + unsigned IOCTL_KDGETLED = KDGETLED; + unsigned IOCTL_KDGETMODE = KDGETMODE; + unsigned IOCTL_KDGKBMODE = KDGKBMODE; + unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; + unsigned IOCTL_KDMKTONE = KDMKTONE; + unsigned IOCTL_KDSETLED = KDSETLED; + unsigned IOCTL_KDSETMODE = KDSETMODE; + unsigned IOCTL_KDSKBMODE = KDSKBMODE; + unsigned IOCTL_KIOCSOUND = KIOCSOUND; + unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP; + unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; + + const int si_SEGV_MAPERR = SEGV_MAPERR; + const int si_SEGV_ACCERR = SEGV_ACCERR; + const int unvis_valid = UNVIS_VALID; + const int unvis_validpush = UNVIS_VALIDPUSH; +} // namespace __sanitizer + +using namespace __sanitizer; + +COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); + +COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); +CHECK_TYPE_SIZE(pthread_key_t); + +// There are more undocumented fields in dl_phdr_info that we are not interested +// in. +COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); + +CHECK_TYPE_SIZE(glob_t); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); +CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); +CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); +CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); +CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); + +CHECK_TYPE_SIZE(addrinfo); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); + +CHECK_TYPE_SIZE(hostent); +CHECK_SIZE_AND_OFFSET(hostent, h_name); +CHECK_SIZE_AND_OFFSET(hostent, h_aliases); +CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); +CHECK_SIZE_AND_OFFSET(hostent, h_length); +CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); + +CHECK_TYPE_SIZE(iovec); +CHECK_SIZE_AND_OFFSET(iovec, iov_base); +CHECK_SIZE_AND_OFFSET(iovec, iov_len); + +CHECK_TYPE_SIZE(msghdr); +CHECK_SIZE_AND_OFFSET(msghdr, msg_name); +CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_control); +CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); + +CHECK_TYPE_SIZE(cmsghdr); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); + +COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); +CHECK_SIZE_AND_OFFSET(dirent, d_ino); +CHECK_SIZE_AND_OFFSET(dirent, d_reclen); + +CHECK_TYPE_SIZE(ifconf); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); + +CHECK_TYPE_SIZE(pollfd); +CHECK_SIZE_AND_OFFSET(pollfd, fd); +CHECK_SIZE_AND_OFFSET(pollfd, events); +CHECK_SIZE_AND_OFFSET(pollfd, revents); + +CHECK_TYPE_SIZE(nfds_t); + +CHECK_TYPE_SIZE(sigset_t); + +COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); +// Can't write checks for sa_handler and sa_sigaction due to them being +// preprocessor macros. +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); + +CHECK_TYPE_SIZE(wordexp_t); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); + +CHECK_TYPE_SIZE(tm); +CHECK_SIZE_AND_OFFSET(tm, tm_sec); +CHECK_SIZE_AND_OFFSET(tm, tm_min); +CHECK_SIZE_AND_OFFSET(tm, tm_hour); +CHECK_SIZE_AND_OFFSET(tm, tm_mday); +CHECK_SIZE_AND_OFFSET(tm, tm_mon); +CHECK_SIZE_AND_OFFSET(tm, tm_year); +CHECK_SIZE_AND_OFFSET(tm, tm_wday); +CHECK_SIZE_AND_OFFSET(tm, tm_yday); +CHECK_SIZE_AND_OFFSET(tm, tm_isdst); +CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); +CHECK_SIZE_AND_OFFSET(tm, tm_zone); + +CHECK_TYPE_SIZE(ether_addr); + +CHECK_TYPE_SIZE(ipc_perm); +CHECK_SIZE_AND_OFFSET(ipc_perm, key); +CHECK_SIZE_AND_OFFSET(ipc_perm, seq); +CHECK_SIZE_AND_OFFSET(ipc_perm, uid); +CHECK_SIZE_AND_OFFSET(ipc_perm, gid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); + +CHECK_TYPE_SIZE(shmid_ds); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); + +CHECK_TYPE_SIZE(clock_t); + +CHECK_TYPE_SIZE(ifaddrs); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); +#undef ifa_dstaddr +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); + +CHECK_TYPE_SIZE(timeb); +CHECK_SIZE_AND_OFFSET(timeb, time); +CHECK_SIZE_AND_OFFSET(timeb, millitm); +CHECK_SIZE_AND_OFFSET(timeb, timezone); +CHECK_SIZE_AND_OFFSET(timeb, dstflag); + +CHECK_TYPE_SIZE(passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_name); +CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_uid); +CHECK_SIZE_AND_OFFSET(passwd, pw_gid); +CHECK_SIZE_AND_OFFSET(passwd, pw_dir); +CHECK_SIZE_AND_OFFSET(passwd, pw_shell); + +CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); + +CHECK_TYPE_SIZE(group); +CHECK_SIZE_AND_OFFSET(group, gr_name); +CHECK_SIZE_AND_OFFSET(group, gr_passwd); +CHECK_SIZE_AND_OFFSET(group, gr_gid); +CHECK_SIZE_AND_OFFSET(group, gr_mem); + +#if HAVE_RPC_XDR_H +CHECK_TYPE_SIZE(XDR); +CHECK_SIZE_AND_OFFSET(XDR, x_op); +CHECK_SIZE_AND_OFFSET(XDR, x_ops); +CHECK_SIZE_AND_OFFSET(XDR, x_public); +CHECK_SIZE_AND_OFFSET(XDR, x_private); +CHECK_SIZE_AND_OFFSET(XDR, x_base); +CHECK_SIZE_AND_OFFSET(XDR, x_handy); +COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE); +COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); +COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); +#endif + +CHECK_TYPE_SIZE(sem_t); + +COMPILER_CHECK(sizeof(__sanitizer_cap_rights_t) >= sizeof(cap_rights_t)); +#endif // SANITIZER_FREEBSD diff --git a/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h b/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h index 7e162a5e49d7..71cf5b9c3571 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h @@ -30,373 +30,373 @@ #include namespace __sanitizer { - extern unsigned struct_utsname_sz; - extern unsigned struct_stat_sz; +extern unsigned struct_utsname_sz; +extern unsigned struct_stat_sz; #if defined(__powerpc64__) - const unsigned struct___old_kernel_stat_sz = 0; +const unsigned struct___old_kernel_stat_sz = 0; #else - const unsigned struct___old_kernel_stat_sz = 32; +const unsigned struct___old_kernel_stat_sz = 32; #endif - extern unsigned struct_rusage_sz; - extern unsigned siginfo_t_sz; - extern unsigned struct_itimerval_sz; - extern unsigned pthread_t_sz; - extern unsigned pthread_mutex_t_sz; - extern unsigned pthread_cond_t_sz; - extern unsigned pid_t_sz; - extern unsigned timeval_sz; - extern unsigned uid_t_sz; - extern unsigned gid_t_sz; - extern unsigned fpos_t_sz; - extern unsigned mbstate_t_sz; - extern unsigned struct_timezone_sz; - extern unsigned struct_tms_sz; - extern unsigned struct_itimerspec_sz; - extern unsigned struct_sigevent_sz; - extern unsigned struct_sched_param_sz; - extern unsigned struct_statfs64_sz; - extern unsigned struct_statfs_sz; - extern unsigned struct_sockaddr_sz; - extern unsigned ucontext_t_sz; - extern unsigned struct_rlimit_sz; - extern unsigned struct_utimbuf_sz; - extern unsigned struct_timespec_sz; - extern unsigned struct_regmatch_sz; - extern unsigned struct_regex_sz; - extern unsigned struct_FTS_sz; - extern unsigned struct_FTSENT_sz; - extern const int unvis_valid; - extern const int unvis_validpush; - - struct __sanitizer_iocb { - u64 aio_data; - u32 aio_key_or_aio_reserved1; // Simply crazy. - u32 aio_reserved1_or_aio_key; // Luckily, we don't need these. - u16 aio_lio_opcode; - s16 aio_reqprio; - u32 aio_fildes; - u64 aio_buf; - u64 aio_nbytes; - s64 aio_offset; - u64 aio_reserved2; - u64 aio_reserved3; - }; - - struct __sanitizer_io_event { - u64 data; - u64 obj; - u64 res; - u64 res2; - }; - - const unsigned iocb_cmd_pread = 0; - const unsigned iocb_cmd_pwrite = 1; - const unsigned iocb_cmd_preadv = 7; - const unsigned iocb_cmd_pwritev = 8; - - struct __sanitizer___sysctl_args { - int *name; - int nlen; - void *oldval; - uptr *oldlenp; - void *newval; - uptr newlen; - unsigned long ___unused[4]; - }; - - struct __sanitizer_ipc_perm { - unsigned int cuid; - unsigned int cgid; - unsigned int uid; - unsigned int gid; - unsigned short mode; - unsigned short seq; - long key; - }; - - struct __sanitizer_shmid_ds { - __sanitizer_ipc_perm shm_perm; - unsigned long shm_segsz; - unsigned int shm_lpid; - unsigned int shm_cpid; - int shm_nattch; - unsigned long shm_atime; - unsigned long shm_dtime; - unsigned long shm_ctime; - }; - - extern unsigned struct_msqid_ds_sz; - extern unsigned struct_mq_attr_sz; - extern unsigned struct_timeb_sz; - extern unsigned struct_statvfs_sz; - - struct __sanitizer_iovec { - void *iov_base; - uptr iov_len; - }; - - struct __sanitizer_ifaddrs { - struct __sanitizer_ifaddrs *ifa_next; - char *ifa_name; - unsigned int ifa_flags; - void *ifa_addr; // (struct sockaddr *) - void *ifa_netmask; // (struct sockaddr *) -# undef ifa_dstaddr - void *ifa_dstaddr; // (struct sockaddr *) - void *ifa_data; - }; - - typedef unsigned __sanitizer_pthread_key_t; - - struct __sanitizer_passwd { - char *pw_name; - char *pw_passwd; - int pw_uid; - int pw_gid; - long pw_change; - char *pw_class; - char *pw_gecos; - char *pw_dir; - char *pw_shell; - long pw_expire; - int pw_fields; - }; - - struct __sanitizer_group { - char *gr_name; - char *gr_passwd; - int gr_gid; - char **gr_mem; - }; - -#if defined(__LP64___) - typedef long long __sanitizer_time_t; +extern unsigned struct_rusage_sz; +extern unsigned siginfo_t_sz; +extern unsigned struct_itimerval_sz; +extern unsigned pthread_t_sz; +extern unsigned pthread_mutex_t_sz; +extern unsigned pthread_cond_t_sz; +extern unsigned pid_t_sz; +extern unsigned timeval_sz; +extern unsigned uid_t_sz; +extern unsigned gid_t_sz; +extern unsigned fpos_t_sz; +extern unsigned mbstate_t_sz; +extern unsigned struct_timezone_sz; +extern unsigned struct_tms_sz; +extern unsigned struct_itimerspec_sz; +extern unsigned struct_sigevent_sz; +extern unsigned struct_sched_param_sz; +extern unsigned struct_statfs64_sz; +extern unsigned struct_statfs_sz; +extern unsigned struct_sockaddr_sz; +extern unsigned ucontext_t_sz; +extern unsigned struct_rlimit_sz; +extern unsigned struct_utimbuf_sz; +extern unsigned struct_timespec_sz; +extern unsigned struct_regmatch_sz; +extern unsigned struct_regex_sz; +extern unsigned struct_FTS_sz; +extern unsigned struct_FTSENT_sz; +extern const int unvis_valid; +extern const int unvis_validpush; + +struct __sanitizer_iocb { + u64 aio_data; + u32 aio_key_or_aio_reserved1; // Simply crazy. + u32 aio_reserved1_or_aio_key; // Luckily, we don't need these. + u16 aio_lio_opcode; + s16 aio_reqprio; + u32 aio_fildes; + u64 aio_buf; + u64 aio_nbytes; + s64 aio_offset; + u64 aio_reserved2; + u64 aio_reserved3; +}; + +struct __sanitizer_io_event { + u64 data; + u64 obj; + u64 res; + u64 res2; +}; + +const unsigned iocb_cmd_pread = 0; +const unsigned iocb_cmd_pwrite = 1; +const unsigned iocb_cmd_preadv = 7; +const unsigned iocb_cmd_pwritev = 8; + +struct __sanitizer___sysctl_args { + int *name; + int nlen; + void *oldval; + uptr *oldlenp; + void *newval; + uptr newlen; + unsigned long ___unused[4]; +}; + +struct __sanitizer_ipc_perm { + unsigned int cuid; + unsigned int cgid; + unsigned int uid; + unsigned int gid; + unsigned short mode; + unsigned short seq; + long key; +}; + +#if !defined(__i386__) +typedef long long __sanitizer_time_t; #else - typedef long __sanitizer_time_t; +typedef long __sanitizer_time_t; #endif - typedef long __sanitizer_suseconds_t; - - struct __sanitizer_timeval { - __sanitizer_time_t tv_sec; - __sanitizer_suseconds_t tv_usec; - }; - - struct __sanitizer_itimerval { - struct __sanitizer_timeval it_interval; - struct __sanitizer_timeval it_value; - }; - - struct __sanitizer_timeb { - __sanitizer_time_t time; - unsigned short millitm; - short timezone; - short dstflag; - }; - - struct __sanitizer_ether_addr { - u8 octet[6]; - }; - - struct __sanitizer_tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; - long int tm_gmtoff; - const char *tm_zone; - }; - - struct __sanitizer_msghdr { - void *msg_name; - unsigned msg_namelen; - struct __sanitizer_iovec *msg_iov; - unsigned msg_iovlen; - void *msg_control; - unsigned msg_controllen; - int msg_flags; - }; - - struct __sanitizer_cmsghdr { - unsigned cmsg_len; - int cmsg_level; - int cmsg_type; - }; - - struct __sanitizer_dirent { +struct __sanitizer_shmid_ds { + __sanitizer_ipc_perm shm_perm; + unsigned long shm_segsz; + unsigned int shm_lpid; + unsigned int shm_cpid; + int shm_nattch; + __sanitizer_time_t shm_atime; + __sanitizer_time_t shm_dtime; + __sanitizer_time_t shm_ctime; +}; + +extern unsigned struct_msqid_ds_sz; +extern unsigned struct_mq_attr_sz; +extern unsigned struct_timeb_sz; +extern unsigned struct_statvfs_sz; + +struct __sanitizer_iovec { + void *iov_base; + uptr iov_len; +}; + +struct __sanitizer_ifaddrs { + struct __sanitizer_ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + void *ifa_addr; // (struct sockaddr *) + void *ifa_netmask; // (struct sockaddr *) +# undef ifa_dstaddr + void *ifa_dstaddr; // (struct sockaddr *) + void *ifa_data; +}; + +typedef unsigned __sanitizer_pthread_key_t; + +struct __sanitizer_passwd { + char *pw_name; + char *pw_passwd; + int pw_uid; + int pw_gid; + __sanitizer_time_t pw_change; + char *pw_class; + char *pw_gecos; + char *pw_dir; + char *pw_shell; + __sanitizer_time_t pw_expire; + int pw_fields; +}; + +struct __sanitizer_group { + char *gr_name; + char *gr_passwd; + int gr_gid; + char **gr_mem; +}; + +typedef long __sanitizer_suseconds_t; + +struct __sanitizer_timeval { + __sanitizer_time_t tv_sec; + __sanitizer_suseconds_t tv_usec; +}; + +struct __sanitizer_itimerval { + struct __sanitizer_timeval it_interval; + struct __sanitizer_timeval it_value; +}; + +struct __sanitizer_timeb { + __sanitizer_time_t time; + unsigned short millitm; + short timezone; + short dstflag; +}; + +struct __sanitizer_ether_addr { + u8 octet[6]; +}; + +struct __sanitizer_tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long int tm_gmtoff; + const char *tm_zone; +}; + +struct __sanitizer_msghdr { + void *msg_name; + unsigned msg_namelen; + struct __sanitizer_iovec *msg_iov; + unsigned msg_iovlen; + void *msg_control; + unsigned msg_controllen; + int msg_flags; +}; + +struct __sanitizer_cmsghdr { + unsigned cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +struct __sanitizer_dirent { #if defined(__INO64) - unsigned long long d_fileno; - unsigned long long d_off; + unsigned long long d_fileno; + unsigned long long d_off; #else - unsigned int d_fileno; + unsigned int d_fileno; #endif - unsigned short d_reclen; - // more fields that we don't care about - }; + unsigned short d_reclen; + // more fields that we don't care about +}; // 'clock_t' is 32 bits wide on x64 FreeBSD - typedef int __sanitizer_clock_t; - typedef int __sanitizer_clockid_t; +typedef int __sanitizer_clock_t; +typedef int __sanitizer_clockid_t; -#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__)\ - || defined(__mips__) - typedef unsigned __sanitizer___kernel_uid_t; - typedef unsigned __sanitizer___kernel_gid_t; +#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__) || \ + defined(__mips__) +typedef unsigned __sanitizer___kernel_uid_t; +typedef unsigned __sanitizer___kernel_gid_t; #else - typedef unsigned short __sanitizer___kernel_uid_t; - typedef unsigned short __sanitizer___kernel_gid_t; +typedef unsigned short __sanitizer___kernel_uid_t; +typedef unsigned short __sanitizer___kernel_gid_t; #endif - typedef long long __sanitizer___kernel_off_t; +typedef long long __sanitizer___kernel_off_t; #if defined(__powerpc__) || defined(__mips__) - typedef unsigned int __sanitizer___kernel_old_uid_t; - typedef unsigned int __sanitizer___kernel_old_gid_t; +typedef unsigned int __sanitizer___kernel_old_uid_t; +typedef unsigned int __sanitizer___kernel_old_gid_t; #else - typedef unsigned short __sanitizer___kernel_old_uid_t; - typedef unsigned short __sanitizer___kernel_old_gid_t; +typedef unsigned short __sanitizer___kernel_old_uid_t; +typedef unsigned short __sanitizer___kernel_old_gid_t; #endif - typedef long long __sanitizer___kernel_loff_t; - typedef struct { - unsigned long fds_bits[1024 / (8 * sizeof(long))]; - } __sanitizer___kernel_fd_set; - - // This thing depends on the platform. We are only interested in the upper - // limit. Verified with a compiler assert in .cc. - const int pthread_attr_t_max_sz = 128; - union __sanitizer_pthread_attr_t { - char size[pthread_attr_t_max_sz]; // NOLINT - void *align; - }; - - const unsigned old_sigset_t_sz = sizeof(unsigned long); - - struct __sanitizer_sigset_t { - // uint32_t * 4 - unsigned int __bits[4]; - }; - - typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t; - - struct __sanitizer_siginfo { - // The size is determined by looking at sizeof of real siginfo_t on linux. - u64 opaque[128 / sizeof(u64)]; - }; - - using __sanitizer_sighandler_ptr = void (*)(int sig); - using __sanitizer_sigactionhandler_ptr = - void (*)(int sig, __sanitizer_siginfo *siginfo, void *uctx); - - struct __sanitizer_sigaction { - union { - __sanitizer_sigactionhandler_ptr sigaction; - __sanitizer_sighandler_ptr handler; - }; - int sa_flags; - __sanitizer_sigset_t sa_mask; - }; - - struct __sanitizer_sem_t { - u32 data[4]; - }; - - extern const uptr sig_ign; - extern const uptr sig_dfl; - extern const uptr sig_err; - extern const uptr sa_siginfo; - - extern int af_inet; - extern int af_inet6; - uptr __sanitizer_in_addr_sz(int af); - - struct __sanitizer_dl_phdr_info { - uptr dlpi_addr; - const char *dlpi_name; - const void *dlpi_phdr; - short dlpi_phnum; - }; - - extern unsigned struct_ElfW_Phdr_sz; - - struct __sanitizer_addrinfo { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - unsigned ai_addrlen; - char *ai_canonname; - void *ai_addr; - struct __sanitizer_addrinfo *ai_next; - }; - - struct __sanitizer_hostent { - char *h_name; - char **h_aliases; - int h_addrtype; - int h_length; - char **h_addr_list; - }; - - struct __sanitizer_pollfd { - int fd; - short events; - short revents; - }; - - typedef unsigned __sanitizer_nfds_t; - - struct __sanitizer_glob_t { - uptr gl_pathc; - uptr gl_matchc; - uptr gl_offs; - int gl_flags; - char **gl_pathv; - int (*gl_errfunc)(const char*, int); - void (*gl_closedir)(void *dirp); - struct dirent *(*gl_readdir)(void *dirp); - void *(*gl_opendir)(const char*); - int (*gl_lstat)(const char*, void* /* struct stat* */); - int (*gl_stat)(const char*, void* /* struct stat* */); - }; - - extern int glob_nomatch; - extern int glob_altdirfunc; - - extern unsigned path_max; - - struct __sanitizer_wordexp_t { - uptr we_wordc; - char **we_wordv; - uptr we_offs; - char *we_strings; - uptr we_nbytes; - }; - - typedef void __sanitizer_FILE; - - extern unsigned struct_shminfo_sz; - extern unsigned struct_shm_info_sz; - extern int shmctl_ipc_stat; - extern int shmctl_ipc_info; - extern int shmctl_shm_info; - extern int shmctl_shm_stat; - - extern unsigned struct_utmpx_sz; - - extern int map_fixed; - - // ioctl arguments - struct __sanitizer_ifconf { - int ifc_len; - union { - void *ifcu_req; - } ifc_ifcu; +typedef long long __sanitizer___kernel_loff_t; +typedef struct { + unsigned long fds_bits[1024 / (8 * sizeof(long))]; +} __sanitizer___kernel_fd_set; + +// This thing depends on the platform. We are only interested in the upper +// limit. Verified with a compiler assert in .cpp. +union __sanitizer_pthread_attr_t { + char size[128]; + void *align; +}; + +const unsigned old_sigset_t_sz = sizeof(unsigned long); + +struct __sanitizer_sigset_t { + // uint32_t * 4 + unsigned int __bits[4]; +}; + +typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t; + +struct __sanitizer_siginfo { + // The size is determined by looking at sizeof of real siginfo_t on linux. + u64 opaque[128 / sizeof(u64)]; +}; + +using __sanitizer_sighandler_ptr = void (*)(int sig); +using __sanitizer_sigactionhandler_ptr = void (*)(int sig, + __sanitizer_siginfo *siginfo, + void *uctx); + +struct __sanitizer_sigaction { + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; }; + int sa_flags; + __sanitizer_sigset_t sa_mask; +}; + +struct __sanitizer_sem_t { + u32 data[4]; +}; + +extern const uptr sig_ign; +extern const uptr sig_dfl; +extern const uptr sig_err; +extern const uptr sa_siginfo; + +extern int af_inet; +extern int af_inet6; +uptr __sanitizer_in_addr_sz(int af); + +struct __sanitizer_dl_phdr_info { + uptr dlpi_addr; + const char *dlpi_name; + const void *dlpi_phdr; + short dlpi_phnum; +}; + +extern unsigned struct_ElfW_Phdr_sz; + +struct __sanitizer_addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + unsigned ai_addrlen; + char *ai_canonname; + void *ai_addr; + struct __sanitizer_addrinfo *ai_next; +}; + +struct __sanitizer_hostent { + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; +}; + +struct __sanitizer_pollfd { + int fd; + short events; + short revents; +}; + +typedef unsigned __sanitizer_nfds_t; + +struct __sanitizer_glob_t { + uptr gl_pathc; + uptr gl_matchc; + uptr gl_offs; + int gl_flags; + char **gl_pathv; + int (*gl_errfunc)(const char *, int); + void (*gl_closedir)(void *dirp); + struct dirent *(*gl_readdir)(void *dirp); + void *(*gl_opendir)(const char *); + int (*gl_lstat)(const char *, void * /* struct stat* */); + int (*gl_stat)(const char *, void * /* struct stat* */); +}; + +extern int glob_nomatch; +extern int glob_altdirfunc; + +extern unsigned path_max; + +struct __sanitizer_wordexp_t { + uptr we_wordc; + char **we_wordv; + uptr we_offs; + char *we_strings; + uptr we_nbytes; +}; + +typedef void __sanitizer_FILE; + +extern unsigned struct_shminfo_sz; +extern unsigned struct_shm_info_sz; +extern int shmctl_ipc_stat; +extern int shmctl_ipc_info; +extern int shmctl_shm_info; +extern int shmctl_shm_stat; + +extern unsigned struct_utmpx_sz; + +extern int map_fixed; + +// ioctl arguments +struct __sanitizer_ifconf { + int ifc_len; + union { + void *ifcu_req; + } ifc_ifcu; +}; #define IOC_NRBITS 8 #define IOC_TYPEBITS 8 @@ -432,204 +432,204 @@ namespace __sanitizer { #define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK) #define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) - extern unsigned struct_ifreq_sz; - extern unsigned struct_termios_sz; - extern unsigned struct_winsize_sz; - - extern unsigned struct_copr_buffer_sz; - extern unsigned struct_copr_debug_buf_sz; - extern unsigned struct_copr_msg_sz; - extern unsigned struct_midi_info_sz; - extern unsigned struct_mtget_sz; - extern unsigned struct_mtop_sz; - extern unsigned struct_rtentry_sz; - extern unsigned struct_sbi_instrument_sz; - extern unsigned struct_seq_event_rec_sz; - extern unsigned struct_synth_info_sz; - extern unsigned struct_vt_mode_sz; - - extern const unsigned long __sanitizer_bufsiz; - extern unsigned struct_audio_buf_info_sz; - extern unsigned struct_ppp_stats_sz; - extern unsigned struct_sioc_sg_req_sz; - extern unsigned struct_sioc_vif_req_sz; - - // ioctl request identifiers - - // A special value to mark ioctls that are not present on the target platform, - // when it can not be determined without including any system headers. - extern const unsigned IOCTL_NOT_PRESENT; - - extern unsigned IOCTL_FIOASYNC; - extern unsigned IOCTL_FIOCLEX; - extern unsigned IOCTL_FIOGETOWN; - extern unsigned IOCTL_FIONBIO; - extern unsigned IOCTL_FIONCLEX; - extern unsigned IOCTL_FIOSETOWN; - extern unsigned IOCTL_SIOCADDMULTI; - extern unsigned IOCTL_SIOCATMARK; - extern unsigned IOCTL_SIOCDELMULTI; - extern unsigned IOCTL_SIOCGIFADDR; - extern unsigned IOCTL_SIOCGIFBRDADDR; - extern unsigned IOCTL_SIOCGIFCONF; - extern unsigned IOCTL_SIOCGIFDSTADDR; - extern unsigned IOCTL_SIOCGIFFLAGS; - extern unsigned IOCTL_SIOCGIFMETRIC; - extern unsigned IOCTL_SIOCGIFMTU; - extern unsigned IOCTL_SIOCGIFNETMASK; - extern unsigned IOCTL_SIOCGPGRP; - extern unsigned IOCTL_SIOCSIFADDR; - extern unsigned IOCTL_SIOCSIFBRDADDR; - extern unsigned IOCTL_SIOCSIFDSTADDR; - extern unsigned IOCTL_SIOCSIFFLAGS; - extern unsigned IOCTL_SIOCSIFMETRIC; - extern unsigned IOCTL_SIOCSIFMTU; - extern unsigned IOCTL_SIOCSIFNETMASK; - extern unsigned IOCTL_SIOCSPGRP; - extern unsigned IOCTL_TIOCCONS; - extern unsigned IOCTL_TIOCEXCL; - extern unsigned IOCTL_TIOCGETD; - extern unsigned IOCTL_TIOCGPGRP; - extern unsigned IOCTL_TIOCGWINSZ; - extern unsigned IOCTL_TIOCMBIC; - extern unsigned IOCTL_TIOCMBIS; - extern unsigned IOCTL_TIOCMGET; - extern unsigned IOCTL_TIOCMSET; - extern unsigned IOCTL_TIOCNOTTY; - extern unsigned IOCTL_TIOCNXCL; - extern unsigned IOCTL_TIOCOUTQ; - extern unsigned IOCTL_TIOCPKT; - extern unsigned IOCTL_TIOCSCTTY; - extern unsigned IOCTL_TIOCSETD; - extern unsigned IOCTL_TIOCSPGRP; - extern unsigned IOCTL_TIOCSTI; - extern unsigned IOCTL_TIOCSWINSZ; - extern unsigned IOCTL_SIOCGETSGCNT; - extern unsigned IOCTL_SIOCGETVIFCNT; - extern unsigned IOCTL_MTIOCGET; - extern unsigned IOCTL_MTIOCTOP; - extern unsigned IOCTL_SIOCADDRT; - extern unsigned IOCTL_SIOCDELRT; - extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; - extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; - extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; - extern unsigned IOCTL_SNDCTL_DSP_POST; - extern unsigned IOCTL_SNDCTL_DSP_RESET; - extern unsigned IOCTL_SNDCTL_DSP_SETFMT; - extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; - extern unsigned IOCTL_SNDCTL_DSP_SPEED; - extern unsigned IOCTL_SNDCTL_DSP_STEREO; - extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; - extern unsigned IOCTL_SNDCTL_DSP_SYNC; - extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE; - extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR; - extern unsigned IOCTL_SNDCTL_MIDI_INFO; - extern unsigned IOCTL_SNDCTL_MIDI_PRETIME; - extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE; - extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT; - extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT; - extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS; - extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS; - extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND; - extern unsigned IOCTL_SNDCTL_SEQ_PANIC; - extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE; - extern unsigned IOCTL_SNDCTL_SEQ_RESET; - extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES; - extern unsigned IOCTL_SNDCTL_SEQ_SYNC; - extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI; - extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD; - extern unsigned IOCTL_SNDCTL_SYNTH_INFO; - extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL; - extern unsigned IOCTL_SNDCTL_TMR_CONTINUE; - extern unsigned IOCTL_SNDCTL_TMR_METRONOME; - extern unsigned IOCTL_SNDCTL_TMR_SELECT; - extern unsigned IOCTL_SNDCTL_TMR_SOURCE; - extern unsigned IOCTL_SNDCTL_TMR_START; - extern unsigned IOCTL_SNDCTL_TMR_STOP; - extern unsigned IOCTL_SNDCTL_TMR_TEMPO; - extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE; - extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM; - extern unsigned IOCTL_SOUND_MIXER_READ_BASS; - extern unsigned IOCTL_SOUND_MIXER_READ_CAPS; - extern unsigned IOCTL_SOUND_MIXER_READ_CD; - extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK; - extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE; - extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN; - extern unsigned IOCTL_SOUND_MIXER_READ_IMIX; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE1; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE2; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE3; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE; - extern unsigned IOCTL_SOUND_MIXER_READ_LOUD; - extern unsigned IOCTL_SOUND_MIXER_READ_MIC; - extern unsigned IOCTL_SOUND_MIXER_READ_MUTE; - extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN; - extern unsigned IOCTL_SOUND_MIXER_READ_PCM; - extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV; - extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK; - extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC; - extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER; - extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS; - extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH; - extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE; - extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME; - extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM; - extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS; - extern unsigned IOCTL_SOUND_MIXER_WRITE_CD; - extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN; - extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD; - extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC; - extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN; - extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM; - extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV; - extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC; - extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER; - extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH; - extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME; - extern unsigned IOCTL_SOUND_PCM_READ_BITS; - extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; - extern unsigned IOCTL_SOUND_PCM_READ_FILTER; - extern unsigned IOCTL_SOUND_PCM_READ_RATE; - extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS; - extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; - extern unsigned IOCTL_VT_ACTIVATE; - extern unsigned IOCTL_VT_GETMODE; - extern unsigned IOCTL_VT_OPENQRY; - extern unsigned IOCTL_VT_RELDISP; - extern unsigned IOCTL_VT_SETMODE; - extern unsigned IOCTL_VT_WAITACTIVE; - extern unsigned IOCTL_GIO_SCRNMAP; - extern unsigned IOCTL_KDDISABIO; - extern unsigned IOCTL_KDENABIO; - extern unsigned IOCTL_KDGETLED; - extern unsigned IOCTL_KDGETMODE; - extern unsigned IOCTL_KDGKBMODE; - extern unsigned IOCTL_KDGKBTYPE; - extern unsigned IOCTL_KDMKTONE; - extern unsigned IOCTL_KDSETLED; - extern unsigned IOCTL_KDSETMODE; - extern unsigned IOCTL_KDSKBMODE; - - extern const int si_SEGV_MAPERR; - extern const int si_SEGV_ACCERR; - - struct __sanitizer_cap_rights { - u64 cr_rights[2]; - }; - - typedef struct __sanitizer_cap_rights __sanitizer_cap_rights_t; - extern unsigned struct_cap_rights_sz; - - extern unsigned struct_fstab_sz; - extern unsigned struct_StringList_sz; +extern unsigned struct_ifreq_sz; +extern unsigned struct_termios_sz; +extern unsigned struct_winsize_sz; + +extern unsigned struct_copr_buffer_sz; +extern unsigned struct_copr_debug_buf_sz; +extern unsigned struct_copr_msg_sz; +extern unsigned struct_midi_info_sz; +extern unsigned struct_mtget_sz; +extern unsigned struct_mtop_sz; +extern unsigned struct_rtentry_sz; +extern unsigned struct_sbi_instrument_sz; +extern unsigned struct_seq_event_rec_sz; +extern unsigned struct_synth_info_sz; +extern unsigned struct_vt_mode_sz; + +extern const unsigned long __sanitizer_bufsiz; +extern unsigned struct_audio_buf_info_sz; +extern unsigned struct_ppp_stats_sz; +extern unsigned struct_sioc_sg_req_sz; +extern unsigned struct_sioc_vif_req_sz; + +// ioctl request identifiers + +// A special value to mark ioctls that are not present on the target platform, +// when it can not be determined without including any system headers. +extern const unsigned IOCTL_NOT_PRESENT; + +extern unsigned IOCTL_FIOASYNC; +extern unsigned IOCTL_FIOCLEX; +extern unsigned IOCTL_FIOGETOWN; +extern unsigned IOCTL_FIONBIO; +extern unsigned IOCTL_FIONCLEX; +extern unsigned IOCTL_FIOSETOWN; +extern unsigned IOCTL_SIOCADDMULTI; +extern unsigned IOCTL_SIOCATMARK; +extern unsigned IOCTL_SIOCDELMULTI; +extern unsigned IOCTL_SIOCGIFADDR; +extern unsigned IOCTL_SIOCGIFBRDADDR; +extern unsigned IOCTL_SIOCGIFCONF; +extern unsigned IOCTL_SIOCGIFDSTADDR; +extern unsigned IOCTL_SIOCGIFFLAGS; +extern unsigned IOCTL_SIOCGIFMETRIC; +extern unsigned IOCTL_SIOCGIFMTU; +extern unsigned IOCTL_SIOCGIFNETMASK; +extern unsigned IOCTL_SIOCGPGRP; +extern unsigned IOCTL_SIOCSIFADDR; +extern unsigned IOCTL_SIOCSIFBRDADDR; +extern unsigned IOCTL_SIOCSIFDSTADDR; +extern unsigned IOCTL_SIOCSIFFLAGS; +extern unsigned IOCTL_SIOCSIFMETRIC; +extern unsigned IOCTL_SIOCSIFMTU; +extern unsigned IOCTL_SIOCSIFNETMASK; +extern unsigned IOCTL_SIOCSPGRP; +extern unsigned IOCTL_TIOCCONS; +extern unsigned IOCTL_TIOCEXCL; +extern unsigned IOCTL_TIOCGETD; +extern unsigned IOCTL_TIOCGPGRP; +extern unsigned IOCTL_TIOCGWINSZ; +extern unsigned IOCTL_TIOCMBIC; +extern unsigned IOCTL_TIOCMBIS; +extern unsigned IOCTL_TIOCMGET; +extern unsigned IOCTL_TIOCMSET; +extern unsigned IOCTL_TIOCNOTTY; +extern unsigned IOCTL_TIOCNXCL; +extern unsigned IOCTL_TIOCOUTQ; +extern unsigned IOCTL_TIOCPKT; +extern unsigned IOCTL_TIOCSCTTY; +extern unsigned IOCTL_TIOCSETD; +extern unsigned IOCTL_TIOCSPGRP; +extern unsigned IOCTL_TIOCSTI; +extern unsigned IOCTL_TIOCSWINSZ; +extern unsigned IOCTL_SIOCGETSGCNT; +extern unsigned IOCTL_SIOCGETVIFCNT; +extern unsigned IOCTL_MTIOCGET; +extern unsigned IOCTL_MTIOCTOP; +extern unsigned IOCTL_SIOCADDRT; +extern unsigned IOCTL_SIOCDELRT; +extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; +extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; +extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; +extern unsigned IOCTL_SNDCTL_DSP_POST; +extern unsigned IOCTL_SNDCTL_DSP_RESET; +extern unsigned IOCTL_SNDCTL_DSP_SETFMT; +extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; +extern unsigned IOCTL_SNDCTL_DSP_SPEED; +extern unsigned IOCTL_SNDCTL_DSP_STEREO; +extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; +extern unsigned IOCTL_SNDCTL_DSP_SYNC; +extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE; +extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR; +extern unsigned IOCTL_SNDCTL_MIDI_INFO; +extern unsigned IOCTL_SNDCTL_MIDI_PRETIME; +extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE; +extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT; +extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT; +extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS; +extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS; +extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND; +extern unsigned IOCTL_SNDCTL_SEQ_PANIC; +extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE; +extern unsigned IOCTL_SNDCTL_SEQ_RESET; +extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES; +extern unsigned IOCTL_SNDCTL_SEQ_SYNC; +extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI; +extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD; +extern unsigned IOCTL_SNDCTL_SYNTH_INFO; +extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL; +extern unsigned IOCTL_SNDCTL_TMR_CONTINUE; +extern unsigned IOCTL_SNDCTL_TMR_METRONOME; +extern unsigned IOCTL_SNDCTL_TMR_SELECT; +extern unsigned IOCTL_SNDCTL_TMR_SOURCE; +extern unsigned IOCTL_SNDCTL_TMR_START; +extern unsigned IOCTL_SNDCTL_TMR_STOP; +extern unsigned IOCTL_SNDCTL_TMR_TEMPO; +extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE; +extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM; +extern unsigned IOCTL_SOUND_MIXER_READ_BASS; +extern unsigned IOCTL_SOUND_MIXER_READ_CAPS; +extern unsigned IOCTL_SOUND_MIXER_READ_CD; +extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK; +extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE; +extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN; +extern unsigned IOCTL_SOUND_MIXER_READ_IMIX; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE1; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE2; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE3; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE; +extern unsigned IOCTL_SOUND_MIXER_READ_LOUD; +extern unsigned IOCTL_SOUND_MIXER_READ_MIC; +extern unsigned IOCTL_SOUND_MIXER_READ_MUTE; +extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN; +extern unsigned IOCTL_SOUND_MIXER_READ_PCM; +extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV; +extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK; +extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC; +extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER; +extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS; +extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH; +extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE; +extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME; +extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM; +extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS; +extern unsigned IOCTL_SOUND_MIXER_WRITE_CD; +extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN; +extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD; +extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC; +extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN; +extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM; +extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV; +extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC; +extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER; +extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH; +extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME; +extern unsigned IOCTL_SOUND_PCM_READ_BITS; +extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_READ_FILTER; +extern unsigned IOCTL_SOUND_PCM_READ_RATE; +extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; +extern unsigned IOCTL_VT_ACTIVATE; +extern unsigned IOCTL_VT_GETMODE; +extern unsigned IOCTL_VT_OPENQRY; +extern unsigned IOCTL_VT_RELDISP; +extern unsigned IOCTL_VT_SETMODE; +extern unsigned IOCTL_VT_WAITACTIVE; +extern unsigned IOCTL_GIO_SCRNMAP; +extern unsigned IOCTL_KDDISABIO; +extern unsigned IOCTL_KDENABIO; +extern unsigned IOCTL_KDGETLED; +extern unsigned IOCTL_KDGETMODE; +extern unsigned IOCTL_KDGKBMODE; +extern unsigned IOCTL_KDGKBTYPE; +extern unsigned IOCTL_KDMKTONE; +extern unsigned IOCTL_KDSETLED; +extern unsigned IOCTL_KDSETMODE; +extern unsigned IOCTL_KDSKBMODE; + +extern const int si_SEGV_MAPERR; +extern const int si_SEGV_ACCERR; + +struct __sanitizer_cap_rights { + u64 cr_rights[2]; +}; + +typedef struct __sanitizer_cap_rights __sanitizer_cap_rights_t; +extern unsigned struct_cap_rights_sz; + +extern unsigned struct_fstab_sz; +extern unsigned struct_StringList_sz; } // namespace __sanitizer #define CHECK_TYPE_SIZE(TYPE) \ diff --git a/lib/sanitizer_common/sanitizer_platform_limits_linux.cc b/lib/sanitizer_common/sanitizer_platform_limits_linux.cc deleted file mode 100644 index 14b0821cb819..000000000000 --- a/lib/sanitizer_common/sanitizer_platform_limits_linux.cc +++ /dev/null @@ -1,108 +0,0 @@ -//===-- sanitizer_platform_limits_linux.cc --------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of Sanitizer common code. -// -// Sizes and layouts of linux kernel data structures. -//===----------------------------------------------------------------------===// - -// This is a separate compilation unit for linux headers that conflict with -// userspace headers. -// Most "normal" includes go in sanitizer_platform_limits_posix.cc - -#include "sanitizer_platform.h" -#if SANITIZER_LINUX - -#include "sanitizer_internal_defs.h" -#include "sanitizer_platform_limits_posix.h" - -// For offsetof -> __builtin_offsetof definition. -#include - -// With old kernels (and even new kernels on powerpc) asm/stat.h uses types that -// are not defined anywhere in userspace headers. Fake them. This seems to work -// fine with newer headers, too. -#include -#if defined(__x86_64__) || defined(__mips__) -#include -#else -#define ino_t __kernel_ino_t -#define mode_t __kernel_mode_t -#define nlink_t __kernel_nlink_t -#define uid_t __kernel_uid_t -#define gid_t __kernel_gid_t -#define off_t __kernel_off_t -#define time_t __kernel_time_t -// This header seems to contain the definitions of _kernel_ stat* structs. -#include -#undef ino_t -#undef mode_t -#undef nlink_t -#undef uid_t -#undef gid_t -#undef off_t -#endif - -#include - -#if !SANITIZER_ANDROID -#include -#include -#endif - -using namespace __sanitizer; - -namespace __sanitizer { -#if !SANITIZER_ANDROID - unsigned struct_statfs64_sz = sizeof(struct statfs64); -#endif -} // namespace __sanitizer - -#if !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__aarch64__)\ - && !defined(__mips__) && !defined(__s390__)\ - && !defined(__sparc__) -COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat)); -#endif - -COMPILER_CHECK(struct_kernel_stat_sz == sizeof(struct stat)); - -#if defined(__i386__) -COMPILER_CHECK(struct_kernel_stat64_sz == sizeof(struct stat64)); -#endif - -CHECK_TYPE_SIZE(io_event); -CHECK_SIZE_AND_OFFSET(io_event, data); -CHECK_SIZE_AND_OFFSET(io_event, obj); -CHECK_SIZE_AND_OFFSET(io_event, res); -CHECK_SIZE_AND_OFFSET(io_event, res2); - -#if !SANITIZER_ANDROID -COMPILER_CHECK(sizeof(struct __sanitizer_perf_event_attr) <= - sizeof(struct perf_event_attr)); -CHECK_SIZE_AND_OFFSET(perf_event_attr, type); -CHECK_SIZE_AND_OFFSET(perf_event_attr, size); -#endif - -COMPILER_CHECK(iocb_cmd_pread == IOCB_CMD_PREAD); -COMPILER_CHECK(iocb_cmd_pwrite == IOCB_CMD_PWRITE); -#if !SANITIZER_ANDROID -COMPILER_CHECK(iocb_cmd_preadv == IOCB_CMD_PREADV); -COMPILER_CHECK(iocb_cmd_pwritev == IOCB_CMD_PWRITEV); -#endif - -CHECK_TYPE_SIZE(iocb); -CHECK_SIZE_AND_OFFSET(iocb, aio_data); -// Skip aio_key, it's weird. -CHECK_SIZE_AND_OFFSET(iocb, aio_lio_opcode); -CHECK_SIZE_AND_OFFSET(iocb, aio_reqprio); -CHECK_SIZE_AND_OFFSET(iocb, aio_fildes); -CHECK_SIZE_AND_OFFSET(iocb, aio_buf); -CHECK_SIZE_AND_OFFSET(iocb, aio_nbytes); -CHECK_SIZE_AND_OFFSET(iocb, aio_offset); - -#endif // SANITIZER_LINUX diff --git a/lib/sanitizer_common/sanitizer_platform_limits_linux.cpp b/lib/sanitizer_common/sanitizer_platform_limits_linux.cpp new file mode 100644 index 000000000000..842bc789f479 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_platform_limits_linux.cpp @@ -0,0 +1,108 @@ +//===-- sanitizer_platform_limits_linux.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of linux kernel data structures. +//===----------------------------------------------------------------------===// + +// This is a separate compilation unit for linux headers that conflict with +// userspace headers. +// Most "normal" includes go in sanitizer_platform_limits_posix.cpp + +#include "sanitizer_platform.h" +#if SANITIZER_LINUX + +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform_limits_posix.h" + +// For offsetof -> __builtin_offsetof definition. +#include + +// With old kernels (and even new kernels on powerpc) asm/stat.h uses types that +// are not defined anywhere in userspace headers. Fake them. This seems to work +// fine with newer headers, too. +#include +#if defined(__x86_64__) || defined(__mips__) +#include +#else +#define ino_t __kernel_ino_t +#define mode_t __kernel_mode_t +#define nlink_t __kernel_nlink_t +#define uid_t __kernel_uid_t +#define gid_t __kernel_gid_t +#define off_t __kernel_off_t +#define time_t __kernel_time_t +// This header seems to contain the definitions of _kernel_ stat* structs. +#include +#undef ino_t +#undef mode_t +#undef nlink_t +#undef uid_t +#undef gid_t +#undef off_t +#endif + +#include + +#if !SANITIZER_ANDROID +#include +#include +#endif + +using namespace __sanitizer; + +namespace __sanitizer { +#if !SANITIZER_ANDROID + unsigned struct_statfs64_sz = sizeof(struct statfs64); +#endif +} // namespace __sanitizer + +#if !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__aarch64__)\ + && !defined(__mips__) && !defined(__s390__)\ + && !defined(__sparc__) +COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat)); +#endif + +COMPILER_CHECK(struct_kernel_stat_sz == sizeof(struct stat)); + +#if defined(__i386__) +COMPILER_CHECK(struct_kernel_stat64_sz == sizeof(struct stat64)); +#endif + +CHECK_TYPE_SIZE(io_event); +CHECK_SIZE_AND_OFFSET(io_event, data); +CHECK_SIZE_AND_OFFSET(io_event, obj); +CHECK_SIZE_AND_OFFSET(io_event, res); +CHECK_SIZE_AND_OFFSET(io_event, res2); + +#if !SANITIZER_ANDROID +COMPILER_CHECK(sizeof(struct __sanitizer_perf_event_attr) <= + sizeof(struct perf_event_attr)); +CHECK_SIZE_AND_OFFSET(perf_event_attr, type); +CHECK_SIZE_AND_OFFSET(perf_event_attr, size); +#endif + +COMPILER_CHECK(iocb_cmd_pread == IOCB_CMD_PREAD); +COMPILER_CHECK(iocb_cmd_pwrite == IOCB_CMD_PWRITE); +#if !SANITIZER_ANDROID +COMPILER_CHECK(iocb_cmd_preadv == IOCB_CMD_PREADV); +COMPILER_CHECK(iocb_cmd_pwritev == IOCB_CMD_PWRITEV); +#endif + +CHECK_TYPE_SIZE(iocb); +CHECK_SIZE_AND_OFFSET(iocb, aio_data); +// Skip aio_key, it's weird. +CHECK_SIZE_AND_OFFSET(iocb, aio_lio_opcode); +CHECK_SIZE_AND_OFFSET(iocb, aio_reqprio); +CHECK_SIZE_AND_OFFSET(iocb, aio_fildes); +CHECK_SIZE_AND_OFFSET(iocb, aio_buf); +CHECK_SIZE_AND_OFFSET(iocb, aio_nbytes); +CHECK_SIZE_AND_OFFSET(iocb, aio_offset); + +#endif // SANITIZER_LINUX diff --git a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc deleted file mode 100644 index b2fb5cb76463..000000000000 --- a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc +++ /dev/null @@ -1,2345 +0,0 @@ -//===-- sanitizer_platform_limits_netbsd.cc -------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of Sanitizer common code. -// -// Sizes and layouts of platform-specific NetBSD data structures. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_NETBSD - -#define _KMEMUSER -#define RAY_DO_SIGLEV - -// clang-format off -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if 0 -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -// clang-format on - -// Include these after system headers to avoid name clashes and ambiguities. -#include "sanitizer_internal_defs.h" -#include "sanitizer_platform_limits_netbsd.h" - -namespace __sanitizer { -unsigned struct_utsname_sz = sizeof(struct utsname); -unsigned struct_stat_sz = sizeof(struct stat); -unsigned struct_rusage_sz = sizeof(struct rusage); -unsigned struct_tm_sz = sizeof(struct tm); -unsigned struct_passwd_sz = sizeof(struct passwd); -unsigned struct_group_sz = sizeof(struct group); -unsigned siginfo_t_sz = sizeof(siginfo_t); -unsigned struct_sigaction_sz = sizeof(struct sigaction); -unsigned struct_itimerval_sz = sizeof(struct itimerval); -unsigned pthread_t_sz = sizeof(pthread_t); -unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); -unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); -unsigned pid_t_sz = sizeof(pid_t); -unsigned timeval_sz = sizeof(timeval); -unsigned uid_t_sz = sizeof(uid_t); -unsigned gid_t_sz = sizeof(gid_t); -unsigned mbstate_t_sz = sizeof(mbstate_t); -unsigned sigset_t_sz = sizeof(sigset_t); -unsigned struct_timezone_sz = sizeof(struct timezone); -unsigned struct_tms_sz = sizeof(struct tms); -unsigned struct_sigevent_sz = sizeof(struct sigevent); -unsigned struct_sched_param_sz = sizeof(struct sched_param); -unsigned struct_sockaddr_sz = sizeof(struct sockaddr); -unsigned ucontext_t_sz = sizeof(ucontext_t); -unsigned struct_rlimit_sz = sizeof(struct rlimit); -unsigned struct_timespec_sz = sizeof(struct timespec); -unsigned struct_sembuf_sz = sizeof(struct sembuf); -unsigned struct_kevent_sz = sizeof(struct kevent); -unsigned struct_FTS_sz = sizeof(FTS); -unsigned struct_FTSENT_sz = sizeof(FTSENT); -unsigned struct_regex_sz = sizeof(regex_t); -unsigned struct_regmatch_sz = sizeof(regmatch_t); -unsigned struct_fstab_sz = sizeof(struct fstab); -unsigned struct_utimbuf_sz = sizeof(struct utimbuf); -unsigned struct_itimerspec_sz = sizeof(struct itimerspec); -unsigned struct_timex_sz = sizeof(struct timex); -unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); -unsigned struct_mq_attr_sz = sizeof(struct mq_attr); -unsigned struct_statvfs_sz = sizeof(struct statvfs); -unsigned struct_sigaltstack_sz = sizeof(stack_t); - -const uptr sig_ign = (uptr)SIG_IGN; -const uptr sig_dfl = (uptr)SIG_DFL; -const uptr sig_err = (uptr)SIG_ERR; -const uptr sa_siginfo = (uptr)SA_SIGINFO; - -const unsigned long __sanitizer_bufsiz = BUFSIZ; - -int ptrace_pt_io = PT_IO; -int ptrace_pt_lwpinfo = PT_LWPINFO; -int ptrace_pt_set_event_mask = PT_SET_EVENT_MASK; -int ptrace_pt_get_event_mask = PT_GET_EVENT_MASK; -int ptrace_pt_get_process_state = PT_GET_PROCESS_STATE; -int ptrace_pt_set_siginfo = PT_SET_SIGINFO; -int ptrace_pt_get_siginfo = PT_GET_SIGINFO; -int ptrace_piod_read_d = PIOD_READ_D; -int ptrace_piod_write_d = PIOD_WRITE_D; -int ptrace_piod_read_i = PIOD_READ_I; -int ptrace_piod_write_i = PIOD_WRITE_I; -int ptrace_piod_read_auxv = PIOD_READ_AUXV; - -#if defined(PT_SETREGS) && defined(PT_GETREGS) -int ptrace_pt_setregs = PT_SETREGS; -int ptrace_pt_getregs = PT_GETREGS; -#else -int ptrace_pt_setregs = -1; -int ptrace_pt_getregs = -1; -#endif - -#if defined(PT_SETFPREGS) && defined(PT_GETFPREGS) -int ptrace_pt_setfpregs = PT_SETFPREGS; -int ptrace_pt_getfpregs = PT_GETFPREGS; -#else -int ptrace_pt_setfpregs = -1; -int ptrace_pt_getfpregs = -1; -#endif - -#if defined(PT_SETDBREGS) && defined(PT_GETDBREGS) -int ptrace_pt_setdbregs = PT_SETDBREGS; -int ptrace_pt_getdbregs = PT_GETDBREGS; -#else -int ptrace_pt_setdbregs = -1; -int ptrace_pt_getdbregs = -1; -#endif - -unsigned struct_ptrace_ptrace_io_desc_struct_sz = sizeof(struct ptrace_io_desc); -unsigned struct_ptrace_ptrace_lwpinfo_struct_sz = sizeof(struct ptrace_lwpinfo); -unsigned struct_ptrace_ptrace_event_struct_sz = sizeof(ptrace_event_t); -unsigned struct_ptrace_ptrace_siginfo_struct_sz = sizeof(ptrace_siginfo_t); - -#if defined(PT_SETREGS) -unsigned struct_ptrace_reg_struct_sz = sizeof(struct reg); -#else -unsigned struct_ptrace_reg_struct_sz = -1; -#endif - -#if defined(PT_SETFPREGS) -unsigned struct_ptrace_fpreg_struct_sz = sizeof(struct fpreg); -#else -unsigned struct_ptrace_fpreg_struct_sz = -1; -#endif - -#if defined(PT_SETDBREGS) -unsigned struct_ptrace_dbreg_struct_sz = sizeof(struct dbreg); -#else -unsigned struct_ptrace_dbreg_struct_sz = -1; -#endif - -int shmctl_ipc_stat = (int)IPC_STAT; - -unsigned struct_utmp_sz = sizeof(struct utmp); -unsigned struct_utmpx_sz = sizeof(struct utmpx); - -int map_fixed = MAP_FIXED; - -int af_inet = (int)AF_INET; -int af_inet6 = (int)AF_INET6; - -uptr __sanitizer_in_addr_sz(int af) { - if (af == AF_INET) - return sizeof(struct in_addr); - else if (af == AF_INET6) - return sizeof(struct in6_addr); - else - return 0; -} - -unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); - -int glob_nomatch = GLOB_NOMATCH; -int glob_altdirfunc = GLOB_ALTDIRFUNC; - -unsigned path_max = PATH_MAX; - -int struct_ttyent_sz = sizeof(struct ttyent); - -struct __sanitizer_nvlist_ref_t { - void *buf; - uptr len; - int flags; -}; - -typedef __sanitizer_nvlist_ref_t nvlist_ref_t; - -// ioctl arguments -unsigned struct_altqreq_sz = sizeof(altqreq); -unsigned struct_amr_user_ioctl_sz = sizeof(amr_user_ioctl); -unsigned struct_ap_control_sz = sizeof(ap_control); -unsigned struct_apm_ctl_sz = sizeof(apm_ctl); -unsigned struct_apm_event_info_sz = sizeof(apm_event_info); -unsigned struct_apm_power_info_sz = sizeof(apm_power_info); -unsigned struct_atabusiodetach_args_sz = sizeof(atabusiodetach_args); -unsigned struct_atabusioscan_args_sz = sizeof(atabusioscan_args); -unsigned struct_ath_diag_sz = sizeof(ath_diag); -unsigned struct_atm_flowmap_sz = sizeof(atm_flowmap); -unsigned struct_audio_buf_info_sz = sizeof(audio_buf_info); -unsigned struct_audio_device_sz = sizeof(audio_device); -unsigned struct_audio_encoding_sz = sizeof(audio_encoding); -unsigned struct_audio_info_sz = sizeof(audio_info); -unsigned struct_audio_offset_sz = sizeof(audio_offset); -unsigned struct_bio_locate_sz = sizeof(bio_locate); -unsigned struct_bioc_alarm_sz = sizeof(bioc_alarm); -unsigned struct_bioc_blink_sz = sizeof(bioc_blink); -unsigned struct_bioc_disk_sz = sizeof(bioc_disk); -unsigned struct_bioc_inq_sz = sizeof(bioc_inq); -unsigned struct_bioc_setstate_sz = sizeof(bioc_setstate); -unsigned struct_bioc_vol_sz = sizeof(bioc_vol); -unsigned struct_bioc_volops_sz = sizeof(bioc_volops); -unsigned struct_bktr_chnlset_sz = sizeof(bktr_chnlset); -unsigned struct_bktr_remote_sz = sizeof(bktr_remote); -unsigned struct_blue_conf_sz = sizeof(blue_conf); -unsigned struct_blue_interface_sz = sizeof(blue_interface); -unsigned struct_blue_stats_sz = sizeof(blue_stats); -unsigned struct_bpf_dltlist_sz = sizeof(bpf_dltlist); -unsigned struct_bpf_program_sz = sizeof(bpf_program); -unsigned struct_bpf_stat_old_sz = sizeof(bpf_stat_old); -unsigned struct_bpf_stat_sz = sizeof(bpf_stat); -unsigned struct_bpf_version_sz = sizeof(bpf_version); -unsigned struct_btreq_sz = sizeof(btreq); -unsigned struct_btsco_info_sz = sizeof(btsco_info); -unsigned struct_buffmem_desc_sz = sizeof(buffmem_desc); -unsigned struct_cbq_add_class_sz = sizeof(cbq_add_class); -unsigned struct_cbq_add_filter_sz = sizeof(cbq_add_filter); -unsigned struct_cbq_delete_class_sz = sizeof(cbq_delete_class); -unsigned struct_cbq_delete_filter_sz = sizeof(cbq_delete_filter); -unsigned struct_cbq_getstats_sz = sizeof(cbq_getstats); -unsigned struct_cbq_interface_sz = sizeof(cbq_interface); -unsigned struct_cbq_modify_class_sz = sizeof(cbq_modify_class); -unsigned struct_ccd_ioctl_sz = sizeof(ccd_ioctl); -unsigned struct_cdnr_add_element_sz = sizeof(cdnr_add_element); -unsigned struct_cdnr_add_filter_sz = sizeof(cdnr_add_filter); -unsigned struct_cdnr_add_tbmeter_sz = sizeof(cdnr_add_tbmeter); -unsigned struct_cdnr_add_trtcm_sz = sizeof(cdnr_add_trtcm); -unsigned struct_cdnr_add_tswtcm_sz = sizeof(cdnr_add_tswtcm); -unsigned struct_cdnr_delete_element_sz = sizeof(cdnr_delete_element); -unsigned struct_cdnr_delete_filter_sz = sizeof(cdnr_delete_filter); -unsigned struct_cdnr_get_stats_sz = sizeof(cdnr_get_stats); -unsigned struct_cdnr_interface_sz = sizeof(cdnr_interface); -unsigned struct_cdnr_modify_tbmeter_sz = sizeof(cdnr_modify_tbmeter); -unsigned struct_cdnr_modify_trtcm_sz = sizeof(cdnr_modify_trtcm); -unsigned struct_cdnr_modify_tswtcm_sz = sizeof(cdnr_modify_tswtcm); -unsigned struct_cdnr_tbmeter_stats_sz = sizeof(cdnr_tbmeter_stats); -unsigned struct_cdnr_tcm_stats_sz = sizeof(cdnr_tcm_stats); -unsigned struct_cgd_ioctl_sz = sizeof(cgd_ioctl); -unsigned struct_cgd_user_sz = sizeof(cgd_user); -unsigned struct_changer_element_status_request_sz = - sizeof(changer_element_status_request); -unsigned struct_changer_exchange_request_sz = sizeof(changer_exchange_request); -unsigned struct_changer_move_request_sz = sizeof(changer_move_request); -unsigned struct_changer_params_sz = sizeof(changer_params); -unsigned struct_changer_position_request_sz = sizeof(changer_position_request); -unsigned struct_changer_set_voltag_request_sz = - sizeof(changer_set_voltag_request); -unsigned struct_clockctl_adjtime_sz = sizeof(clockctl_adjtime); -unsigned struct_clockctl_clock_settime_sz = sizeof(clockctl_clock_settime); -unsigned struct_clockctl_ntp_adjtime_sz = sizeof(clockctl_ntp_adjtime); -unsigned struct_clockctl_settimeofday_sz = sizeof(clockctl_settimeofday); -unsigned struct_cnwistats_sz = sizeof(cnwistats); -unsigned struct_cnwitrail_sz = sizeof(cnwitrail); -unsigned struct_cnwstatus_sz = sizeof(cnwstatus); -unsigned struct_count_info_sz = sizeof(count_info); -unsigned struct_cpu_ucode_sz = sizeof(cpu_ucode); -unsigned struct_cpu_ucode_version_sz = sizeof(cpu_ucode_version); -unsigned struct_crypt_kop_sz = sizeof(crypt_kop); -unsigned struct_crypt_mkop_sz = sizeof(crypt_mkop); -unsigned struct_crypt_mop_sz = sizeof(crypt_mop); -unsigned struct_crypt_op_sz = sizeof(crypt_op); -unsigned struct_crypt_result_sz = sizeof(crypt_result); -unsigned struct_crypt_sfop_sz = sizeof(crypt_sfop); -unsigned struct_crypt_sgop_sz = sizeof(crypt_sgop); -unsigned struct_cryptret_sz = sizeof(cryptret); -unsigned struct_devdetachargs_sz = sizeof(devdetachargs); -unsigned struct_devlistargs_sz = sizeof(devlistargs); -unsigned struct_devpmargs_sz = sizeof(devpmargs); -unsigned struct_devrescanargs_sz = sizeof(devrescanargs); -unsigned struct_disk_badsecinfo_sz = sizeof(disk_badsecinfo); -unsigned struct_disk_strategy_sz = sizeof(disk_strategy); -unsigned struct_disklabel_sz = sizeof(disklabel); -unsigned struct_dkbad_sz = sizeof(dkbad); -unsigned struct_dkwedge_info_sz = sizeof(dkwedge_info); -unsigned struct_dkwedge_list_sz = sizeof(dkwedge_list); -unsigned struct_dmio_setfunc_sz = sizeof(dmio_setfunc); -unsigned struct_dmx_pes_filter_params_sz = sizeof(dmx_pes_filter_params); -unsigned struct_dmx_sct_filter_params_sz = sizeof(dmx_sct_filter_params); -unsigned struct_dmx_stc_sz = sizeof(dmx_stc); -unsigned struct_dvb_diseqc_master_cmd_sz = sizeof(dvb_diseqc_master_cmd); -unsigned struct_dvb_diseqc_slave_reply_sz = sizeof(dvb_diseqc_slave_reply); -unsigned struct_dvb_frontend_event_sz = sizeof(dvb_frontend_event); -unsigned struct_dvb_frontend_info_sz = sizeof(dvb_frontend_info); -unsigned struct_dvb_frontend_parameters_sz = sizeof(dvb_frontend_parameters); -unsigned struct_eccapreq_sz = sizeof(eccapreq); -unsigned struct_fbcmap_sz = sizeof(fbcmap); -unsigned struct_fbcurpos_sz = sizeof(fbcurpos); -unsigned struct_fbcursor_sz = sizeof(fbcursor); -unsigned struct_fbgattr_sz = sizeof(fbgattr); -unsigned struct_fbsattr_sz = sizeof(fbsattr); -unsigned struct_fbtype_sz = sizeof(fbtype); -unsigned struct_fdformat_cmd_sz = sizeof(fdformat_cmd); -unsigned struct_fdformat_parms_sz = sizeof(fdformat_parms); -unsigned struct_fifoq_conf_sz = sizeof(fifoq_conf); -unsigned struct_fifoq_getstats_sz = sizeof(fifoq_getstats); -unsigned struct_fifoq_interface_sz = sizeof(fifoq_interface); -unsigned struct_format_op_sz = sizeof(format_op); -unsigned struct_fss_get_sz = sizeof(fss_get); -unsigned struct_fss_set_sz = sizeof(fss_set); -unsigned struct_gpio_attach_sz = sizeof(gpio_attach); -unsigned struct_gpio_info_sz = sizeof(gpio_info); -unsigned struct_gpio_req_sz = sizeof(gpio_req); -unsigned struct_gpio_set_sz = sizeof(gpio_set); -unsigned struct_hfsc_add_class_sz = sizeof(hfsc_add_class); -unsigned struct_hfsc_add_filter_sz = sizeof(hfsc_add_filter); -unsigned struct_hfsc_attach_sz = sizeof(hfsc_attach); -unsigned struct_hfsc_class_stats_sz = sizeof(hfsc_class_stats); -unsigned struct_hfsc_delete_class_sz = sizeof(hfsc_delete_class); -unsigned struct_hfsc_delete_filter_sz = sizeof(hfsc_delete_filter); -unsigned struct_hfsc_interface_sz = sizeof(hfsc_interface); -unsigned struct_hfsc_modify_class_sz = sizeof(hfsc_modify_class); -unsigned struct_hpcfb_dsp_op_sz = sizeof(hpcfb_dsp_op); -unsigned struct_hpcfb_dspconf_sz = sizeof(hpcfb_dspconf); -unsigned struct_hpcfb_fbconf_sz = sizeof(hpcfb_fbconf); -unsigned struct_if_addrprefreq_sz = sizeof(if_addrprefreq); -unsigned struct_if_clonereq_sz = sizeof(if_clonereq); -unsigned struct_if_laddrreq_sz = sizeof(if_laddrreq); -unsigned struct_ifaddr_sz = sizeof(ifaddr); -unsigned struct_ifaliasreq_sz = sizeof(ifaliasreq); -unsigned struct_ifcapreq_sz = sizeof(ifcapreq); -unsigned struct_ifconf_sz = sizeof(ifconf); -unsigned struct_ifdatareq_sz = sizeof(ifdatareq); -unsigned struct_ifdrv_sz = sizeof(ifdrv); -unsigned struct_ifmediareq_sz = sizeof(ifmediareq); -unsigned struct_ifpppcstatsreq_sz = sizeof(ifpppcstatsreq); -unsigned struct_ifpppstatsreq_sz = sizeof(ifpppstatsreq); -unsigned struct_ifreq_sz = sizeof(ifreq); -unsigned struct_in6_addrpolicy_sz = sizeof(in6_addrpolicy); -unsigned struct_in6_ndireq_sz = sizeof(in6_ndireq); -unsigned struct_ioc_load_unload_sz = sizeof(ioc_load_unload); -unsigned struct_ioc_patch_sz = sizeof(ioc_patch); -unsigned struct_ioc_play_blocks_sz = sizeof(ioc_play_blocks); -unsigned struct_ioc_play_msf_sz = sizeof(ioc_play_msf); -unsigned struct_ioc_play_track_sz = sizeof(ioc_play_track); -unsigned struct_ioc_read_subchannel_sz = sizeof(ioc_read_subchannel); -unsigned struct_ioc_read_toc_entry_sz = sizeof(ioc_read_toc_entry); -unsigned struct_ioc_toc_header_sz = sizeof(ioc_toc_header); -unsigned struct_ioc_vol_sz = sizeof(ioc_vol); -unsigned struct_ioctl_pt_sz = sizeof(ioctl_pt); -unsigned struct_ioppt_sz = sizeof(ioppt); -unsigned struct_iovec_sz = sizeof(iovec); -unsigned struct_ipfobj_sz = sizeof(ipfobj); -unsigned struct_irda_params_sz = sizeof(irda_params); -unsigned struct_isp_fc_device_sz = sizeof(isp_fc_device); -unsigned struct_isp_fc_tsk_mgmt_sz = sizeof(isp_fc_tsk_mgmt); -unsigned struct_isp_hba_device_sz = sizeof(isp_hba_device); -unsigned struct_isv_cmd_sz = sizeof(isv_cmd); -unsigned struct_jobs_add_class_sz = sizeof(jobs_add_class); -unsigned struct_jobs_add_filter_sz = sizeof(jobs_add_filter); -unsigned struct_jobs_attach_sz = sizeof(jobs_attach); -unsigned struct_jobs_class_stats_sz = sizeof(jobs_class_stats); -unsigned struct_jobs_delete_class_sz = sizeof(jobs_delete_class); -unsigned struct_jobs_delete_filter_sz = sizeof(jobs_delete_filter); -unsigned struct_jobs_interface_sz = sizeof(jobs_interface); -unsigned struct_jobs_modify_class_sz = sizeof(jobs_modify_class); -unsigned struct_kbentry_sz = sizeof(kbentry); -unsigned struct_kfilter_mapping_sz = sizeof(kfilter_mapping); -unsigned struct_kiockeymap_sz = sizeof(kiockeymap); -unsigned struct_ksyms_gsymbol_sz = sizeof(ksyms_gsymbol); -unsigned struct_ksyms_gvalue_sz = sizeof(ksyms_gvalue); -unsigned struct_ksyms_ogsymbol_sz = sizeof(ksyms_ogsymbol); -unsigned struct_kttcp_io_args_sz = sizeof(kttcp_io_args); -unsigned struct_ltchars_sz = sizeof(ltchars); -unsigned struct_lua_create_sz = sizeof(struct lua_create); -unsigned struct_lua_info_sz = sizeof(struct lua_info); -unsigned struct_lua_load_sz = sizeof(struct lua_load); -unsigned struct_lua_require_sz = sizeof(lua_require); -unsigned struct_mbpp_param_sz = sizeof(mbpp_param); -unsigned struct_md_conf_sz = sizeof(md_conf); -unsigned struct_meteor_capframe_sz = sizeof(meteor_capframe); -unsigned struct_meteor_counts_sz = sizeof(meteor_counts); -unsigned struct_meteor_geomet_sz = sizeof(meteor_geomet); -unsigned struct_meteor_pixfmt_sz = sizeof(meteor_pixfmt); -unsigned struct_meteor_video_sz = sizeof(meteor_video); -unsigned struct_mlx_cinfo_sz = sizeof(mlx_cinfo); -unsigned struct_mlx_pause_sz = sizeof(mlx_pause); -unsigned struct_mlx_rebuild_request_sz = sizeof(mlx_rebuild_request); -unsigned struct_mlx_rebuild_status_sz = sizeof(mlx_rebuild_status); -unsigned struct_mlx_usercommand_sz = sizeof(mlx_usercommand); -unsigned struct_mly_user_command_sz = sizeof(mly_user_command); -unsigned struct_mly_user_health_sz = sizeof(mly_user_health); -unsigned struct_mtget_sz = sizeof(mtget); -unsigned struct_mtop_sz = sizeof(mtop); -unsigned struct_npf_ioctl_table_sz = sizeof(npf_ioctl_table); -unsigned struct_npioctl_sz = sizeof(npioctl); -unsigned struct_nvme_pt_command_sz = sizeof(nvme_pt_command); -unsigned struct_ochanger_element_status_request_sz = - sizeof(ochanger_element_status_request); -unsigned struct_ofiocdesc_sz = sizeof(ofiocdesc); -unsigned struct_okiockey_sz = sizeof(okiockey); -unsigned struct_ortentry_sz = sizeof(ortentry); -unsigned struct_oscsi_addr_sz = sizeof(oscsi_addr); -unsigned struct_oss_audioinfo_sz = sizeof(oss_audioinfo); -unsigned struct_oss_sysinfo_sz = sizeof(oss_sysinfo); -unsigned struct_pciio_bdf_cfgreg_sz = sizeof(pciio_bdf_cfgreg); -unsigned struct_pciio_businfo_sz = sizeof(pciio_businfo); -unsigned struct_pciio_cfgreg_sz = sizeof(pciio_cfgreg); -unsigned struct_pciio_drvname_sz = sizeof(pciio_drvname); -unsigned struct_pciio_drvnameonbus_sz = sizeof(pciio_drvnameonbus); -unsigned struct_pcvtid_sz = sizeof(pcvtid); -unsigned struct_pf_osfp_ioctl_sz = sizeof(pf_osfp_ioctl); -unsigned struct_pf_status_sz = sizeof(pf_status); -unsigned struct_pfioc_altq_sz = sizeof(pfioc_altq); -unsigned struct_pfioc_if_sz = sizeof(pfioc_if); -unsigned struct_pfioc_iface_sz = sizeof(pfioc_iface); -unsigned struct_pfioc_limit_sz = sizeof(pfioc_limit); -unsigned struct_pfioc_natlook_sz = sizeof(pfioc_natlook); -unsigned struct_pfioc_pooladdr_sz = sizeof(pfioc_pooladdr); -unsigned struct_pfioc_qstats_sz = sizeof(pfioc_qstats); -unsigned struct_pfioc_rule_sz = sizeof(pfioc_rule); -unsigned struct_pfioc_ruleset_sz = sizeof(pfioc_ruleset); -unsigned struct_pfioc_src_node_kill_sz = sizeof(pfioc_src_node_kill); -unsigned struct_pfioc_src_nodes_sz = sizeof(pfioc_src_nodes); -unsigned struct_pfioc_state_kill_sz = sizeof(pfioc_state_kill); -unsigned struct_pfioc_state_sz = sizeof(pfioc_state); -unsigned struct_pfioc_states_sz = sizeof(pfioc_states); -unsigned struct_pfioc_table_sz = sizeof(pfioc_table); -unsigned struct_pfioc_tm_sz = sizeof(pfioc_tm); -unsigned struct_pfioc_trans_sz = sizeof(pfioc_trans); -unsigned struct_plistref_sz = sizeof(plistref); -unsigned struct_power_type_sz = sizeof(power_type); -unsigned struct_ppp_idle_sz = sizeof(ppp_idle); -unsigned struct_ppp_option_data_sz = sizeof(ppp_option_data); -unsigned struct_ppp_rawin_sz = sizeof(ppp_rawin); -unsigned struct_pppoeconnectionstate_sz = sizeof(pppoeconnectionstate); -unsigned struct_pppoediscparms_sz = sizeof(pppoediscparms); -unsigned struct_priq_add_class_sz = sizeof(priq_add_class); -unsigned struct_priq_add_filter_sz = sizeof(priq_add_filter); -unsigned struct_priq_class_stats_sz = sizeof(priq_class_stats); -unsigned struct_priq_delete_class_sz = sizeof(priq_delete_class); -unsigned struct_priq_delete_filter_sz = sizeof(priq_delete_filter); -unsigned struct_priq_interface_sz = sizeof(priq_interface); -unsigned struct_priq_modify_class_sz = sizeof(priq_modify_class); -unsigned struct_ptmget_sz = sizeof(ptmget); -unsigned struct_radio_info_sz = sizeof(radio_info); -unsigned struct_red_conf_sz = sizeof(red_conf); -unsigned struct_red_interface_sz = sizeof(red_interface); -unsigned struct_red_stats_sz = sizeof(red_stats); -unsigned struct_redparams_sz = sizeof(redparams); -unsigned struct_rf_pmparams_sz = sizeof(rf_pmparams); -unsigned struct_rf_pmstat_sz = sizeof(rf_pmstat); -unsigned struct_rf_recon_req_sz = sizeof(rf_recon_req); -unsigned struct_rio_conf_sz = sizeof(rio_conf); -unsigned struct_rio_interface_sz = sizeof(rio_interface); -unsigned struct_rio_stats_sz = sizeof(rio_stats); -unsigned struct_scan_io_sz = sizeof(scan_io); -unsigned struct_scbusaccel_args_sz = sizeof(scbusaccel_args); -unsigned struct_scbusiodetach_args_sz = sizeof(scbusiodetach_args); -unsigned struct_scbusioscan_args_sz = sizeof(scbusioscan_args); -unsigned struct_scsi_addr_sz = sizeof(scsi_addr); -unsigned struct_seq_event_rec_sz = sizeof(seq_event_rec); -unsigned struct_session_op_sz = sizeof(session_op); -unsigned struct_sgttyb_sz = sizeof(sgttyb); -unsigned struct_sioc_sg_req_sz = sizeof(sioc_sg_req); -unsigned struct_sioc_vif_req_sz = sizeof(sioc_vif_req); -unsigned struct_smbioc_flags_sz = sizeof(smbioc_flags); -unsigned struct_smbioc_lookup_sz = sizeof(smbioc_lookup); -unsigned struct_smbioc_oshare_sz = sizeof(smbioc_oshare); -unsigned struct_smbioc_ossn_sz = sizeof(smbioc_ossn); -unsigned struct_smbioc_rq_sz = sizeof(smbioc_rq); -unsigned struct_smbioc_rw_sz = sizeof(smbioc_rw); -unsigned struct_spppauthcfg_sz = sizeof(spppauthcfg); -unsigned struct_spppauthfailuresettings_sz = sizeof(spppauthfailuresettings); -unsigned struct_spppauthfailurestats_sz = sizeof(spppauthfailurestats); -unsigned struct_spppdnsaddrs_sz = sizeof(spppdnsaddrs); -unsigned struct_spppdnssettings_sz = sizeof(spppdnssettings); -unsigned struct_spppidletimeout_sz = sizeof(spppidletimeout); -unsigned struct_spppkeepalivesettings_sz = sizeof(spppkeepalivesettings); -unsigned struct_sppplcpcfg_sz = sizeof(sppplcpcfg); -unsigned struct_spppstatus_sz = sizeof(spppstatus); -unsigned struct_spppstatusncp_sz = sizeof(spppstatusncp); -unsigned struct_srt_rt_sz = sizeof(srt_rt); -unsigned struct_stic_xinfo_sz = sizeof(stic_xinfo); -unsigned struct_sun_dkctlr_sz = sizeof(sun_dkctlr); -unsigned struct_sun_dkgeom_sz = sizeof(sun_dkgeom); -unsigned struct_sun_dkpart_sz = sizeof(sun_dkpart); -unsigned struct_synth_info_sz = sizeof(synth_info); -unsigned struct_tbrreq_sz = sizeof(tbrreq); -unsigned struct_tchars_sz = sizeof(tchars); -unsigned struct_termios_sz = sizeof(termios); -unsigned struct_timeval_sz = sizeof(timeval); -unsigned struct_twe_drivecommand_sz = sizeof(twe_drivecommand); -unsigned struct_twe_paramcommand_sz = sizeof(twe_paramcommand); -unsigned struct_twe_usercommand_sz = sizeof(twe_usercommand); -unsigned struct_ukyopon_identify_sz = sizeof(ukyopon_identify); -unsigned struct_urio_command_sz = sizeof(urio_command); -unsigned struct_usb_alt_interface_sz = sizeof(usb_alt_interface); -unsigned struct_usb_bulk_ra_wb_opt_sz = sizeof(usb_bulk_ra_wb_opt); -unsigned struct_usb_config_desc_sz = sizeof(usb_config_desc); -unsigned struct_usb_ctl_report_desc_sz = sizeof(usb_ctl_report_desc); -unsigned struct_usb_ctl_report_sz = sizeof(usb_ctl_report); -unsigned struct_usb_ctl_request_sz = sizeof(usb_ctl_request); -unsigned struct_autofs_daemon_request_sz = sizeof(autofs_daemon_request); -unsigned struct_autofs_daemon_done_sz = sizeof(autofs_daemon_done); -unsigned struct_sctp_connectx_addrs_sz = sizeof(sctp_connectx_addrs); -unsigned struct_usb_device_info_old_sz = sizeof(usb_device_info_old); -unsigned struct_usb_device_info_sz = sizeof(usb_device_info); -unsigned struct_usb_device_stats_sz = sizeof(usb_device_stats); -unsigned struct_usb_endpoint_desc_sz = sizeof(usb_endpoint_desc); -unsigned struct_usb_full_desc_sz = sizeof(usb_full_desc); -unsigned struct_usb_interface_desc_sz = sizeof(usb_interface_desc); -unsigned struct_usb_string_desc_sz = sizeof(usb_string_desc); -unsigned struct_utoppy_readfile_sz = sizeof(utoppy_readfile); -unsigned struct_utoppy_rename_sz = sizeof(utoppy_rename); -unsigned struct_utoppy_stats_sz = sizeof(utoppy_stats); -unsigned struct_utoppy_writefile_sz = sizeof(utoppy_writefile); -unsigned struct_v4l2_audio_sz = sizeof(v4l2_audio); -unsigned struct_v4l2_audioout_sz = sizeof(v4l2_audioout); -unsigned struct_v4l2_buffer_sz = sizeof(v4l2_buffer); -unsigned struct_v4l2_capability_sz = sizeof(v4l2_capability); -unsigned struct_v4l2_control_sz = sizeof(v4l2_control); -unsigned struct_v4l2_crop_sz = sizeof(v4l2_crop); -unsigned struct_v4l2_cropcap_sz = sizeof(v4l2_cropcap); -unsigned struct_v4l2_fmtdesc_sz = sizeof(v4l2_fmtdesc); -unsigned struct_v4l2_format_sz = sizeof(v4l2_format); -unsigned struct_v4l2_framebuffer_sz = sizeof(v4l2_framebuffer); -unsigned struct_v4l2_frequency_sz = sizeof(v4l2_frequency); -unsigned struct_v4l2_frmivalenum_sz = sizeof(v4l2_frmivalenum); -unsigned struct_v4l2_frmsizeenum_sz = sizeof(v4l2_frmsizeenum); -unsigned struct_v4l2_input_sz = sizeof(v4l2_input); -unsigned struct_v4l2_jpegcompression_sz = sizeof(v4l2_jpegcompression); -unsigned struct_v4l2_modulator_sz = sizeof(v4l2_modulator); -unsigned struct_v4l2_output_sz = sizeof(v4l2_output); -unsigned struct_v4l2_queryctrl_sz = sizeof(v4l2_queryctrl); -unsigned struct_v4l2_querymenu_sz = sizeof(v4l2_querymenu); -unsigned struct_v4l2_requestbuffers_sz = sizeof(v4l2_requestbuffers); -unsigned struct_v4l2_standard_sz = sizeof(v4l2_standard); -unsigned struct_v4l2_streamparm_sz = sizeof(v4l2_streamparm); -unsigned struct_v4l2_tuner_sz = sizeof(v4l2_tuner); -unsigned struct_vnd_ioctl_sz = sizeof(vnd_ioctl); -unsigned struct_vnd_user_sz = sizeof(vnd_user); -unsigned struct_vt_stat_sz = sizeof(vt_stat); -unsigned struct_wdog_conf_sz = sizeof(wdog_conf); -unsigned struct_wdog_mode_sz = sizeof(wdog_mode); -unsigned struct_wfq_conf_sz = sizeof(wfq_conf); -unsigned struct_wfq_getqid_sz = sizeof(wfq_getqid); -unsigned struct_wfq_getstats_sz = sizeof(wfq_getstats); -unsigned struct_wfq_interface_sz = sizeof(wfq_interface); -unsigned struct_wfq_setweight_sz = sizeof(wfq_setweight); -unsigned struct_winsize_sz = sizeof(winsize); -unsigned struct_wscons_event_sz = sizeof(wscons_event); -unsigned struct_wsdisplay_addscreendata_sz = sizeof(wsdisplay_addscreendata); -unsigned struct_wsdisplay_char_sz = sizeof(wsdisplay_char); -unsigned struct_wsdisplay_cmap_sz = sizeof(wsdisplay_cmap); -unsigned struct_wsdisplay_curpos_sz = sizeof(wsdisplay_curpos); -unsigned struct_wsdisplay_cursor_sz = sizeof(wsdisplay_cursor); -unsigned struct_wsdisplay_delscreendata_sz = sizeof(wsdisplay_delscreendata); -unsigned struct_wsdisplay_fbinfo_sz = sizeof(wsdisplay_fbinfo); -unsigned struct_wsdisplay_font_sz = sizeof(wsdisplay_font); -unsigned struct_wsdisplay_kbddata_sz = sizeof(wsdisplay_kbddata); -unsigned struct_wsdisplay_msgattrs_sz = sizeof(wsdisplay_msgattrs); -unsigned struct_wsdisplay_param_sz = sizeof(wsdisplay_param); -unsigned struct_wsdisplay_scroll_data_sz = sizeof(wsdisplay_scroll_data); -unsigned struct_wsdisplay_usefontdata_sz = sizeof(wsdisplay_usefontdata); -unsigned struct_wsdisplayio_blit_sz = sizeof(wsdisplayio_blit); -unsigned struct_wsdisplayio_bus_id_sz = sizeof(wsdisplayio_bus_id); -unsigned struct_wsdisplayio_edid_info_sz = sizeof(wsdisplayio_edid_info); -unsigned struct_wsdisplayio_fbinfo_sz = sizeof(wsdisplayio_fbinfo); -unsigned struct_wskbd_bell_data_sz = sizeof(wskbd_bell_data); -unsigned struct_wskbd_keyrepeat_data_sz = sizeof(wskbd_keyrepeat_data); -unsigned struct_wskbd_map_data_sz = sizeof(wskbd_map_data); -unsigned struct_wskbd_scroll_data_sz = sizeof(wskbd_scroll_data); -unsigned struct_wsmouse_calibcoords_sz = sizeof(wsmouse_calibcoords); -unsigned struct_wsmouse_id_sz = sizeof(wsmouse_id); -unsigned struct_wsmouse_repeat_sz = sizeof(wsmouse_repeat); -unsigned struct_wsmux_device_list_sz = sizeof(wsmux_device_list); -unsigned struct_wsmux_device_sz = sizeof(wsmux_device); -unsigned struct_xd_iocmd_sz = sizeof(xd_iocmd); - -unsigned struct_scsireq_sz = sizeof(struct scsireq); -unsigned struct_tone_sz = sizeof(tone_t); -unsigned union_twe_statrequest_sz = sizeof(union twe_statrequest); -unsigned struct_usb_device_descriptor_sz = sizeof(usb_device_descriptor_t); -unsigned struct_vt_mode_sz = sizeof(struct vt_mode); -unsigned struct__old_mixer_info_sz = sizeof(struct _old_mixer_info); -unsigned struct__agp_allocate_sz = sizeof(struct _agp_allocate); -unsigned struct__agp_bind_sz = sizeof(struct _agp_bind); -unsigned struct__agp_info_sz = sizeof(struct _agp_info); -unsigned struct__agp_setup_sz = sizeof(struct _agp_setup); -unsigned struct__agp_unbind_sz = sizeof(struct _agp_unbind); -unsigned struct_atareq_sz = sizeof(struct atareq); -unsigned struct_cpustate_sz = sizeof(struct cpustate); -unsigned struct_dmx_caps_sz = sizeof(struct dmx_caps); -unsigned enum_dmx_source_sz = sizeof(dmx_source_t); -unsigned union_dvd_authinfo_sz = sizeof(dvd_authinfo); -unsigned union_dvd_struct_sz = sizeof(dvd_struct); -unsigned enum_v4l2_priority_sz = sizeof(enum v4l2_priority); -unsigned struct_envsys_basic_info_sz = sizeof(struct envsys_basic_info); -unsigned struct_envsys_tre_data_sz = sizeof(struct envsys_tre_data); -unsigned enum_fe_sec_mini_cmd_sz = sizeof(enum fe_sec_mini_cmd); -unsigned enum_fe_sec_tone_mode_sz = sizeof(enum fe_sec_tone_mode); -unsigned enum_fe_sec_voltage_sz = sizeof(enum fe_sec_voltage); -unsigned enum_fe_status_sz = sizeof(enum fe_status); -unsigned struct_gdt_ctrt_sz = sizeof(struct gdt_ctrt); -unsigned struct_gdt_event_sz = sizeof(struct gdt_event); -unsigned struct_gdt_osv_sz = sizeof(struct gdt_osv); -unsigned struct_gdt_rescan_sz = sizeof(struct gdt_rescan); -unsigned struct_gdt_statist_sz = sizeof(struct gdt_statist); -unsigned struct_gdt_ucmd_sz = sizeof(struct gdt_ucmd); -unsigned struct_iscsi_conn_status_parameters_sz = - sizeof(iscsi_conn_status_parameters_t); -unsigned struct_iscsi_get_version_parameters_sz = - sizeof(iscsi_get_version_parameters_t); -unsigned struct_iscsi_iocommand_parameters_sz = - sizeof(iscsi_iocommand_parameters_t); -unsigned struct_iscsi_login_parameters_sz = sizeof(iscsi_login_parameters_t); -unsigned struct_iscsi_logout_parameters_sz = sizeof(iscsi_logout_parameters_t); -unsigned struct_iscsi_register_event_parameters_sz = - sizeof(iscsi_register_event_parameters_t); -unsigned struct_iscsi_remove_parameters_sz = sizeof(iscsi_remove_parameters_t); -unsigned struct_iscsi_send_targets_parameters_sz = - sizeof(iscsi_send_targets_parameters_t); -unsigned struct_iscsi_set_node_name_parameters_sz = - sizeof(iscsi_set_node_name_parameters_t); -unsigned struct_iscsi_wait_event_parameters_sz = - sizeof(iscsi_wait_event_parameters_t); -unsigned struct_isp_stats_sz = sizeof(isp_stats_t); -unsigned struct_lsenable_sz = sizeof(struct lsenable); -unsigned struct_lsdisable_sz = sizeof(struct lsdisable); -unsigned struct_mixer_ctrl_sz = sizeof(struct mixer_ctrl); -unsigned struct_mixer_devinfo_sz = sizeof(struct mixer_devinfo); -unsigned struct_mpu_command_rec_sz = sizeof(mpu_command_rec); -unsigned struct_rndstat_sz = sizeof(rndstat_t); -unsigned struct_rndstat_name_sz = sizeof(rndstat_name_t); -unsigned struct_rndctl_sz = sizeof(rndctl_t); -unsigned struct_rnddata_sz = sizeof(rnddata_t); -unsigned struct_rndpoolstat_sz = sizeof(rndpoolstat_t); -unsigned struct_rndstat_est_sz = sizeof(rndstat_est_t); -unsigned struct_rndstat_est_name_sz = sizeof(rndstat_est_name_t); -unsigned struct_pps_params_sz = sizeof(pps_params_t); -unsigned struct_pps_info_sz = sizeof(pps_info_t); -unsigned struct_mixer_info_sz = sizeof(struct mixer_info); -unsigned struct_RF_SparetWait_sz = sizeof(RF_SparetWait_t); -unsigned struct_RF_ComponentLabel_sz = sizeof(RF_ComponentLabel_t); -unsigned struct_RF_SingleComponent_sz = sizeof(RF_SingleComponent_t); -unsigned struct_RF_ProgressInfo_sz = sizeof(RF_ProgressInfo_t); -unsigned struct_nvlist_ref_sz = sizeof(struct __sanitizer_nvlist_ref_t); -unsigned struct_StringList_sz = sizeof(StringList); - -const unsigned IOCTL_NOT_PRESENT = 0; - -unsigned IOCTL_AFM_ADDFMAP = AFM_ADDFMAP; -unsigned IOCTL_AFM_DELFMAP = AFM_DELFMAP; -unsigned IOCTL_AFM_CLEANFMAP = AFM_CLEANFMAP; -unsigned IOCTL_AFM_GETFMAP = AFM_GETFMAP; -unsigned IOCTL_ALTQGTYPE = ALTQGTYPE; -unsigned IOCTL_ALTQTBRSET = ALTQTBRSET; -unsigned IOCTL_ALTQTBRGET = ALTQTBRGET; -unsigned IOCTL_BLUE_IF_ATTACH = BLUE_IF_ATTACH; -unsigned IOCTL_BLUE_IF_DETACH = BLUE_IF_DETACH; -unsigned IOCTL_BLUE_ENABLE = BLUE_ENABLE; -unsigned IOCTL_BLUE_DISABLE = BLUE_DISABLE; -unsigned IOCTL_BLUE_CONFIG = BLUE_CONFIG; -unsigned IOCTL_BLUE_GETSTATS = BLUE_GETSTATS; -unsigned IOCTL_CBQ_IF_ATTACH = CBQ_IF_ATTACH; -unsigned IOCTL_CBQ_IF_DETACH = CBQ_IF_DETACH; -unsigned IOCTL_CBQ_ENABLE = CBQ_ENABLE; -unsigned IOCTL_CBQ_DISABLE = CBQ_DISABLE; -unsigned IOCTL_CBQ_CLEAR_HIERARCHY = CBQ_CLEAR_HIERARCHY; -unsigned IOCTL_CBQ_ADD_CLASS = CBQ_ADD_CLASS; -unsigned IOCTL_CBQ_DEL_CLASS = CBQ_DEL_CLASS; -unsigned IOCTL_CBQ_MODIFY_CLASS = CBQ_MODIFY_CLASS; -unsigned IOCTL_CBQ_ADD_FILTER = CBQ_ADD_FILTER; -unsigned IOCTL_CBQ_DEL_FILTER = CBQ_DEL_FILTER; -unsigned IOCTL_CBQ_GETSTATS = CBQ_GETSTATS; -unsigned IOCTL_CDNR_IF_ATTACH = CDNR_IF_ATTACH; -unsigned IOCTL_CDNR_IF_DETACH = CDNR_IF_DETACH; -unsigned IOCTL_CDNR_ENABLE = CDNR_ENABLE; -unsigned IOCTL_CDNR_DISABLE = CDNR_DISABLE; -unsigned IOCTL_CDNR_ADD_FILTER = CDNR_ADD_FILTER; -unsigned IOCTL_CDNR_DEL_FILTER = CDNR_DEL_FILTER; -unsigned IOCTL_CDNR_GETSTATS = CDNR_GETSTATS; -unsigned IOCTL_CDNR_ADD_ELEM = CDNR_ADD_ELEM; -unsigned IOCTL_CDNR_DEL_ELEM = CDNR_DEL_ELEM; -unsigned IOCTL_CDNR_ADD_TBM = CDNR_ADD_TBM; -unsigned IOCTL_CDNR_MOD_TBM = CDNR_MOD_TBM; -unsigned IOCTL_CDNR_TBM_STATS = CDNR_TBM_STATS; -unsigned IOCTL_CDNR_ADD_TCM = CDNR_ADD_TCM; -unsigned IOCTL_CDNR_MOD_TCM = CDNR_MOD_TCM; -unsigned IOCTL_CDNR_TCM_STATS = CDNR_TCM_STATS; -unsigned IOCTL_CDNR_ADD_TSW = CDNR_ADD_TSW; -unsigned IOCTL_CDNR_MOD_TSW = CDNR_MOD_TSW; -unsigned IOCTL_FIFOQ_IF_ATTACH = FIFOQ_IF_ATTACH; -unsigned IOCTL_FIFOQ_IF_DETACH = FIFOQ_IF_DETACH; -unsigned IOCTL_FIFOQ_ENABLE = FIFOQ_ENABLE; -unsigned IOCTL_FIFOQ_DISABLE = FIFOQ_DISABLE; -unsigned IOCTL_FIFOQ_CONFIG = FIFOQ_CONFIG; -unsigned IOCTL_FIFOQ_GETSTATS = FIFOQ_GETSTATS; -unsigned IOCTL_HFSC_IF_ATTACH = HFSC_IF_ATTACH; -unsigned IOCTL_HFSC_IF_DETACH = HFSC_IF_DETACH; -unsigned IOCTL_HFSC_ENABLE = HFSC_ENABLE; -unsigned IOCTL_HFSC_DISABLE = HFSC_DISABLE; -unsigned IOCTL_HFSC_CLEAR_HIERARCHY = HFSC_CLEAR_HIERARCHY; -unsigned IOCTL_HFSC_ADD_CLASS = HFSC_ADD_CLASS; -unsigned IOCTL_HFSC_DEL_CLASS = HFSC_DEL_CLASS; -unsigned IOCTL_HFSC_MOD_CLASS = HFSC_MOD_CLASS; -unsigned IOCTL_HFSC_ADD_FILTER = HFSC_ADD_FILTER; -unsigned IOCTL_HFSC_DEL_FILTER = HFSC_DEL_FILTER; -unsigned IOCTL_HFSC_GETSTATS = HFSC_GETSTATS; -unsigned IOCTL_JOBS_IF_ATTACH = JOBS_IF_ATTACH; -unsigned IOCTL_JOBS_IF_DETACH = JOBS_IF_DETACH; -unsigned IOCTL_JOBS_ENABLE = JOBS_ENABLE; -unsigned IOCTL_JOBS_DISABLE = JOBS_DISABLE; -unsigned IOCTL_JOBS_CLEAR = JOBS_CLEAR; -unsigned IOCTL_JOBS_ADD_CLASS = JOBS_ADD_CLASS; -unsigned IOCTL_JOBS_DEL_CLASS = JOBS_DEL_CLASS; -unsigned IOCTL_JOBS_MOD_CLASS = JOBS_MOD_CLASS; -unsigned IOCTL_JOBS_ADD_FILTER = JOBS_ADD_FILTER; -unsigned IOCTL_JOBS_DEL_FILTER = JOBS_DEL_FILTER; -unsigned IOCTL_JOBS_GETSTATS = JOBS_GETSTATS; -unsigned IOCTL_PRIQ_IF_ATTACH = PRIQ_IF_ATTACH; -unsigned IOCTL_PRIQ_IF_DETACH = PRIQ_IF_DETACH; -unsigned IOCTL_PRIQ_ENABLE = PRIQ_ENABLE; -unsigned IOCTL_PRIQ_DISABLE = PRIQ_DISABLE; -unsigned IOCTL_PRIQ_CLEAR = PRIQ_CLEAR; -unsigned IOCTL_PRIQ_ADD_CLASS = PRIQ_ADD_CLASS; -unsigned IOCTL_PRIQ_DEL_CLASS = PRIQ_DEL_CLASS; -unsigned IOCTL_PRIQ_MOD_CLASS = PRIQ_MOD_CLASS; -unsigned IOCTL_PRIQ_ADD_FILTER = PRIQ_ADD_FILTER; -unsigned IOCTL_PRIQ_DEL_FILTER = PRIQ_DEL_FILTER; -unsigned IOCTL_PRIQ_GETSTATS = PRIQ_GETSTATS; -unsigned IOCTL_RED_IF_ATTACH = RED_IF_ATTACH; -unsigned IOCTL_RED_IF_DETACH = RED_IF_DETACH; -unsigned IOCTL_RED_ENABLE = RED_ENABLE; -unsigned IOCTL_RED_DISABLE = RED_DISABLE; -unsigned IOCTL_RED_CONFIG = RED_CONFIG; -unsigned IOCTL_RED_GETSTATS = RED_GETSTATS; -unsigned IOCTL_RED_SETDEFAULTS = RED_SETDEFAULTS; -unsigned IOCTL_RIO_IF_ATTACH = RIO_IF_ATTACH; -unsigned IOCTL_RIO_IF_DETACH = RIO_IF_DETACH; -unsigned IOCTL_RIO_ENABLE = RIO_ENABLE; -unsigned IOCTL_RIO_DISABLE = RIO_DISABLE; -unsigned IOCTL_RIO_CONFIG = RIO_CONFIG; -unsigned IOCTL_RIO_GETSTATS = RIO_GETSTATS; -unsigned IOCTL_RIO_SETDEFAULTS = RIO_SETDEFAULTS; -unsigned IOCTL_WFQ_IF_ATTACH = WFQ_IF_ATTACH; -unsigned IOCTL_WFQ_IF_DETACH = WFQ_IF_DETACH; -unsigned IOCTL_WFQ_ENABLE = WFQ_ENABLE; -unsigned IOCTL_WFQ_DISABLE = WFQ_DISABLE; -unsigned IOCTL_WFQ_CONFIG = WFQ_CONFIG; -unsigned IOCTL_WFQ_GET_STATS = WFQ_GET_STATS; -unsigned IOCTL_WFQ_GET_QID = WFQ_GET_QID; -unsigned IOCTL_WFQ_SET_WEIGHT = WFQ_SET_WEIGHT; -unsigned IOCTL_CRIOGET = CRIOGET; -unsigned IOCTL_CIOCFSESSION = CIOCFSESSION; -unsigned IOCTL_CIOCKEY = CIOCKEY; -unsigned IOCTL_CIOCNFKEYM = CIOCNFKEYM; -unsigned IOCTL_CIOCNFSESSION = CIOCNFSESSION; -unsigned IOCTL_CIOCNCRYPTRETM = CIOCNCRYPTRETM; -unsigned IOCTL_CIOCNCRYPTRET = CIOCNCRYPTRET; -unsigned IOCTL_CIOCGSESSION = CIOCGSESSION; -unsigned IOCTL_CIOCNGSESSION = CIOCNGSESSION; -unsigned IOCTL_CIOCCRYPT = CIOCCRYPT; -unsigned IOCTL_CIOCNCRYPTM = CIOCNCRYPTM; -unsigned IOCTL_CIOCASYMFEAT = CIOCASYMFEAT; -unsigned IOCTL_APM_IOC_REJECT = APM_IOC_REJECT; -unsigned IOCTL_APM_IOC_STANDBY = APM_IOC_STANDBY; -unsigned IOCTL_APM_IOC_SUSPEND = APM_IOC_SUSPEND; -unsigned IOCTL_OAPM_IOC_GETPOWER = OAPM_IOC_GETPOWER; -unsigned IOCTL_APM_IOC_GETPOWER = APM_IOC_GETPOWER; -unsigned IOCTL_APM_IOC_NEXTEVENT = APM_IOC_NEXTEVENT; -unsigned IOCTL_APM_IOC_DEV_CTL = APM_IOC_DEV_CTL; -unsigned IOCTL_NETBSD_DM_IOCTL = NETBSD_DM_IOCTL; -unsigned IOCTL_DMIO_SETFUNC = DMIO_SETFUNC; -unsigned IOCTL_DMX_START = DMX_START; -unsigned IOCTL_DMX_STOP = DMX_STOP; -unsigned IOCTL_DMX_SET_FILTER = DMX_SET_FILTER; -unsigned IOCTL_DMX_SET_PES_FILTER = DMX_SET_PES_FILTER; -unsigned IOCTL_DMX_SET_BUFFER_SIZE = DMX_SET_BUFFER_SIZE; -unsigned IOCTL_DMX_GET_STC = DMX_GET_STC; -unsigned IOCTL_DMX_ADD_PID = DMX_ADD_PID; -unsigned IOCTL_DMX_REMOVE_PID = DMX_REMOVE_PID; -unsigned IOCTL_DMX_GET_CAPS = DMX_GET_CAPS; -unsigned IOCTL_DMX_SET_SOURCE = DMX_SET_SOURCE; -unsigned IOCTL_FE_READ_STATUS = FE_READ_STATUS; -unsigned IOCTL_FE_READ_BER = FE_READ_BER; -unsigned IOCTL_FE_READ_SNR = FE_READ_SNR; -unsigned IOCTL_FE_READ_SIGNAL_STRENGTH = FE_READ_SIGNAL_STRENGTH; -unsigned IOCTL_FE_READ_UNCORRECTED_BLOCKS = FE_READ_UNCORRECTED_BLOCKS; -unsigned IOCTL_FE_SET_FRONTEND = FE_SET_FRONTEND; -unsigned IOCTL_FE_GET_FRONTEND = FE_GET_FRONTEND; -unsigned IOCTL_FE_GET_EVENT = FE_GET_EVENT; -unsigned IOCTL_FE_GET_INFO = FE_GET_INFO; -unsigned IOCTL_FE_DISEQC_RESET_OVERLOAD = FE_DISEQC_RESET_OVERLOAD; -unsigned IOCTL_FE_DISEQC_SEND_MASTER_CMD = FE_DISEQC_SEND_MASTER_CMD; -unsigned IOCTL_FE_DISEQC_RECV_SLAVE_REPLY = FE_DISEQC_RECV_SLAVE_REPLY; -unsigned IOCTL_FE_DISEQC_SEND_BURST = FE_DISEQC_SEND_BURST; -unsigned IOCTL_FE_SET_TONE = FE_SET_TONE; -unsigned IOCTL_FE_SET_VOLTAGE = FE_SET_VOLTAGE; -unsigned IOCTL_FE_ENABLE_HIGH_LNB_VOLTAGE = FE_ENABLE_HIGH_LNB_VOLTAGE; -unsigned IOCTL_FE_SET_FRONTEND_TUNE_MODE = FE_SET_FRONTEND_TUNE_MODE; -unsigned IOCTL_FE_DISHNETWORK_SEND_LEGACY_CMD = FE_DISHNETWORK_SEND_LEGACY_CMD; -unsigned IOCTL_FILEMON_SET_FD = FILEMON_SET_FD; -unsigned IOCTL_FILEMON_SET_PID = FILEMON_SET_PID; -unsigned IOCTL_HDAUDIO_FGRP_INFO = HDAUDIO_FGRP_INFO; -unsigned IOCTL_HDAUDIO_FGRP_GETCONFIG = HDAUDIO_FGRP_GETCONFIG; -unsigned IOCTL_HDAUDIO_FGRP_SETCONFIG = HDAUDIO_FGRP_SETCONFIG; -unsigned IOCTL_HDAUDIO_FGRP_WIDGET_INFO = HDAUDIO_FGRP_WIDGET_INFO; -unsigned IOCTL_HDAUDIO_FGRP_CODEC_INFO = HDAUDIO_FGRP_CODEC_INFO; -unsigned IOCTL_HDAUDIO_AFG_WIDGET_INFO = HDAUDIO_AFG_WIDGET_INFO; -unsigned IOCTL_HDAUDIO_AFG_CODEC_INFO = HDAUDIO_AFG_CODEC_INFO; -unsigned IOCTL_CEC_GET_PHYS_ADDR = CEC_GET_PHYS_ADDR; -unsigned IOCTL_CEC_GET_LOG_ADDRS = CEC_GET_LOG_ADDRS; -unsigned IOCTL_CEC_SET_LOG_ADDRS = CEC_SET_LOG_ADDRS; -unsigned IOCTL_CEC_GET_VENDOR_ID = CEC_GET_VENDOR_ID; -unsigned IOCTL_HPCFBIO_GCONF = HPCFBIO_GCONF; -unsigned IOCTL_HPCFBIO_SCONF = HPCFBIO_SCONF; -unsigned IOCTL_HPCFBIO_GDSPCONF = HPCFBIO_GDSPCONF; -unsigned IOCTL_HPCFBIO_SDSPCONF = HPCFBIO_SDSPCONF; -unsigned IOCTL_HPCFBIO_GOP = HPCFBIO_GOP; -unsigned IOCTL_HPCFBIO_SOP = HPCFBIO_SOP; -unsigned IOCTL_IOPIOCPT = IOPIOCPT; -unsigned IOCTL_IOPIOCGLCT = IOPIOCGLCT; -unsigned IOCTL_IOPIOCGSTATUS = IOPIOCGSTATUS; -unsigned IOCTL_IOPIOCRECONFIG = IOPIOCRECONFIG; -unsigned IOCTL_IOPIOCGTIDMAP = IOPIOCGTIDMAP; -unsigned IOCTL_SIOCGATHSTATS = SIOCGATHSTATS; -unsigned IOCTL_SIOCGATHDIAG = SIOCGATHDIAG; -unsigned IOCTL_METEORCAPTUR = METEORCAPTUR; -unsigned IOCTL_METEORCAPFRM = METEORCAPFRM; -unsigned IOCTL_METEORSETGEO = METEORSETGEO; -unsigned IOCTL_METEORGETGEO = METEORGETGEO; -unsigned IOCTL_METEORSTATUS = METEORSTATUS; -unsigned IOCTL_METEORSHUE = METEORSHUE; -unsigned IOCTL_METEORGHUE = METEORGHUE; -unsigned IOCTL_METEORSFMT = METEORSFMT; -unsigned IOCTL_METEORGFMT = METEORGFMT; -unsigned IOCTL_METEORSINPUT = METEORSINPUT; -unsigned IOCTL_METEORGINPUT = METEORGINPUT; -unsigned IOCTL_METEORSCHCV = METEORSCHCV; -unsigned IOCTL_METEORGCHCV = METEORGCHCV; -unsigned IOCTL_METEORSCOUNT = METEORSCOUNT; -unsigned IOCTL_METEORGCOUNT = METEORGCOUNT; -unsigned IOCTL_METEORSFPS = METEORSFPS; -unsigned IOCTL_METEORGFPS = METEORGFPS; -unsigned IOCTL_METEORSSIGNAL = METEORSSIGNAL; -unsigned IOCTL_METEORGSIGNAL = METEORGSIGNAL; -unsigned IOCTL_METEORSVIDEO = METEORSVIDEO; -unsigned IOCTL_METEORGVIDEO = METEORGVIDEO; -unsigned IOCTL_METEORSBRIG = METEORSBRIG; -unsigned IOCTL_METEORGBRIG = METEORGBRIG; -unsigned IOCTL_METEORSCSAT = METEORSCSAT; -unsigned IOCTL_METEORGCSAT = METEORGCSAT; -unsigned IOCTL_METEORSCONT = METEORSCONT; -unsigned IOCTL_METEORGCONT = METEORGCONT; -unsigned IOCTL_METEORSHWS = METEORSHWS; -unsigned IOCTL_METEORGHWS = METEORGHWS; -unsigned IOCTL_METEORSVWS = METEORSVWS; -unsigned IOCTL_METEORGVWS = METEORGVWS; -unsigned IOCTL_METEORSTS = METEORSTS; -unsigned IOCTL_METEORGTS = METEORGTS; -unsigned IOCTL_TVTUNER_SETCHNL = TVTUNER_SETCHNL; -unsigned IOCTL_TVTUNER_GETCHNL = TVTUNER_GETCHNL; -unsigned IOCTL_TVTUNER_SETTYPE = TVTUNER_SETTYPE; -unsigned IOCTL_TVTUNER_GETTYPE = TVTUNER_GETTYPE; -unsigned IOCTL_TVTUNER_GETSTATUS = TVTUNER_GETSTATUS; -unsigned IOCTL_TVTUNER_SETFREQ = TVTUNER_SETFREQ; -unsigned IOCTL_TVTUNER_GETFREQ = TVTUNER_GETFREQ; -unsigned IOCTL_TVTUNER_SETAFC = TVTUNER_SETAFC; -unsigned IOCTL_TVTUNER_GETAFC = TVTUNER_GETAFC; -unsigned IOCTL_RADIO_SETMODE = RADIO_SETMODE; -unsigned IOCTL_RADIO_GETMODE = RADIO_GETMODE; -unsigned IOCTL_RADIO_SETFREQ = RADIO_SETFREQ; -unsigned IOCTL_RADIO_GETFREQ = RADIO_GETFREQ; -unsigned IOCTL_METEORSACTPIXFMT = METEORSACTPIXFMT; -unsigned IOCTL_METEORGACTPIXFMT = METEORGACTPIXFMT; -unsigned IOCTL_METEORGSUPPIXFMT = METEORGSUPPIXFMT; -unsigned IOCTL_TVTUNER_GETCHNLSET = TVTUNER_GETCHNLSET; -unsigned IOCTL_REMOTE_GETKEY = REMOTE_GETKEY; -unsigned IOCTL_GDT_IOCTL_GENERAL = GDT_IOCTL_GENERAL; -unsigned IOCTL_GDT_IOCTL_DRVERS = GDT_IOCTL_DRVERS; -unsigned IOCTL_GDT_IOCTL_CTRTYPE = GDT_IOCTL_CTRTYPE; -unsigned IOCTL_GDT_IOCTL_OSVERS = GDT_IOCTL_OSVERS; -unsigned IOCTL_GDT_IOCTL_CTRCNT = GDT_IOCTL_CTRCNT; -unsigned IOCTL_GDT_IOCTL_EVENT = GDT_IOCTL_EVENT; -unsigned IOCTL_GDT_IOCTL_STATIST = GDT_IOCTL_STATIST; -unsigned IOCTL_GDT_IOCTL_RESCAN = GDT_IOCTL_RESCAN; -unsigned IOCTL_ISP_SDBLEV = ISP_SDBLEV; -unsigned IOCTL_ISP_RESETHBA = ISP_RESETHBA; -unsigned IOCTL_ISP_RESCAN = ISP_RESCAN; -unsigned IOCTL_ISP_SETROLE = ISP_SETROLE; -unsigned IOCTL_ISP_GETROLE = ISP_GETROLE; -unsigned IOCTL_ISP_GET_STATS = ISP_GET_STATS; -unsigned IOCTL_ISP_CLR_STATS = ISP_CLR_STATS; -unsigned IOCTL_ISP_FC_LIP = ISP_FC_LIP; -unsigned IOCTL_ISP_FC_GETDINFO = ISP_FC_GETDINFO; -unsigned IOCTL_ISP_GET_FW_CRASH_DUMP = ISP_GET_FW_CRASH_DUMP; -unsigned IOCTL_ISP_FORCE_CRASH_DUMP = ISP_FORCE_CRASH_DUMP; -unsigned IOCTL_ISP_FC_GETHINFO = ISP_FC_GETHINFO; -unsigned IOCTL_ISP_TSK_MGMT = ISP_TSK_MGMT; -unsigned IOCTL_ISP_FC_GETDLIST = ISP_FC_GETDLIST; -unsigned IOCTL_MLXD_STATUS = MLXD_STATUS; -unsigned IOCTL_MLXD_CHECKASYNC = MLXD_CHECKASYNC; -unsigned IOCTL_MLXD_DETACH = MLXD_DETACH; -unsigned IOCTL_MLX_RESCAN_DRIVES = MLX_RESCAN_DRIVES; -unsigned IOCTL_MLX_PAUSE_CHANNEL = MLX_PAUSE_CHANNEL; -unsigned IOCTL_MLX_COMMAND = MLX_COMMAND; -unsigned IOCTL_MLX_REBUILDASYNC = MLX_REBUILDASYNC; -unsigned IOCTL_MLX_REBUILDSTAT = MLX_REBUILDSTAT; -unsigned IOCTL_MLX_GET_SYSDRIVE = MLX_GET_SYSDRIVE; -unsigned IOCTL_MLX_GET_CINFO = MLX_GET_CINFO; -unsigned IOCTL_NVME_PASSTHROUGH_CMD = NVME_PASSTHROUGH_CMD; -unsigned IOCTL_FWCFGIO_SET_INDEX = FWCFGIO_SET_INDEX; -unsigned IOCTL_IRDA_RESET_PARAMS = IRDA_RESET_PARAMS; -unsigned IOCTL_IRDA_SET_PARAMS = IRDA_SET_PARAMS; -unsigned IOCTL_IRDA_GET_SPEEDMASK = IRDA_GET_SPEEDMASK; -unsigned IOCTL_IRDA_GET_TURNAROUNDMASK = IRDA_GET_TURNAROUNDMASK; -unsigned IOCTL_IRFRAMETTY_GET_DEVICE = IRFRAMETTY_GET_DEVICE; -unsigned IOCTL_IRFRAMETTY_GET_DONGLE = IRFRAMETTY_GET_DONGLE; -unsigned IOCTL_IRFRAMETTY_SET_DONGLE = IRFRAMETTY_SET_DONGLE; -unsigned IOCTL_ISV_CMD = ISV_CMD; -unsigned IOCTL_WTQICMD = WTQICMD; -unsigned IOCTL_ISCSI_GET_VERSION = ISCSI_GET_VERSION; -unsigned IOCTL_ISCSI_LOGIN = ISCSI_LOGIN; -unsigned IOCTL_ISCSI_LOGOUT = ISCSI_LOGOUT; -unsigned IOCTL_ISCSI_ADD_CONNECTION = ISCSI_ADD_CONNECTION; -unsigned IOCTL_ISCSI_RESTORE_CONNECTION = ISCSI_RESTORE_CONNECTION; -unsigned IOCTL_ISCSI_REMOVE_CONNECTION = ISCSI_REMOVE_CONNECTION; -unsigned IOCTL_ISCSI_CONNECTION_STATUS = ISCSI_CONNECTION_STATUS; -unsigned IOCTL_ISCSI_SEND_TARGETS = ISCSI_SEND_TARGETS; -unsigned IOCTL_ISCSI_SET_NODE_NAME = ISCSI_SET_NODE_NAME; -unsigned IOCTL_ISCSI_IO_COMMAND = ISCSI_IO_COMMAND; -unsigned IOCTL_ISCSI_REGISTER_EVENT = ISCSI_REGISTER_EVENT; -unsigned IOCTL_ISCSI_DEREGISTER_EVENT = ISCSI_DEREGISTER_EVENT; -unsigned IOCTL_ISCSI_WAIT_EVENT = ISCSI_WAIT_EVENT; -unsigned IOCTL_ISCSI_POLL_EVENT = ISCSI_POLL_EVENT; -unsigned IOCTL_OFIOCGET = OFIOCGET; -unsigned IOCTL_OFIOCSET = OFIOCSET; -unsigned IOCTL_OFIOCNEXTPROP = OFIOCNEXTPROP; -unsigned IOCTL_OFIOCGETOPTNODE = OFIOCGETOPTNODE; -unsigned IOCTL_OFIOCGETNEXT = OFIOCGETNEXT; -unsigned IOCTL_OFIOCGETCHILD = OFIOCGETCHILD; -unsigned IOCTL_OFIOCFINDDEVICE = OFIOCFINDDEVICE; -unsigned IOCTL_AMR_IO_VERSION = AMR_IO_VERSION; -unsigned IOCTL_AMR_IO_COMMAND = AMR_IO_COMMAND; -unsigned IOCTL_MLYIO_COMMAND = MLYIO_COMMAND; -unsigned IOCTL_MLYIO_HEALTH = MLYIO_HEALTH; -unsigned IOCTL_PCI_IOC_CFGREAD = PCI_IOC_CFGREAD; -unsigned IOCTL_PCI_IOC_CFGWRITE = PCI_IOC_CFGWRITE; -unsigned IOCTL_PCI_IOC_BDF_CFGREAD = PCI_IOC_BDF_CFGREAD; -unsigned IOCTL_PCI_IOC_BDF_CFGWRITE = PCI_IOC_BDF_CFGWRITE; -unsigned IOCTL_PCI_IOC_BUSINFO = PCI_IOC_BUSINFO; -unsigned IOCTL_PCI_IOC_DRVNAME = PCI_IOC_DRVNAME; -unsigned IOCTL_PCI_IOC_DRVNAMEONBUS = PCI_IOC_DRVNAMEONBUS; -unsigned IOCTL_TWEIO_COMMAND = TWEIO_COMMAND; -unsigned IOCTL_TWEIO_STATS = TWEIO_STATS; -unsigned IOCTL_TWEIO_AEN_POLL = TWEIO_AEN_POLL; -unsigned IOCTL_TWEIO_AEN_WAIT = TWEIO_AEN_WAIT; -unsigned IOCTL_TWEIO_SET_PARAM = TWEIO_SET_PARAM; -unsigned IOCTL_TWEIO_GET_PARAM = TWEIO_GET_PARAM; -unsigned IOCTL_TWEIO_RESET = TWEIO_RESET; -unsigned IOCTL_TWEIO_ADD_UNIT = TWEIO_ADD_UNIT; -unsigned IOCTL_TWEIO_DEL_UNIT = TWEIO_DEL_UNIT; -unsigned IOCTL_SIOCSCNWDOMAIN = SIOCSCNWDOMAIN; -unsigned IOCTL_SIOCGCNWDOMAIN = SIOCGCNWDOMAIN; -unsigned IOCTL_SIOCSCNWKEY = SIOCSCNWKEY; -unsigned IOCTL_SIOCGCNWSTATUS = SIOCGCNWSTATUS; -unsigned IOCTL_SIOCGCNWSTATS = SIOCGCNWSTATS; -unsigned IOCTL_SIOCGCNWTRAIL = SIOCGCNWTRAIL; -unsigned IOCTL_SIOCGRAYSIGLEV = SIOCGRAYSIGLEV; -unsigned IOCTL_RAIDFRAME_SHUTDOWN = RAIDFRAME_SHUTDOWN; -unsigned IOCTL_RAIDFRAME_TUR = RAIDFRAME_TUR; -unsigned IOCTL_RAIDFRAME_FAIL_DISK = RAIDFRAME_FAIL_DISK; -unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS = RAIDFRAME_CHECK_RECON_STATUS; -unsigned IOCTL_RAIDFRAME_REWRITEPARITY = RAIDFRAME_REWRITEPARITY; -unsigned IOCTL_RAIDFRAME_COPYBACK = RAIDFRAME_COPYBACK; -unsigned IOCTL_RAIDFRAME_SPARET_WAIT = RAIDFRAME_SPARET_WAIT; -unsigned IOCTL_RAIDFRAME_SEND_SPARET = RAIDFRAME_SEND_SPARET; -unsigned IOCTL_RAIDFRAME_ABORT_SPARET_WAIT = RAIDFRAME_ABORT_SPARET_WAIT; -unsigned IOCTL_RAIDFRAME_START_ATRACE = RAIDFRAME_START_ATRACE; -unsigned IOCTL_RAIDFRAME_STOP_ATRACE = RAIDFRAME_STOP_ATRACE; -unsigned IOCTL_RAIDFRAME_GET_SIZE = RAIDFRAME_GET_SIZE; -unsigned IOCTL_RAIDFRAME_RESET_ACCTOTALS = RAIDFRAME_RESET_ACCTOTALS; -unsigned IOCTL_RAIDFRAME_KEEP_ACCTOTALS = RAIDFRAME_KEEP_ACCTOTALS; -unsigned IOCTL_RAIDFRAME_GET_COMPONENT_LABEL = RAIDFRAME_GET_COMPONENT_LABEL; -unsigned IOCTL_RAIDFRAME_SET_COMPONENT_LABEL = RAIDFRAME_SET_COMPONENT_LABEL; -unsigned IOCTL_RAIDFRAME_INIT_LABELS = RAIDFRAME_INIT_LABELS; -unsigned IOCTL_RAIDFRAME_ADD_HOT_SPARE = RAIDFRAME_ADD_HOT_SPARE; -unsigned IOCTL_RAIDFRAME_REMOVE_HOT_SPARE = RAIDFRAME_REMOVE_HOT_SPARE; -unsigned IOCTL_RAIDFRAME_REBUILD_IN_PLACE = RAIDFRAME_REBUILD_IN_PLACE; -unsigned IOCTL_RAIDFRAME_CHECK_PARITY = RAIDFRAME_CHECK_PARITY; -unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS = - RAIDFRAME_CHECK_PARITYREWRITE_STATUS; -unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS = - RAIDFRAME_CHECK_COPYBACK_STATUS; -unsigned IOCTL_RAIDFRAME_SET_AUTOCONFIG = RAIDFRAME_SET_AUTOCONFIG; -unsigned IOCTL_RAIDFRAME_SET_ROOT = RAIDFRAME_SET_ROOT; -unsigned IOCTL_RAIDFRAME_DELETE_COMPONENT = RAIDFRAME_DELETE_COMPONENT; -unsigned IOCTL_RAIDFRAME_INCORPORATE_HOT_SPARE = - RAIDFRAME_INCORPORATE_HOT_SPARE; -unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS_EXT = - RAIDFRAME_CHECK_RECON_STATUS_EXT; -unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT = - RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT; -unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS_EXT = - RAIDFRAME_CHECK_COPYBACK_STATUS_EXT; -unsigned IOCTL_RAIDFRAME_CONFIGURE = RAIDFRAME_CONFIGURE; -unsigned IOCTL_RAIDFRAME_GET_INFO = RAIDFRAME_GET_INFO; -unsigned IOCTL_RAIDFRAME_PARITYMAP_STATUS = RAIDFRAME_PARITYMAP_STATUS; -unsigned IOCTL_RAIDFRAME_PARITYMAP_GET_DISABLE = - RAIDFRAME_PARITYMAP_GET_DISABLE; -unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_DISABLE = - RAIDFRAME_PARITYMAP_SET_DISABLE; -unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_PARAMS = RAIDFRAME_PARITYMAP_SET_PARAMS; -unsigned IOCTL_RAIDFRAME_SET_LAST_UNIT = RAIDFRAME_SET_LAST_UNIT; -unsigned IOCTL_MBPPIOCSPARAM = MBPPIOCSPARAM; -unsigned IOCTL_MBPPIOCGPARAM = MBPPIOCGPARAM; -unsigned IOCTL_MBPPIOCGSTAT = MBPPIOCGSTAT; -unsigned IOCTL_SESIOC_GETNOBJ = SESIOC_GETNOBJ; -unsigned IOCTL_SESIOC_GETOBJMAP = SESIOC_GETOBJMAP; -unsigned IOCTL_SESIOC_GETENCSTAT = SESIOC_GETENCSTAT; -unsigned IOCTL_SESIOC_SETENCSTAT = SESIOC_SETENCSTAT; -unsigned IOCTL_SESIOC_GETOBJSTAT = SESIOC_GETOBJSTAT; -unsigned IOCTL_SESIOC_SETOBJSTAT = SESIOC_SETOBJSTAT; -unsigned IOCTL_SESIOC_GETTEXT = SESIOC_GETTEXT; -unsigned IOCTL_SESIOC_INIT = SESIOC_INIT; -unsigned IOCTL_SUN_DKIOCGGEOM = SUN_DKIOCGGEOM; -unsigned IOCTL_SUN_DKIOCINFO = SUN_DKIOCINFO; -unsigned IOCTL_SUN_DKIOCGPART = SUN_DKIOCGPART; -unsigned IOCTL_FBIOGTYPE = FBIOGTYPE; -unsigned IOCTL_FBIOPUTCMAP = FBIOPUTCMAP; -unsigned IOCTL_FBIOGETCMAP = FBIOGETCMAP; -unsigned IOCTL_FBIOGATTR = FBIOGATTR; -unsigned IOCTL_FBIOSVIDEO = FBIOSVIDEO; -unsigned IOCTL_FBIOGVIDEO = FBIOGVIDEO; -unsigned IOCTL_FBIOSCURSOR = FBIOSCURSOR; -unsigned IOCTL_FBIOGCURSOR = FBIOGCURSOR; -unsigned IOCTL_FBIOSCURPOS = FBIOSCURPOS; -unsigned IOCTL_FBIOGCURPOS = FBIOGCURPOS; -unsigned IOCTL_FBIOGCURMAX = FBIOGCURMAX; -unsigned IOCTL_KIOCTRANS = KIOCTRANS; -unsigned IOCTL_KIOCSETKEY = KIOCSETKEY; -unsigned IOCTL_KIOCGETKEY = KIOCGETKEY; -unsigned IOCTL_KIOCGTRANS = KIOCGTRANS; -unsigned IOCTL_KIOCCMD = KIOCCMD; -unsigned IOCTL_KIOCTYPE = KIOCTYPE; -unsigned IOCTL_KIOCSDIRECT = KIOCSDIRECT; -unsigned IOCTL_KIOCSKEY = KIOCSKEY; -unsigned IOCTL_KIOCGKEY = KIOCGKEY; -unsigned IOCTL_KIOCSLED = KIOCSLED; -unsigned IOCTL_KIOCGLED = KIOCGLED; -unsigned IOCTL_KIOCLAYOUT = KIOCLAYOUT; -unsigned IOCTL_VUIDSFORMAT = VUIDSFORMAT; -unsigned IOCTL_VUIDGFORMAT = VUIDGFORMAT; -unsigned IOCTL_STICIO_GXINFO = STICIO_GXINFO; -unsigned IOCTL_STICIO_RESET = STICIO_RESET; -unsigned IOCTL_STICIO_STARTQ = STICIO_STARTQ; -unsigned IOCTL_STICIO_STOPQ = STICIO_STOPQ; -unsigned IOCTL_UKYOPON_IDENTIFY = UKYOPON_IDENTIFY; -unsigned IOCTL_URIO_SEND_COMMAND = URIO_SEND_COMMAND; -unsigned IOCTL_URIO_RECV_COMMAND = URIO_RECV_COMMAND; -unsigned IOCTL_USB_REQUEST = USB_REQUEST; -unsigned IOCTL_USB_SETDEBUG = USB_SETDEBUG; -unsigned IOCTL_USB_DISCOVER = USB_DISCOVER; -unsigned IOCTL_USB_DEVICEINFO = USB_DEVICEINFO; -unsigned IOCTL_USB_DEVICEINFO_OLD = USB_DEVICEINFO_OLD; -unsigned IOCTL_USB_DEVICESTATS = USB_DEVICESTATS; -unsigned IOCTL_USB_GET_REPORT_DESC = USB_GET_REPORT_DESC; -unsigned IOCTL_USB_SET_IMMED = USB_SET_IMMED; -unsigned IOCTL_USB_GET_REPORT = USB_GET_REPORT; -unsigned IOCTL_USB_SET_REPORT = USB_SET_REPORT; -unsigned IOCTL_USB_GET_REPORT_ID = USB_GET_REPORT_ID; -unsigned IOCTL_USB_GET_CONFIG = USB_GET_CONFIG; -unsigned IOCTL_USB_SET_CONFIG = USB_SET_CONFIG; -unsigned IOCTL_USB_GET_ALTINTERFACE = USB_GET_ALTINTERFACE; -unsigned IOCTL_USB_SET_ALTINTERFACE = USB_SET_ALTINTERFACE; -unsigned IOCTL_USB_GET_NO_ALT = USB_GET_NO_ALT; -unsigned IOCTL_USB_GET_DEVICE_DESC = USB_GET_DEVICE_DESC; -unsigned IOCTL_USB_GET_CONFIG_DESC = USB_GET_CONFIG_DESC; -unsigned IOCTL_USB_GET_INTERFACE_DESC = USB_GET_INTERFACE_DESC; -unsigned IOCTL_USB_GET_ENDPOINT_DESC = USB_GET_ENDPOINT_DESC; -unsigned IOCTL_USB_GET_FULL_DESC = USB_GET_FULL_DESC; -unsigned IOCTL_USB_GET_STRING_DESC = USB_GET_STRING_DESC; -unsigned IOCTL_USB_DO_REQUEST = USB_DO_REQUEST; -unsigned IOCTL_USB_GET_DEVICEINFO = USB_GET_DEVICEINFO; -unsigned IOCTL_USB_GET_DEVICEINFO_OLD = USB_GET_DEVICEINFO_OLD; -unsigned IOCTL_USB_SET_SHORT_XFER = USB_SET_SHORT_XFER; -unsigned IOCTL_USB_SET_TIMEOUT = USB_SET_TIMEOUT; -unsigned IOCTL_USB_SET_BULK_RA = USB_SET_BULK_RA; -unsigned IOCTL_USB_SET_BULK_WB = USB_SET_BULK_WB; -unsigned IOCTL_USB_SET_BULK_RA_OPT = USB_SET_BULK_RA_OPT; -unsigned IOCTL_USB_SET_BULK_WB_OPT = USB_SET_BULK_WB_OPT; -unsigned IOCTL_USB_GET_CM_OVER_DATA = USB_GET_CM_OVER_DATA; -unsigned IOCTL_USB_SET_CM_OVER_DATA = USB_SET_CM_OVER_DATA; -unsigned IOCTL_UTOPPYIOTURBO = UTOPPYIOTURBO; -unsigned IOCTL_UTOPPYIOCANCEL = UTOPPYIOCANCEL; -unsigned IOCTL_UTOPPYIOREBOOT = UTOPPYIOREBOOT; -unsigned IOCTL_UTOPPYIOSTATS = UTOPPYIOSTATS; -unsigned IOCTL_UTOPPYIORENAME = UTOPPYIORENAME; -unsigned IOCTL_UTOPPYIOMKDIR = UTOPPYIOMKDIR; -unsigned IOCTL_UTOPPYIODELETE = UTOPPYIODELETE; -unsigned IOCTL_UTOPPYIOREADDIR = UTOPPYIOREADDIR; -unsigned IOCTL_UTOPPYIOREADFILE = UTOPPYIOREADFILE; -unsigned IOCTL_UTOPPYIOWRITEFILE = UTOPPYIOWRITEFILE; -unsigned IOCTL_DIOSXDCMD = DIOSXDCMD; -unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; -unsigned IOCTL_VT_SETMODE = VT_SETMODE; -unsigned IOCTL_VT_GETMODE = VT_GETMODE; -unsigned IOCTL_VT_RELDISP = VT_RELDISP; -unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; -unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; -unsigned IOCTL_VT_GETACTIVE = VT_GETACTIVE; -unsigned IOCTL_VT_GETSTATE = VT_GETSTATE; -unsigned IOCTL_KDGETKBENT = KDGETKBENT; -unsigned IOCTL_KDGKBMODE = KDGKBMODE; -unsigned IOCTL_KDSKBMODE = KDSKBMODE; -unsigned IOCTL_KDMKTONE = KDMKTONE; -unsigned IOCTL_KDSETMODE = KDSETMODE; -unsigned IOCTL_KDENABIO = KDENABIO; -unsigned IOCTL_KDDISABIO = KDDISABIO; -unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; -unsigned IOCTL_KDGETLED = KDGETLED; -unsigned IOCTL_KDSETLED = KDSETLED; -unsigned IOCTL_KDSETRAD = KDSETRAD; -unsigned IOCTL_VGAPCVTID = VGAPCVTID; -unsigned IOCTL_CONS_GETVERS = CONS_GETVERS; -unsigned IOCTL_WSKBDIO_GTYPE = WSKBDIO_GTYPE; -unsigned IOCTL_WSKBDIO_BELL = WSKBDIO_BELL; -unsigned IOCTL_WSKBDIO_COMPLEXBELL = WSKBDIO_COMPLEXBELL; -unsigned IOCTL_WSKBDIO_SETBELL = WSKBDIO_SETBELL; -unsigned IOCTL_WSKBDIO_GETBELL = WSKBDIO_GETBELL; -unsigned IOCTL_WSKBDIO_SETDEFAULTBELL = WSKBDIO_SETDEFAULTBELL; -unsigned IOCTL_WSKBDIO_GETDEFAULTBELL = WSKBDIO_GETDEFAULTBELL; -unsigned IOCTL_WSKBDIO_SETKEYREPEAT = WSKBDIO_SETKEYREPEAT; -unsigned IOCTL_WSKBDIO_GETKEYREPEAT = WSKBDIO_GETKEYREPEAT; -unsigned IOCTL_WSKBDIO_SETDEFAULTKEYREPEAT = WSKBDIO_SETDEFAULTKEYREPEAT; -unsigned IOCTL_WSKBDIO_GETDEFAULTKEYREPEAT = WSKBDIO_GETDEFAULTKEYREPEAT; -unsigned IOCTL_WSKBDIO_SETLEDS = WSKBDIO_SETLEDS; -unsigned IOCTL_WSKBDIO_GETLEDS = WSKBDIO_GETLEDS; -unsigned IOCTL_WSKBDIO_GETMAP = WSKBDIO_GETMAP; -unsigned IOCTL_WSKBDIO_SETMAP = WSKBDIO_SETMAP; -unsigned IOCTL_WSKBDIO_GETENCODING = WSKBDIO_GETENCODING; -unsigned IOCTL_WSKBDIO_SETENCODING = WSKBDIO_SETENCODING; -unsigned IOCTL_WSKBDIO_SETMODE = WSKBDIO_SETMODE; -unsigned IOCTL_WSKBDIO_GETMODE = WSKBDIO_GETMODE; -unsigned IOCTL_WSKBDIO_SETKEYCLICK = WSKBDIO_SETKEYCLICK; -unsigned IOCTL_WSKBDIO_GETKEYCLICK = WSKBDIO_GETKEYCLICK; -unsigned IOCTL_WSKBDIO_GETSCROLL = WSKBDIO_GETSCROLL; -unsigned IOCTL_WSKBDIO_SETSCROLL = WSKBDIO_SETSCROLL; -unsigned IOCTL_WSKBDIO_SETVERSION = WSKBDIO_SETVERSION; -unsigned IOCTL_WSMOUSEIO_GTYPE = WSMOUSEIO_GTYPE; -unsigned IOCTL_WSMOUSEIO_SRES = WSMOUSEIO_SRES; -unsigned IOCTL_WSMOUSEIO_SSCALE = WSMOUSEIO_SSCALE; -unsigned IOCTL_WSMOUSEIO_SRATE = WSMOUSEIO_SRATE; -unsigned IOCTL_WSMOUSEIO_SCALIBCOORDS = WSMOUSEIO_SCALIBCOORDS; -unsigned IOCTL_WSMOUSEIO_GCALIBCOORDS = WSMOUSEIO_GCALIBCOORDS; -unsigned IOCTL_WSMOUSEIO_GETID = WSMOUSEIO_GETID; -unsigned IOCTL_WSMOUSEIO_GETREPEAT = WSMOUSEIO_GETREPEAT; -unsigned IOCTL_WSMOUSEIO_SETREPEAT = WSMOUSEIO_SETREPEAT; -unsigned IOCTL_WSMOUSEIO_SETVERSION = WSMOUSEIO_SETVERSION; -unsigned IOCTL_WSDISPLAYIO_GTYPE = WSDISPLAYIO_GTYPE; -unsigned IOCTL_WSDISPLAYIO_GINFO = WSDISPLAYIO_GINFO; -unsigned IOCTL_WSDISPLAYIO_GETCMAP = WSDISPLAYIO_GETCMAP; -unsigned IOCTL_WSDISPLAYIO_PUTCMAP = WSDISPLAYIO_PUTCMAP; -unsigned IOCTL_WSDISPLAYIO_GVIDEO = WSDISPLAYIO_GVIDEO; -unsigned IOCTL_WSDISPLAYIO_SVIDEO = WSDISPLAYIO_SVIDEO; -unsigned IOCTL_WSDISPLAYIO_GCURPOS = WSDISPLAYIO_GCURPOS; -unsigned IOCTL_WSDISPLAYIO_SCURPOS = WSDISPLAYIO_SCURPOS; -unsigned IOCTL_WSDISPLAYIO_GCURMAX = WSDISPLAYIO_GCURMAX; -unsigned IOCTL_WSDISPLAYIO_GCURSOR = WSDISPLAYIO_GCURSOR; -unsigned IOCTL_WSDISPLAYIO_SCURSOR = WSDISPLAYIO_SCURSOR; -unsigned IOCTL_WSDISPLAYIO_GMODE = WSDISPLAYIO_GMODE; -unsigned IOCTL_WSDISPLAYIO_SMODE = WSDISPLAYIO_SMODE; -unsigned IOCTL_WSDISPLAYIO_LDFONT = WSDISPLAYIO_LDFONT; -unsigned IOCTL_WSDISPLAYIO_ADDSCREEN = WSDISPLAYIO_ADDSCREEN; -unsigned IOCTL_WSDISPLAYIO_DELSCREEN = WSDISPLAYIO_DELSCREEN; -unsigned IOCTL_WSDISPLAYIO_SFONT = WSDISPLAYIO_SFONT; -unsigned IOCTL__O_WSDISPLAYIO_SETKEYBOARD = _O_WSDISPLAYIO_SETKEYBOARD; -unsigned IOCTL_WSDISPLAYIO_GETPARAM = WSDISPLAYIO_GETPARAM; -unsigned IOCTL_WSDISPLAYIO_SETPARAM = WSDISPLAYIO_SETPARAM; -unsigned IOCTL_WSDISPLAYIO_GETACTIVESCREEN = WSDISPLAYIO_GETACTIVESCREEN; -unsigned IOCTL_WSDISPLAYIO_GETWSCHAR = WSDISPLAYIO_GETWSCHAR; -unsigned IOCTL_WSDISPLAYIO_PUTWSCHAR = WSDISPLAYIO_PUTWSCHAR; -unsigned IOCTL_WSDISPLAYIO_DGSCROLL = WSDISPLAYIO_DGSCROLL; -unsigned IOCTL_WSDISPLAYIO_DSSCROLL = WSDISPLAYIO_DSSCROLL; -unsigned IOCTL_WSDISPLAYIO_GMSGATTRS = WSDISPLAYIO_GMSGATTRS; -unsigned IOCTL_WSDISPLAYIO_SMSGATTRS = WSDISPLAYIO_SMSGATTRS; -unsigned IOCTL_WSDISPLAYIO_GBORDER = WSDISPLAYIO_GBORDER; -unsigned IOCTL_WSDISPLAYIO_SBORDER = WSDISPLAYIO_SBORDER; -unsigned IOCTL_WSDISPLAYIO_SSPLASH = WSDISPLAYIO_SSPLASH; -unsigned IOCTL_WSDISPLAYIO_SPROGRESS = WSDISPLAYIO_SPROGRESS; -unsigned IOCTL_WSDISPLAYIO_LINEBYTES = WSDISPLAYIO_LINEBYTES; -unsigned IOCTL_WSDISPLAYIO_SETVERSION = WSDISPLAYIO_SETVERSION; -unsigned IOCTL_WSMUXIO_ADD_DEVICE = WSMUXIO_ADD_DEVICE; -unsigned IOCTL_WSMUXIO_REMOVE_DEVICE = WSMUXIO_REMOVE_DEVICE; -unsigned IOCTL_WSMUXIO_LIST_DEVICES = WSMUXIO_LIST_DEVICES; -unsigned IOCTL_WSMUXIO_INJECTEVENT = WSMUXIO_INJECTEVENT; -unsigned IOCTL_WSDISPLAYIO_GET_BUSID = WSDISPLAYIO_GET_BUSID; -unsigned IOCTL_WSDISPLAYIO_GET_EDID = WSDISPLAYIO_GET_EDID; -unsigned IOCTL_WSDISPLAYIO_SET_POLLING = WSDISPLAYIO_SET_POLLING; -unsigned IOCTL_WSDISPLAYIO_GET_FBINFO = WSDISPLAYIO_GET_FBINFO; -unsigned IOCTL_WSDISPLAYIO_DOBLIT = WSDISPLAYIO_DOBLIT; -unsigned IOCTL_WSDISPLAYIO_WAITBLIT = WSDISPLAYIO_WAITBLIT; -unsigned IOCTL_BIOCLOCATE = BIOCLOCATE; -unsigned IOCTL_BIOCINQ = BIOCINQ; -unsigned IOCTL_BIOCDISK_NOVOL = BIOCDISK_NOVOL; -unsigned IOCTL_BIOCDISK = BIOCDISK; -unsigned IOCTL_BIOCVOL = BIOCVOL; -unsigned IOCTL_BIOCALARM = BIOCALARM; -unsigned IOCTL_BIOCBLINK = BIOCBLINK; -unsigned IOCTL_BIOCSETSTATE = BIOCSETSTATE; -unsigned IOCTL_BIOCVOLOPS = BIOCVOLOPS; -unsigned IOCTL_MD_GETCONF = MD_GETCONF; -unsigned IOCTL_MD_SETCONF = MD_SETCONF; -unsigned IOCTL_CCDIOCSET = CCDIOCSET; -unsigned IOCTL_CCDIOCCLR = CCDIOCCLR; -unsigned IOCTL_CGDIOCSET = CGDIOCSET; -unsigned IOCTL_CGDIOCCLR = CGDIOCCLR; -unsigned IOCTL_CGDIOCGET = CGDIOCGET; -unsigned IOCTL_FSSIOCSET = FSSIOCSET; -unsigned IOCTL_FSSIOCGET = FSSIOCGET; -unsigned IOCTL_FSSIOCCLR = FSSIOCCLR; -unsigned IOCTL_FSSIOFSET = FSSIOFSET; -unsigned IOCTL_FSSIOFGET = FSSIOFGET; -unsigned IOCTL_BTDEV_ATTACH = BTDEV_ATTACH; -unsigned IOCTL_BTDEV_DETACH = BTDEV_DETACH; -unsigned IOCTL_BTSCO_GETINFO = BTSCO_GETINFO; -unsigned IOCTL_KTTCP_IO_SEND = KTTCP_IO_SEND; -unsigned IOCTL_KTTCP_IO_RECV = KTTCP_IO_RECV; -unsigned IOCTL_IOC_LOCKSTAT_GVERSION = IOC_LOCKSTAT_GVERSION; -unsigned IOCTL_IOC_LOCKSTAT_ENABLE = IOC_LOCKSTAT_ENABLE; -unsigned IOCTL_IOC_LOCKSTAT_DISABLE = IOC_LOCKSTAT_DISABLE; -unsigned IOCTL_VNDIOCSET = VNDIOCSET; -unsigned IOCTL_VNDIOCCLR = VNDIOCCLR; -unsigned IOCTL_VNDIOCGET = VNDIOCGET; -unsigned IOCTL_SPKRTONE = SPKRTONE; -unsigned IOCTL_SPKRTUNE = SPKRTUNE; -unsigned IOCTL_SPKRGETVOL = SPKRGETVOL; -unsigned IOCTL_SPKRSETVOL = SPKRSETVOL; -#if 0 /* interfaces are WIP */ -unsigned IOCTL_NVMM_IOC_CAPABILITY = NVMM_IOC_CAPABILITY; -unsigned IOCTL_NVMM_IOC_MACHINE_CREATE = NVMM_IOC_MACHINE_CREATE; -unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY = NVMM_IOC_MACHINE_DESTROY; -unsigned IOCTL_NVMM_IOC_MACHINE_CONFIGURE = NVMM_IOC_MACHINE_CONFIGURE; -unsigned IOCTL_NVMM_IOC_VCPU_CREATE = NVMM_IOC_VCPU_CREATE; -unsigned IOCTL_NVMM_IOC_VCPU_DESTROY = NVMM_IOC_VCPU_DESTROY; -unsigned IOCTL_NVMM_IOC_VCPU_SETSTATE = NVMM_IOC_VCPU_SETSTATE; -unsigned IOCTL_NVMM_IOC_VCPU_GETSTATE = NVMM_IOC_VCPU_GETSTATE; -unsigned IOCTL_NVMM_IOC_VCPU_INJECT = NVMM_IOC_VCPU_INJECT; -unsigned IOCTL_NVMM_IOC_VCPU_RUN = NVMM_IOC_VCPU_RUN; -unsigned IOCTL_NVMM_IOC_GPA_MAP = NVMM_IOC_GPA_MAP; -unsigned IOCTL_NVMM_IOC_GPA_UNMAP = NVMM_IOC_GPA_UNMAP; -unsigned IOCTL_NVMM_IOC_HVA_MAP = NVMM_IOC_HVA_MAP; -unsigned IOCTL_NVMM_IOC_HVA_UNMAP = NVMM_IOC_HVA_UNMAP; -#endif -unsigned IOCTL_AUTOFSREQUEST = AUTOFSREQUEST; -unsigned IOCTL_AUTOFSDONE = AUTOFSDONE; -unsigned IOCTL_BIOCGBLEN = BIOCGBLEN; -unsigned IOCTL_BIOCSBLEN = BIOCSBLEN; -unsigned IOCTL_BIOCSETF = BIOCSETF; -unsigned IOCTL_BIOCFLUSH = BIOCFLUSH; -unsigned IOCTL_BIOCPROMISC = BIOCPROMISC; -unsigned IOCTL_BIOCGDLT = BIOCGDLT; -unsigned IOCTL_BIOCGETIF = BIOCGETIF; -unsigned IOCTL_BIOCSETIF = BIOCSETIF; -unsigned IOCTL_BIOCGSTATS = BIOCGSTATS; -unsigned IOCTL_BIOCGSTATSOLD = BIOCGSTATSOLD; -unsigned IOCTL_BIOCIMMEDIATE = BIOCIMMEDIATE; -unsigned IOCTL_BIOCVERSION = BIOCVERSION; -unsigned IOCTL_BIOCSTCPF = BIOCSTCPF; -unsigned IOCTL_BIOCSUDPF = BIOCSUDPF; -unsigned IOCTL_BIOCGHDRCMPLT = BIOCGHDRCMPLT; -unsigned IOCTL_BIOCSHDRCMPLT = BIOCSHDRCMPLT; -unsigned IOCTL_BIOCSDLT = BIOCSDLT; -unsigned IOCTL_BIOCGDLTLIST = BIOCGDLTLIST; -unsigned IOCTL_BIOCGDIRECTION = BIOCGDIRECTION; -unsigned IOCTL_BIOCSDIRECTION = BIOCSDIRECTION; -unsigned IOCTL_BIOCSRTIMEOUT = BIOCSRTIMEOUT; -unsigned IOCTL_BIOCGRTIMEOUT = BIOCGRTIMEOUT; -unsigned IOCTL_BIOCGFEEDBACK = BIOCGFEEDBACK; -unsigned IOCTL_BIOCSFEEDBACK = BIOCSFEEDBACK; -unsigned IOCTL_GRESADDRS = GRESADDRS; -unsigned IOCTL_GRESADDRD = GRESADDRD; -unsigned IOCTL_GREGADDRS = GREGADDRS; -unsigned IOCTL_GREGADDRD = GREGADDRD; -unsigned IOCTL_GRESPROTO = GRESPROTO; -unsigned IOCTL_GREGPROTO = GREGPROTO; -unsigned IOCTL_GRESSOCK = GRESSOCK; -unsigned IOCTL_GREDSOCK = GREDSOCK; -unsigned IOCTL_PPPIOCGRAWIN = PPPIOCGRAWIN; -unsigned IOCTL_PPPIOCGFLAGS = PPPIOCGFLAGS; -unsigned IOCTL_PPPIOCSFLAGS = PPPIOCSFLAGS; -unsigned IOCTL_PPPIOCGASYNCMAP = PPPIOCGASYNCMAP; -unsigned IOCTL_PPPIOCSASYNCMAP = PPPIOCSASYNCMAP; -unsigned IOCTL_PPPIOCGUNIT = PPPIOCGUNIT; -unsigned IOCTL_PPPIOCGRASYNCMAP = PPPIOCGRASYNCMAP; -unsigned IOCTL_PPPIOCSRASYNCMAP = PPPIOCSRASYNCMAP; -unsigned IOCTL_PPPIOCGMRU = PPPIOCGMRU; -unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU; -unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID; -unsigned IOCTL_PPPIOCGXASYNCMAP = PPPIOCGXASYNCMAP; -unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP; -unsigned IOCTL_PPPIOCXFERUNIT = PPPIOCXFERUNIT; -unsigned IOCTL_PPPIOCSCOMPRESS = PPPIOCSCOMPRESS; -unsigned IOCTL_PPPIOCGNPMODE = PPPIOCGNPMODE; -unsigned IOCTL_PPPIOCSNPMODE = PPPIOCSNPMODE; -unsigned IOCTL_PPPIOCGIDLE = PPPIOCGIDLE; -unsigned IOCTL_PPPIOCGMTU = PPPIOCGMTU; -unsigned IOCTL_PPPIOCSMTU = PPPIOCSMTU; -unsigned IOCTL_SIOCGPPPSTATS = SIOCGPPPSTATS; -unsigned IOCTL_SIOCGPPPCSTATS = SIOCGPPPCSTATS; -unsigned IOCTL_IOC_NPF_VERSION = IOC_NPF_VERSION; -unsigned IOCTL_IOC_NPF_SWITCH = IOC_NPF_SWITCH; -unsigned IOCTL_IOC_NPF_LOAD = IOC_NPF_LOAD; -unsigned IOCTL_IOC_NPF_TABLE = IOC_NPF_TABLE; -unsigned IOCTL_IOC_NPF_STATS = IOC_NPF_STATS; -unsigned IOCTL_IOC_NPF_SAVE = IOC_NPF_SAVE; -unsigned IOCTL_IOC_NPF_RULE = IOC_NPF_RULE; -unsigned IOCTL_IOC_NPF_CONN_LOOKUP = IOC_NPF_CONN_LOOKUP; -unsigned IOCTL_PPPOESETPARMS = PPPOESETPARMS; -unsigned IOCTL_PPPOEGETPARMS = PPPOEGETPARMS; -unsigned IOCTL_PPPOEGETSESSION = PPPOEGETSESSION; -unsigned IOCTL_SPPPGETAUTHCFG = SPPPGETAUTHCFG; -unsigned IOCTL_SPPPSETAUTHCFG = SPPPSETAUTHCFG; -unsigned IOCTL_SPPPGETLCPCFG = SPPPGETLCPCFG; -unsigned IOCTL_SPPPSETLCPCFG = SPPPSETLCPCFG; -unsigned IOCTL_SPPPGETSTATUS = SPPPGETSTATUS; -unsigned IOCTL_SPPPGETSTATUSNCP = SPPPGETSTATUSNCP; -unsigned IOCTL_SPPPGETIDLETO = SPPPGETIDLETO; -unsigned IOCTL_SPPPSETIDLETO = SPPPSETIDLETO; -unsigned IOCTL_SPPPGETAUTHFAILURES = SPPPGETAUTHFAILURES; -unsigned IOCTL_SPPPSETAUTHFAILURE = SPPPSETAUTHFAILURE; -unsigned IOCTL_SPPPSETDNSOPTS = SPPPSETDNSOPTS; -unsigned IOCTL_SPPPGETDNSOPTS = SPPPGETDNSOPTS; -unsigned IOCTL_SPPPGETDNSADDRS = SPPPGETDNSADDRS; -unsigned IOCTL_SPPPSETKEEPALIVE = SPPPSETKEEPALIVE; -unsigned IOCTL_SPPPGETKEEPALIVE = SPPPGETKEEPALIVE; -unsigned IOCTL_SRT_GETNRT = SRT_GETNRT; -unsigned IOCTL_SRT_GETRT = SRT_GETRT; -unsigned IOCTL_SRT_SETRT = SRT_SETRT; -unsigned IOCTL_SRT_DELRT = SRT_DELRT; -unsigned IOCTL_SRT_SFLAGS = SRT_SFLAGS; -unsigned IOCTL_SRT_GFLAGS = SRT_GFLAGS; -unsigned IOCTL_SRT_SGFLAGS = SRT_SGFLAGS; -unsigned IOCTL_SRT_DEBUG = SRT_DEBUG; -unsigned IOCTL_TAPGIFNAME = TAPGIFNAME; -unsigned IOCTL_TUNSDEBUG = TUNSDEBUG; -unsigned IOCTL_TUNGDEBUG = TUNGDEBUG; -unsigned IOCTL_TUNSIFMODE = TUNSIFMODE; -unsigned IOCTL_TUNSLMODE = TUNSLMODE; -unsigned IOCTL_TUNSIFHEAD = TUNSIFHEAD; -unsigned IOCTL_TUNGIFHEAD = TUNGIFHEAD; -unsigned IOCTL_DIOCSTART = DIOCSTART; -unsigned IOCTL_DIOCSTOP = DIOCSTOP; -unsigned IOCTL_DIOCADDRULE = DIOCADDRULE; -unsigned IOCTL_DIOCGETRULES = DIOCGETRULES; -unsigned IOCTL_DIOCGETRULE = DIOCGETRULE; -unsigned IOCTL_DIOCSETLCK = DIOCSETLCK; -unsigned IOCTL_DIOCCLRSTATES = DIOCCLRSTATES; -unsigned IOCTL_DIOCGETSTATE = DIOCGETSTATE; -unsigned IOCTL_DIOCSETSTATUSIF = DIOCSETSTATUSIF; -unsigned IOCTL_DIOCGETSTATUS = DIOCGETSTATUS; -unsigned IOCTL_DIOCCLRSTATUS = DIOCCLRSTATUS; -unsigned IOCTL_DIOCNATLOOK = DIOCNATLOOK; -unsigned IOCTL_DIOCSETDEBUG = DIOCSETDEBUG; -unsigned IOCTL_DIOCGETSTATES = DIOCGETSTATES; -unsigned IOCTL_DIOCCHANGERULE = DIOCCHANGERULE; -unsigned IOCTL_DIOCSETTIMEOUT = DIOCSETTIMEOUT; -unsigned IOCTL_DIOCGETTIMEOUT = DIOCGETTIMEOUT; -unsigned IOCTL_DIOCADDSTATE = DIOCADDSTATE; -unsigned IOCTL_DIOCCLRRULECTRS = DIOCCLRRULECTRS; -unsigned IOCTL_DIOCGETLIMIT = DIOCGETLIMIT; -unsigned IOCTL_DIOCSETLIMIT = DIOCSETLIMIT; -unsigned IOCTL_DIOCKILLSTATES = DIOCKILLSTATES; -unsigned IOCTL_DIOCSTARTALTQ = DIOCSTARTALTQ; -unsigned IOCTL_DIOCSTOPALTQ = DIOCSTOPALTQ; -unsigned IOCTL_DIOCADDALTQ = DIOCADDALTQ; -unsigned IOCTL_DIOCGETALTQS = DIOCGETALTQS; -unsigned IOCTL_DIOCGETALTQ = DIOCGETALTQ; -unsigned IOCTL_DIOCCHANGEALTQ = DIOCCHANGEALTQ; -unsigned IOCTL_DIOCGETQSTATS = DIOCGETQSTATS; -unsigned IOCTL_DIOCBEGINADDRS = DIOCBEGINADDRS; -unsigned IOCTL_DIOCADDADDR = DIOCADDADDR; -unsigned IOCTL_DIOCGETADDRS = DIOCGETADDRS; -unsigned IOCTL_DIOCGETADDR = DIOCGETADDR; -unsigned IOCTL_DIOCCHANGEADDR = DIOCCHANGEADDR; -unsigned IOCTL_DIOCADDSTATES = DIOCADDSTATES; -unsigned IOCTL_DIOCGETRULESETS = DIOCGETRULESETS; -unsigned IOCTL_DIOCGETRULESET = DIOCGETRULESET; -unsigned IOCTL_DIOCRCLRTABLES = DIOCRCLRTABLES; -unsigned IOCTL_DIOCRADDTABLES = DIOCRADDTABLES; -unsigned IOCTL_DIOCRDELTABLES = DIOCRDELTABLES; -unsigned IOCTL_DIOCRGETTABLES = DIOCRGETTABLES; -unsigned IOCTL_DIOCRGETTSTATS = DIOCRGETTSTATS; -unsigned IOCTL_DIOCRCLRTSTATS = DIOCRCLRTSTATS; -unsigned IOCTL_DIOCRCLRADDRS = DIOCRCLRADDRS; -unsigned IOCTL_DIOCRADDADDRS = DIOCRADDADDRS; -unsigned IOCTL_DIOCRDELADDRS = DIOCRDELADDRS; -unsigned IOCTL_DIOCRSETADDRS = DIOCRSETADDRS; -unsigned IOCTL_DIOCRGETADDRS = DIOCRGETADDRS; -unsigned IOCTL_DIOCRGETASTATS = DIOCRGETASTATS; -unsigned IOCTL_DIOCRCLRASTATS = DIOCRCLRASTATS; -unsigned IOCTL_DIOCRTSTADDRS = DIOCRTSTADDRS; -unsigned IOCTL_DIOCRSETTFLAGS = DIOCRSETTFLAGS; -unsigned IOCTL_DIOCRINADEFINE = DIOCRINADEFINE; -unsigned IOCTL_DIOCOSFPFLUSH = DIOCOSFPFLUSH; -unsigned IOCTL_DIOCOSFPADD = DIOCOSFPADD; -unsigned IOCTL_DIOCOSFPGET = DIOCOSFPGET; -unsigned IOCTL_DIOCXBEGIN = DIOCXBEGIN; -unsigned IOCTL_DIOCXCOMMIT = DIOCXCOMMIT; -unsigned IOCTL_DIOCXROLLBACK = DIOCXROLLBACK; -unsigned IOCTL_DIOCGETSRCNODES = DIOCGETSRCNODES; -unsigned IOCTL_DIOCCLRSRCNODES = DIOCCLRSRCNODES; -unsigned IOCTL_DIOCSETHOSTID = DIOCSETHOSTID; -unsigned IOCTL_DIOCIGETIFACES = DIOCIGETIFACES; -unsigned IOCTL_DIOCSETIFFLAG = DIOCSETIFFLAG; -unsigned IOCTL_DIOCCLRIFFLAG = DIOCCLRIFFLAG; -unsigned IOCTL_DIOCKILLSRCNODES = DIOCKILLSRCNODES; -unsigned IOCTL_SLIOCGUNIT = SLIOCGUNIT; -unsigned IOCTL_SIOCGBTINFO = SIOCGBTINFO; -unsigned IOCTL_SIOCGBTINFOA = SIOCGBTINFOA; -unsigned IOCTL_SIOCNBTINFO = SIOCNBTINFO; -unsigned IOCTL_SIOCSBTFLAGS = SIOCSBTFLAGS; -unsigned IOCTL_SIOCSBTPOLICY = SIOCSBTPOLICY; -unsigned IOCTL_SIOCSBTPTYPE = SIOCSBTPTYPE; -unsigned IOCTL_SIOCGBTSTATS = SIOCGBTSTATS; -unsigned IOCTL_SIOCZBTSTATS = SIOCZBTSTATS; -unsigned IOCTL_SIOCBTDUMP = SIOCBTDUMP; -unsigned IOCTL_SIOCSBTSCOMTU = SIOCSBTSCOMTU; -unsigned IOCTL_SIOCGBTFEAT = SIOCGBTFEAT; -unsigned IOCTL_SIOCADNAT = SIOCADNAT; -unsigned IOCTL_SIOCRMNAT = SIOCRMNAT; -unsigned IOCTL_SIOCGNATS = SIOCGNATS; -unsigned IOCTL_SIOCGNATL = SIOCGNATL; -unsigned IOCTL_SIOCPURGENAT = SIOCPURGENAT; -unsigned IOCTL_SIOCCONNECTX = SIOCCONNECTX; -unsigned IOCTL_SIOCCONNECTXDEL = SIOCCONNECTXDEL; -unsigned IOCTL_SIOCSIFINFO_FLAGS = SIOCSIFINFO_FLAGS; -unsigned IOCTL_SIOCAADDRCTL_POLICY = SIOCAADDRCTL_POLICY; -unsigned IOCTL_SIOCDADDRCTL_POLICY = SIOCDADDRCTL_POLICY; -unsigned IOCTL_SMBIOC_OPENSESSION = SMBIOC_OPENSESSION; -unsigned IOCTL_SMBIOC_OPENSHARE = SMBIOC_OPENSHARE; -unsigned IOCTL_SMBIOC_REQUEST = SMBIOC_REQUEST; -unsigned IOCTL_SMBIOC_SETFLAGS = SMBIOC_SETFLAGS; -unsigned IOCTL_SMBIOC_LOOKUP = SMBIOC_LOOKUP; -unsigned IOCTL_SMBIOC_READ = SMBIOC_READ; -unsigned IOCTL_SMBIOC_WRITE = SMBIOC_WRITE; -unsigned IOCTL_AGPIOC_INFO = AGPIOC_INFO; -unsigned IOCTL_AGPIOC_ACQUIRE = AGPIOC_ACQUIRE; -unsigned IOCTL_AGPIOC_RELEASE = AGPIOC_RELEASE; -unsigned IOCTL_AGPIOC_SETUP = AGPIOC_SETUP; -unsigned IOCTL_AGPIOC_ALLOCATE = AGPIOC_ALLOCATE; -unsigned IOCTL_AGPIOC_DEALLOCATE = AGPIOC_DEALLOCATE; -unsigned IOCTL_AGPIOC_BIND = AGPIOC_BIND; -unsigned IOCTL_AGPIOC_UNBIND = AGPIOC_UNBIND; -unsigned IOCTL_AUDIO_GETINFO = AUDIO_GETINFO; -unsigned IOCTL_AUDIO_SETINFO = AUDIO_SETINFO; -unsigned IOCTL_AUDIO_DRAIN = AUDIO_DRAIN; -unsigned IOCTL_AUDIO_FLUSH = AUDIO_FLUSH; -unsigned IOCTL_AUDIO_WSEEK = AUDIO_WSEEK; -unsigned IOCTL_AUDIO_RERROR = AUDIO_RERROR; -unsigned IOCTL_AUDIO_GETDEV = AUDIO_GETDEV; -unsigned IOCTL_AUDIO_GETENC = AUDIO_GETENC; -unsigned IOCTL_AUDIO_GETFD = AUDIO_GETFD; -unsigned IOCTL_AUDIO_SETFD = AUDIO_SETFD; -unsigned IOCTL_AUDIO_PERROR = AUDIO_PERROR; -unsigned IOCTL_AUDIO_GETIOFFS = AUDIO_GETIOFFS; -unsigned IOCTL_AUDIO_GETOOFFS = AUDIO_GETOOFFS; -unsigned IOCTL_AUDIO_GETPROPS = AUDIO_GETPROPS; -unsigned IOCTL_AUDIO_GETBUFINFO = AUDIO_GETBUFINFO; -unsigned IOCTL_AUDIO_SETCHAN = AUDIO_SETCHAN; -unsigned IOCTL_AUDIO_GETCHAN = AUDIO_GETCHAN; -unsigned IOCTL_AUDIO_MIXER_READ = AUDIO_MIXER_READ; -unsigned IOCTL_AUDIO_MIXER_WRITE = AUDIO_MIXER_WRITE; -unsigned IOCTL_AUDIO_MIXER_DEVINFO = AUDIO_MIXER_DEVINFO; -unsigned IOCTL_ATAIOCCOMMAND = ATAIOCCOMMAND; -unsigned IOCTL_ATABUSIOSCAN = ATABUSIOSCAN; -unsigned IOCTL_ATABUSIORESET = ATABUSIORESET; -unsigned IOCTL_ATABUSIODETACH = ATABUSIODETACH; -unsigned IOCTL_CDIOCPLAYTRACKS = CDIOCPLAYTRACKS; -unsigned IOCTL_CDIOCPLAYBLOCKS = CDIOCPLAYBLOCKS; -unsigned IOCTL_CDIOCREADSUBCHANNEL = CDIOCREADSUBCHANNEL; -unsigned IOCTL_CDIOREADTOCHEADER = CDIOREADTOCHEADER; -unsigned IOCTL_CDIOREADTOCENTRIES = CDIOREADTOCENTRIES; -unsigned IOCTL_CDIOREADMSADDR = CDIOREADMSADDR; -unsigned IOCTL_CDIOCSETPATCH = CDIOCSETPATCH; -unsigned IOCTL_CDIOCGETVOL = CDIOCGETVOL; -unsigned IOCTL_CDIOCSETVOL = CDIOCSETVOL; -unsigned IOCTL_CDIOCSETMONO = CDIOCSETMONO; -unsigned IOCTL_CDIOCSETSTEREO = CDIOCSETSTEREO; -unsigned IOCTL_CDIOCSETMUTE = CDIOCSETMUTE; -unsigned IOCTL_CDIOCSETLEFT = CDIOCSETLEFT; -unsigned IOCTL_CDIOCSETRIGHT = CDIOCSETRIGHT; -unsigned IOCTL_CDIOCSETDEBUG = CDIOCSETDEBUG; -unsigned IOCTL_CDIOCCLRDEBUG = CDIOCCLRDEBUG; -unsigned IOCTL_CDIOCPAUSE = CDIOCPAUSE; -unsigned IOCTL_CDIOCRESUME = CDIOCRESUME; -unsigned IOCTL_CDIOCRESET = CDIOCRESET; -unsigned IOCTL_CDIOCSTART = CDIOCSTART; -unsigned IOCTL_CDIOCSTOP = CDIOCSTOP; -unsigned IOCTL_CDIOCEJECT = CDIOCEJECT; -unsigned IOCTL_CDIOCALLOW = CDIOCALLOW; -unsigned IOCTL_CDIOCPREVENT = CDIOCPREVENT; -unsigned IOCTL_CDIOCCLOSE = CDIOCCLOSE; -unsigned IOCTL_CDIOCPLAYMSF = CDIOCPLAYMSF; -unsigned IOCTL_CDIOCLOADUNLOAD = CDIOCLOADUNLOAD; -unsigned IOCTL_CHIOMOVE = CHIOMOVE; -unsigned IOCTL_CHIOEXCHANGE = CHIOEXCHANGE; -unsigned IOCTL_CHIOPOSITION = CHIOPOSITION; -unsigned IOCTL_CHIOGPICKER = CHIOGPICKER; -unsigned IOCTL_CHIOSPICKER = CHIOSPICKER; -unsigned IOCTL_CHIOGPARAMS = CHIOGPARAMS; -unsigned IOCTL_CHIOIELEM = CHIOIELEM; -unsigned IOCTL_OCHIOGSTATUS = OCHIOGSTATUS; -unsigned IOCTL_CHIOGSTATUS = CHIOGSTATUS; -unsigned IOCTL_CHIOSVOLTAG = CHIOSVOLTAG; -unsigned IOCTL_CLOCKCTL_SETTIMEOFDAY = CLOCKCTL_SETTIMEOFDAY; -unsigned IOCTL_CLOCKCTL_ADJTIME = CLOCKCTL_ADJTIME; -unsigned IOCTL_CLOCKCTL_CLOCK_SETTIME = CLOCKCTL_CLOCK_SETTIME; -unsigned IOCTL_CLOCKCTL_NTP_ADJTIME = CLOCKCTL_NTP_ADJTIME; -unsigned IOCTL_IOC_CPU_SETSTATE = IOC_CPU_SETSTATE; -unsigned IOCTL_IOC_CPU_GETSTATE = IOC_CPU_GETSTATE; -unsigned IOCTL_IOC_CPU_GETCOUNT = IOC_CPU_GETCOUNT; -unsigned IOCTL_IOC_CPU_MAPID = IOC_CPU_MAPID; -unsigned IOCTL_IOC_CPU_UCODE_GET_VERSION = IOC_CPU_UCODE_GET_VERSION; -unsigned IOCTL_IOC_CPU_UCODE_APPLY = IOC_CPU_UCODE_APPLY; -unsigned IOCTL_DIOCGDINFO = DIOCGDINFO; -unsigned IOCTL_DIOCSDINFO = DIOCSDINFO; -unsigned IOCTL_DIOCWDINFO = DIOCWDINFO; -unsigned IOCTL_DIOCRFORMAT = DIOCRFORMAT; -unsigned IOCTL_DIOCWFORMAT = DIOCWFORMAT; -unsigned IOCTL_DIOCSSTEP = DIOCSSTEP; -unsigned IOCTL_DIOCSRETRIES = DIOCSRETRIES; -unsigned IOCTL_DIOCKLABEL = DIOCKLABEL; -unsigned IOCTL_DIOCWLABEL = DIOCWLABEL; -unsigned IOCTL_DIOCSBAD = DIOCSBAD; -unsigned IOCTL_DIOCEJECT = DIOCEJECT; -unsigned IOCTL_ODIOCEJECT = ODIOCEJECT; -unsigned IOCTL_DIOCLOCK = DIOCLOCK; -unsigned IOCTL_DIOCGDEFLABEL = DIOCGDEFLABEL; -unsigned IOCTL_DIOCCLRLABEL = DIOCCLRLABEL; -unsigned IOCTL_DIOCGCACHE = DIOCGCACHE; -unsigned IOCTL_DIOCSCACHE = DIOCSCACHE; -unsigned IOCTL_DIOCCACHESYNC = DIOCCACHESYNC; -unsigned IOCTL_DIOCBSLIST = DIOCBSLIST; -unsigned IOCTL_DIOCBSFLUSH = DIOCBSFLUSH; -unsigned IOCTL_DIOCAWEDGE = DIOCAWEDGE; -unsigned IOCTL_DIOCGWEDGEINFO = DIOCGWEDGEINFO; -unsigned IOCTL_DIOCDWEDGE = DIOCDWEDGE; -unsigned IOCTL_DIOCLWEDGES = DIOCLWEDGES; -unsigned IOCTL_DIOCGSTRATEGY = DIOCGSTRATEGY; -unsigned IOCTL_DIOCSSTRATEGY = DIOCSSTRATEGY; -unsigned IOCTL_DIOCGDISKINFO = DIOCGDISKINFO; -unsigned IOCTL_DIOCTUR = DIOCTUR; -unsigned IOCTL_DIOCMWEDGES = DIOCMWEDGES; -unsigned IOCTL_DIOCGSECTORSIZE = DIOCGSECTORSIZE; -unsigned IOCTL_DIOCGMEDIASIZE = DIOCGMEDIASIZE; -unsigned IOCTL_DRVDETACHDEV = DRVDETACHDEV; -unsigned IOCTL_DRVRESCANBUS = DRVRESCANBUS; -unsigned IOCTL_DRVCTLCOMMAND = DRVCTLCOMMAND; -unsigned IOCTL_DRVRESUMEDEV = DRVRESUMEDEV; -unsigned IOCTL_DRVLISTDEV = DRVLISTDEV; -unsigned IOCTL_DRVGETEVENT = DRVGETEVENT; -unsigned IOCTL_DRVSUSPENDDEV = DRVSUSPENDDEV; -unsigned IOCTL_DVD_READ_STRUCT = DVD_READ_STRUCT; -unsigned IOCTL_DVD_WRITE_STRUCT = DVD_WRITE_STRUCT; -unsigned IOCTL_DVD_AUTH = DVD_AUTH; -unsigned IOCTL_ENVSYS_GETDICTIONARY = ENVSYS_GETDICTIONARY; -unsigned IOCTL_ENVSYS_SETDICTIONARY = ENVSYS_SETDICTIONARY; -unsigned IOCTL_ENVSYS_REMOVEPROPS = ENVSYS_REMOVEPROPS; -unsigned IOCTL_ENVSYS_GTREDATA = ENVSYS_GTREDATA; -unsigned IOCTL_ENVSYS_GTREINFO = ENVSYS_GTREINFO; -unsigned IOCTL_KFILTER_BYFILTER = KFILTER_BYFILTER; -unsigned IOCTL_KFILTER_BYNAME = KFILTER_BYNAME; -unsigned IOCTL_FDIOCGETOPTS = FDIOCGETOPTS; -unsigned IOCTL_FDIOCSETOPTS = FDIOCSETOPTS; -unsigned IOCTL_FDIOCSETFORMAT = FDIOCSETFORMAT; -unsigned IOCTL_FDIOCGETFORMAT = FDIOCGETFORMAT; -unsigned IOCTL_FDIOCFORMAT_TRACK = FDIOCFORMAT_TRACK; -unsigned IOCTL_FIOCLEX = FIOCLEX; -unsigned IOCTL_FIONCLEX = FIONCLEX; -unsigned IOCTL_FIOSEEKDATA = FIOSEEKDATA; -unsigned IOCTL_FIOSEEKHOLE = FIOSEEKHOLE; -unsigned IOCTL_FIONREAD = FIONREAD; -unsigned IOCTL_FIONBIO = FIONBIO; -unsigned IOCTL_FIOASYNC = FIOASYNC; -unsigned IOCTL_FIOSETOWN = FIOSETOWN; -unsigned IOCTL_FIOGETOWN = FIOGETOWN; -unsigned IOCTL_OFIOGETBMAP = OFIOGETBMAP; -unsigned IOCTL_FIOGETBMAP = FIOGETBMAP; -unsigned IOCTL_FIONWRITE = FIONWRITE; -unsigned IOCTL_FIONSPACE = FIONSPACE; -unsigned IOCTL_GPIOINFO = GPIOINFO; -unsigned IOCTL_GPIOSET = GPIOSET; -unsigned IOCTL_GPIOUNSET = GPIOUNSET; -unsigned IOCTL_GPIOREAD = GPIOREAD; -unsigned IOCTL_GPIOWRITE = GPIOWRITE; -unsigned IOCTL_GPIOTOGGLE = GPIOTOGGLE; -unsigned IOCTL_GPIOATTACH = GPIOATTACH; -unsigned IOCTL_PTIOCNETBSD = PTIOCNETBSD; -unsigned IOCTL_PTIOCSUNOS = PTIOCSUNOS; -unsigned IOCTL_PTIOCLINUX = PTIOCLINUX; -unsigned IOCTL_PTIOCFREEBSD = PTIOCFREEBSD; -unsigned IOCTL_PTIOCULTRIX = PTIOCULTRIX; -unsigned IOCTL_TIOCHPCL = TIOCHPCL; -unsigned IOCTL_TIOCGETP = TIOCGETP; -unsigned IOCTL_TIOCSETP = TIOCSETP; -unsigned IOCTL_TIOCSETN = TIOCSETN; -unsigned IOCTL_TIOCSETC = TIOCSETC; -unsigned IOCTL_TIOCGETC = TIOCGETC; -unsigned IOCTL_TIOCLBIS = TIOCLBIS; -unsigned IOCTL_TIOCLBIC = TIOCLBIC; -unsigned IOCTL_TIOCLSET = TIOCLSET; -unsigned IOCTL_TIOCLGET = TIOCLGET; -unsigned IOCTL_TIOCSLTC = TIOCSLTC; -unsigned IOCTL_TIOCGLTC = TIOCGLTC; -unsigned IOCTL_OTIOCCONS = OTIOCCONS; -unsigned IOCTL_JOY_SETTIMEOUT = JOY_SETTIMEOUT; -unsigned IOCTL_JOY_GETTIMEOUT = JOY_GETTIMEOUT; -unsigned IOCTL_JOY_SET_X_OFFSET = JOY_SET_X_OFFSET; -unsigned IOCTL_JOY_SET_Y_OFFSET = JOY_SET_Y_OFFSET; -unsigned IOCTL_JOY_GET_X_OFFSET = JOY_GET_X_OFFSET; -unsigned IOCTL_JOY_GET_Y_OFFSET = JOY_GET_Y_OFFSET; -unsigned IOCTL_OKIOCGSYMBOL = OKIOCGSYMBOL; -unsigned IOCTL_OKIOCGVALUE = OKIOCGVALUE; -unsigned IOCTL_KIOCGSIZE = KIOCGSIZE; -unsigned IOCTL_KIOCGVALUE = KIOCGVALUE; -unsigned IOCTL_KIOCGSYMBOL = KIOCGSYMBOL; -unsigned IOCTL_LUAINFO = LUAINFO; -unsigned IOCTL_LUACREATE = LUACREATE; -unsigned IOCTL_LUADESTROY = LUADESTROY; -unsigned IOCTL_LUAREQUIRE = LUAREQUIRE; -unsigned IOCTL_LUALOAD = LUALOAD; -unsigned IOCTL_MIDI_PRETIME = MIDI_PRETIME; -unsigned IOCTL_MIDI_MPUMODE = MIDI_MPUMODE; -unsigned IOCTL_MIDI_MPUCMD = MIDI_MPUCMD; -unsigned IOCTL_SEQUENCER_RESET = SEQUENCER_RESET; -unsigned IOCTL_SEQUENCER_SYNC = SEQUENCER_SYNC; -unsigned IOCTL_SEQUENCER_INFO = SEQUENCER_INFO; -unsigned IOCTL_SEQUENCER_CTRLRATE = SEQUENCER_CTRLRATE; -unsigned IOCTL_SEQUENCER_GETOUTCOUNT = SEQUENCER_GETOUTCOUNT; -unsigned IOCTL_SEQUENCER_GETINCOUNT = SEQUENCER_GETINCOUNT; -unsigned IOCTL_SEQUENCER_RESETSAMPLES = SEQUENCER_RESETSAMPLES; -unsigned IOCTL_SEQUENCER_NRSYNTHS = SEQUENCER_NRSYNTHS; -unsigned IOCTL_SEQUENCER_NRMIDIS = SEQUENCER_NRMIDIS; -unsigned IOCTL_SEQUENCER_THRESHOLD = SEQUENCER_THRESHOLD; -unsigned IOCTL_SEQUENCER_MEMAVL = SEQUENCER_MEMAVL; -unsigned IOCTL_SEQUENCER_PANIC = SEQUENCER_PANIC; -unsigned IOCTL_SEQUENCER_OUTOFBAND = SEQUENCER_OUTOFBAND; -unsigned IOCTL_SEQUENCER_GETTIME = SEQUENCER_GETTIME; -unsigned IOCTL_SEQUENCER_TMR_TIMEBASE = SEQUENCER_TMR_TIMEBASE; -unsigned IOCTL_SEQUENCER_TMR_START = SEQUENCER_TMR_START; -unsigned IOCTL_SEQUENCER_TMR_STOP = SEQUENCER_TMR_STOP; -unsigned IOCTL_SEQUENCER_TMR_CONTINUE = SEQUENCER_TMR_CONTINUE; -unsigned IOCTL_SEQUENCER_TMR_TEMPO = SEQUENCER_TMR_TEMPO; -unsigned IOCTL_SEQUENCER_TMR_SOURCE = SEQUENCER_TMR_SOURCE; -unsigned IOCTL_SEQUENCER_TMR_METRONOME = SEQUENCER_TMR_METRONOME; -unsigned IOCTL_SEQUENCER_TMR_SELECT = SEQUENCER_TMR_SELECT; -unsigned IOCTL_MTIOCTOP = MTIOCTOP; -unsigned IOCTL_MTIOCGET = MTIOCGET; -unsigned IOCTL_MTIOCIEOT = MTIOCIEOT; -unsigned IOCTL_MTIOCEEOT = MTIOCEEOT; -unsigned IOCTL_MTIOCRDSPOS = MTIOCRDSPOS; -unsigned IOCTL_MTIOCRDHPOS = MTIOCRDHPOS; -unsigned IOCTL_MTIOCSLOCATE = MTIOCSLOCATE; -unsigned IOCTL_MTIOCHLOCATE = MTIOCHLOCATE; -unsigned IOCTL_POWER_EVENT_RECVDICT = POWER_EVENT_RECVDICT; -unsigned IOCTL_POWER_IOC_GET_TYPE = POWER_IOC_GET_TYPE; -unsigned IOCTL_RIOCGINFO = RIOCGINFO; -unsigned IOCTL_RIOCSINFO = RIOCSINFO; -unsigned IOCTL_RIOCSSRCH = RIOCSSRCH; -unsigned IOCTL_RNDGETENTCNT = RNDGETENTCNT; -unsigned IOCTL_RNDGETSRCNUM = RNDGETSRCNUM; -unsigned IOCTL_RNDGETSRCNAME = RNDGETSRCNAME; -unsigned IOCTL_RNDCTL = RNDCTL; -unsigned IOCTL_RNDADDDATA = RNDADDDATA; -unsigned IOCTL_RNDGETPOOLSTAT = RNDGETPOOLSTAT; -unsigned IOCTL_RNDGETESTNUM = RNDGETESTNUM; -unsigned IOCTL_RNDGETESTNAME = RNDGETESTNAME; -unsigned IOCTL_SCIOCGET = SCIOCGET; -unsigned IOCTL_SCIOCSET = SCIOCSET; -unsigned IOCTL_SCIOCRESTART = SCIOCRESTART; -unsigned IOCTL_SCIOC_USE_ADF = SCIOC_USE_ADF; -unsigned IOCTL_SCIOCCOMMAND = SCIOCCOMMAND; -unsigned IOCTL_SCIOCDEBUG = SCIOCDEBUG; -unsigned IOCTL_SCIOCIDENTIFY = SCIOCIDENTIFY; -unsigned IOCTL_OSCIOCIDENTIFY = OSCIOCIDENTIFY; -unsigned IOCTL_SCIOCDECONFIG = SCIOCDECONFIG; -unsigned IOCTL_SCIOCRECONFIG = SCIOCRECONFIG; -unsigned IOCTL_SCIOCRESET = SCIOCRESET; -unsigned IOCTL_SCBUSIOSCAN = SCBUSIOSCAN; -unsigned IOCTL_SCBUSIORESET = SCBUSIORESET; -unsigned IOCTL_SCBUSIODETACH = SCBUSIODETACH; -unsigned IOCTL_SCBUSACCEL = SCBUSACCEL; -unsigned IOCTL_SCBUSIOLLSCAN = SCBUSIOLLSCAN; -unsigned IOCTL_SIOCSHIWAT = SIOCSHIWAT; -unsigned IOCTL_SIOCGHIWAT = SIOCGHIWAT; -unsigned IOCTL_SIOCSLOWAT = SIOCSLOWAT; -unsigned IOCTL_SIOCGLOWAT = SIOCGLOWAT; -unsigned IOCTL_SIOCATMARK = SIOCATMARK; -unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; -unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; -unsigned IOCTL_SIOCPEELOFF = SIOCPEELOFF; -unsigned IOCTL_SIOCADDRT = SIOCADDRT; -unsigned IOCTL_SIOCDELRT = SIOCDELRT; -unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; -unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; -unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; -unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; -unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; -unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; -unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; -unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; -unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; -unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; -unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; -unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; -unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; -unsigned IOCTL_SIOCDIFADDR = SIOCDIFADDR; -unsigned IOCTL_SIOCAIFADDR = SIOCAIFADDR; -unsigned IOCTL_SIOCGIFALIAS = SIOCGIFALIAS; -unsigned IOCTL_SIOCGIFAFLAG_IN = SIOCGIFAFLAG_IN; -unsigned IOCTL_SIOCALIFADDR = SIOCALIFADDR; -unsigned IOCTL_SIOCGLIFADDR = SIOCGLIFADDR; -unsigned IOCTL_SIOCDLIFADDR = SIOCDLIFADDR; -unsigned IOCTL_SIOCSIFADDRPREF = SIOCSIFADDRPREF; -unsigned IOCTL_SIOCGIFADDRPREF = SIOCGIFADDRPREF; -unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; -unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; -unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; -unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; -unsigned IOCTL_SIOCSIFMEDIA = SIOCSIFMEDIA; -unsigned IOCTL_SIOCGIFMEDIA = SIOCGIFMEDIA; -unsigned IOCTL_SIOCSIFGENERIC = SIOCSIFGENERIC; -unsigned IOCTL_SIOCGIFGENERIC = SIOCGIFGENERIC; -unsigned IOCTL_SIOCSIFPHYADDR = SIOCSIFPHYADDR; -unsigned IOCTL_SIOCGIFPSRCADDR = SIOCGIFPSRCADDR; -unsigned IOCTL_SIOCGIFPDSTADDR = SIOCGIFPDSTADDR; -unsigned IOCTL_SIOCDIFPHYADDR = SIOCDIFPHYADDR; -unsigned IOCTL_SIOCSLIFPHYADDR = SIOCSLIFPHYADDR; -unsigned IOCTL_SIOCGLIFPHYADDR = SIOCGLIFPHYADDR; -unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; -unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; -unsigned IOCTL_SIOCSDRVSPEC = SIOCSDRVSPEC; -unsigned IOCTL_SIOCGDRVSPEC = SIOCGDRVSPEC; -unsigned IOCTL_SIOCIFCREATE = SIOCIFCREATE; -unsigned IOCTL_SIOCIFDESTROY = SIOCIFDESTROY; -unsigned IOCTL_SIOCIFGCLONERS = SIOCIFGCLONERS; -unsigned IOCTL_SIOCGIFDLT = SIOCGIFDLT; -unsigned IOCTL_SIOCGIFCAP = SIOCGIFCAP; -unsigned IOCTL_SIOCSIFCAP = SIOCSIFCAP; -unsigned IOCTL_SIOCSVH = SIOCSVH; -unsigned IOCTL_SIOCGVH = SIOCGVH; -unsigned IOCTL_SIOCINITIFADDR = SIOCINITIFADDR; -unsigned IOCTL_SIOCGIFDATA = SIOCGIFDATA; -unsigned IOCTL_SIOCZIFDATA = SIOCZIFDATA; -unsigned IOCTL_SIOCGLINKSTR = SIOCGLINKSTR; -unsigned IOCTL_SIOCSLINKSTR = SIOCSLINKSTR; -unsigned IOCTL_SIOCGETHERCAP = SIOCGETHERCAP; -unsigned IOCTL_SIOCGIFINDEX = SIOCGIFINDEX; -unsigned IOCTL_SIOCSETHERCAP = SIOCSETHERCAP; -unsigned IOCTL_SIOCGUMBINFO = SIOCGUMBINFO; -unsigned IOCTL_SIOCSUMBPARAM = SIOCSUMBPARAM; -unsigned IOCTL_SIOCGUMBPARAM = SIOCGUMBPARAM; -unsigned IOCTL_SIOCSETPFSYNC = SIOCSETPFSYNC; -unsigned IOCTL_SIOCGETPFSYNC = SIOCGETPFSYNC; -unsigned IOCTL_PPS_IOC_CREATE = PPS_IOC_CREATE; -unsigned IOCTL_PPS_IOC_DESTROY = PPS_IOC_DESTROY; -unsigned IOCTL_PPS_IOC_SETPARAMS = PPS_IOC_SETPARAMS; -unsigned IOCTL_PPS_IOC_GETPARAMS = PPS_IOC_GETPARAMS; -unsigned IOCTL_PPS_IOC_GETCAP = PPS_IOC_GETCAP; -unsigned IOCTL_PPS_IOC_FETCH = PPS_IOC_FETCH; -unsigned IOCTL_PPS_IOC_KCBIND = PPS_IOC_KCBIND; -unsigned IOCTL_TIOCEXCL = TIOCEXCL; -unsigned IOCTL_TIOCNXCL = TIOCNXCL; -unsigned IOCTL_TIOCFLUSH = TIOCFLUSH; -unsigned IOCTL_TIOCGETA = TIOCGETA; -unsigned IOCTL_TIOCSETA = TIOCSETA; -unsigned IOCTL_TIOCSETAW = TIOCSETAW; -unsigned IOCTL_TIOCSETAF = TIOCSETAF; -unsigned IOCTL_TIOCGETD = TIOCGETD; -unsigned IOCTL_TIOCSETD = TIOCSETD; -unsigned IOCTL_TIOCGLINED = TIOCGLINED; -unsigned IOCTL_TIOCSLINED = TIOCSLINED; -unsigned IOCTL_TIOCSBRK = TIOCSBRK; -unsigned IOCTL_TIOCCBRK = TIOCCBRK; -unsigned IOCTL_TIOCSDTR = TIOCSDTR; -unsigned IOCTL_TIOCCDTR = TIOCCDTR; -unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; -unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; -unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; -unsigned IOCTL_TIOCSTI = TIOCSTI; -unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; -unsigned IOCTL_TIOCPKT = TIOCPKT; -unsigned IOCTL_TIOCSTOP = TIOCSTOP; -unsigned IOCTL_TIOCSTART = TIOCSTART; -unsigned IOCTL_TIOCMSET = TIOCMSET; -unsigned IOCTL_TIOCMBIS = TIOCMBIS; -unsigned IOCTL_TIOCMBIC = TIOCMBIC; -unsigned IOCTL_TIOCMGET = TIOCMGET; -unsigned IOCTL_TIOCREMOTE = TIOCREMOTE; -unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; -unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; -unsigned IOCTL_TIOCUCNTL = TIOCUCNTL; -unsigned IOCTL_TIOCSTAT = TIOCSTAT; -unsigned IOCTL_TIOCGSID = TIOCGSID; -unsigned IOCTL_TIOCCONS = TIOCCONS; -unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; -unsigned IOCTL_TIOCEXT = TIOCEXT; -unsigned IOCTL_TIOCSIG = TIOCSIG; -unsigned IOCTL_TIOCDRAIN = TIOCDRAIN; -unsigned IOCTL_TIOCGFLAGS = TIOCGFLAGS; -unsigned IOCTL_TIOCSFLAGS = TIOCSFLAGS; -unsigned IOCTL_TIOCDCDTIMESTAMP = TIOCDCDTIMESTAMP; -unsigned IOCTL_TIOCRCVFRAME = TIOCRCVFRAME; -unsigned IOCTL_TIOCXMTFRAME = TIOCXMTFRAME; -unsigned IOCTL_TIOCPTMGET = TIOCPTMGET; -unsigned IOCTL_TIOCGRANTPT = TIOCGRANTPT; -unsigned IOCTL_TIOCPTSNAME = TIOCPTSNAME; -unsigned IOCTL_TIOCSQSIZE = TIOCSQSIZE; -unsigned IOCTL_TIOCGQSIZE = TIOCGQSIZE; -unsigned IOCTL_VERIEXEC_LOAD = VERIEXEC_LOAD; -unsigned IOCTL_VERIEXEC_TABLESIZE = VERIEXEC_TABLESIZE; -unsigned IOCTL_VERIEXEC_DELETE = VERIEXEC_DELETE; -unsigned IOCTL_VERIEXEC_QUERY = VERIEXEC_QUERY; -unsigned IOCTL_VERIEXEC_DUMP = VERIEXEC_DUMP; -unsigned IOCTL_VERIEXEC_FLUSH = VERIEXEC_FLUSH; -unsigned IOCTL_VIDIOC_QUERYCAP = VIDIOC_QUERYCAP; -unsigned IOCTL_VIDIOC_RESERVED = VIDIOC_RESERVED; -unsigned IOCTL_VIDIOC_ENUM_FMT = VIDIOC_ENUM_FMT; -unsigned IOCTL_VIDIOC_G_FMT = VIDIOC_G_FMT; -unsigned IOCTL_VIDIOC_S_FMT = VIDIOC_S_FMT; -unsigned IOCTL_VIDIOC_REQBUFS = VIDIOC_REQBUFS; -unsigned IOCTL_VIDIOC_QUERYBUF = VIDIOC_QUERYBUF; -unsigned IOCTL_VIDIOC_G_FBUF = VIDIOC_G_FBUF; -unsigned IOCTL_VIDIOC_S_FBUF = VIDIOC_S_FBUF; -unsigned IOCTL_VIDIOC_OVERLAY = VIDIOC_OVERLAY; -unsigned IOCTL_VIDIOC_QBUF = VIDIOC_QBUF; -unsigned IOCTL_VIDIOC_DQBUF = VIDIOC_DQBUF; -unsigned IOCTL_VIDIOC_STREAMON = VIDIOC_STREAMON; -unsigned IOCTL_VIDIOC_STREAMOFF = VIDIOC_STREAMOFF; -unsigned IOCTL_VIDIOC_G_PARM = VIDIOC_G_PARM; -unsigned IOCTL_VIDIOC_S_PARM = VIDIOC_S_PARM; -unsigned IOCTL_VIDIOC_G_STD = VIDIOC_G_STD; -unsigned IOCTL_VIDIOC_S_STD = VIDIOC_S_STD; -unsigned IOCTL_VIDIOC_ENUMSTD = VIDIOC_ENUMSTD; -unsigned IOCTL_VIDIOC_ENUMINPUT = VIDIOC_ENUMINPUT; -unsigned IOCTL_VIDIOC_G_CTRL = VIDIOC_G_CTRL; -unsigned IOCTL_VIDIOC_S_CTRL = VIDIOC_S_CTRL; -unsigned IOCTL_VIDIOC_G_TUNER = VIDIOC_G_TUNER; -unsigned IOCTL_VIDIOC_S_TUNER = VIDIOC_S_TUNER; -unsigned IOCTL_VIDIOC_G_AUDIO = VIDIOC_G_AUDIO; -unsigned IOCTL_VIDIOC_S_AUDIO = VIDIOC_S_AUDIO; -unsigned IOCTL_VIDIOC_QUERYCTRL = VIDIOC_QUERYCTRL; -unsigned IOCTL_VIDIOC_QUERYMENU = VIDIOC_QUERYMENU; -unsigned IOCTL_VIDIOC_G_INPUT = VIDIOC_G_INPUT; -unsigned IOCTL_VIDIOC_S_INPUT = VIDIOC_S_INPUT; -unsigned IOCTL_VIDIOC_G_OUTPUT = VIDIOC_G_OUTPUT; -unsigned IOCTL_VIDIOC_S_OUTPUT = VIDIOC_S_OUTPUT; -unsigned IOCTL_VIDIOC_ENUMOUTPUT = VIDIOC_ENUMOUTPUT; -unsigned IOCTL_VIDIOC_G_AUDOUT = VIDIOC_G_AUDOUT; -unsigned IOCTL_VIDIOC_S_AUDOUT = VIDIOC_S_AUDOUT; -unsigned IOCTL_VIDIOC_G_MODULATOR = VIDIOC_G_MODULATOR; -unsigned IOCTL_VIDIOC_S_MODULATOR = VIDIOC_S_MODULATOR; -unsigned IOCTL_VIDIOC_G_FREQUENCY = VIDIOC_G_FREQUENCY; -unsigned IOCTL_VIDIOC_S_FREQUENCY = VIDIOC_S_FREQUENCY; -unsigned IOCTL_VIDIOC_CROPCAP = VIDIOC_CROPCAP; -unsigned IOCTL_VIDIOC_G_CROP = VIDIOC_G_CROP; -unsigned IOCTL_VIDIOC_S_CROP = VIDIOC_S_CROP; -unsigned IOCTL_VIDIOC_G_JPEGCOMP = VIDIOC_G_JPEGCOMP; -unsigned IOCTL_VIDIOC_S_JPEGCOMP = VIDIOC_S_JPEGCOMP; -unsigned IOCTL_VIDIOC_QUERYSTD = VIDIOC_QUERYSTD; -unsigned IOCTL_VIDIOC_TRY_FMT = VIDIOC_TRY_FMT; -unsigned IOCTL_VIDIOC_ENUMAUDIO = VIDIOC_ENUMAUDIO; -unsigned IOCTL_VIDIOC_ENUMAUDOUT = VIDIOC_ENUMAUDOUT; -unsigned IOCTL_VIDIOC_G_PRIORITY = VIDIOC_G_PRIORITY; -unsigned IOCTL_VIDIOC_S_PRIORITY = VIDIOC_S_PRIORITY; -unsigned IOCTL_VIDIOC_ENUM_FRAMESIZES = VIDIOC_ENUM_FRAMESIZES; -unsigned IOCTL_VIDIOC_ENUM_FRAMEINTERVALS = VIDIOC_ENUM_FRAMEINTERVALS; -unsigned IOCTL_WDOGIOC_GMODE = WDOGIOC_GMODE; -unsigned IOCTL_WDOGIOC_SMODE = WDOGIOC_SMODE; -unsigned IOCTL_WDOGIOC_WHICH = WDOGIOC_WHICH; -unsigned IOCTL_WDOGIOC_TICKLE = WDOGIOC_TICKLE; -unsigned IOCTL_WDOGIOC_GTICKLER = WDOGIOC_GTICKLER; -unsigned IOCTL_WDOGIOC_GWDOGS = WDOGIOC_GWDOGS; -unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; -unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; -unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; -unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE; -unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; -unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; -unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; -unsigned IOCTL_SOUND_PCM_READ_BITS = SOUND_PCM_READ_BITS; -unsigned IOCTL_SNDCTL_DSP_CHANNELS = SNDCTL_DSP_CHANNELS; -unsigned IOCTL_SOUND_PCM_READ_CHANNELS = SOUND_PCM_READ_CHANNELS; -unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER; -unsigned IOCTL_SOUND_PCM_READ_FILTER = SOUND_PCM_READ_FILTER; -unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; -unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; -unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; -unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; -unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE; -unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; -unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; -unsigned IOCTL_SNDCTL_DSP_GETCAPS = SNDCTL_DSP_GETCAPS; -unsigned IOCTL_SNDCTL_DSP_GETTRIGGER = SNDCTL_DSP_GETTRIGGER; -unsigned IOCTL_SNDCTL_DSP_SETTRIGGER = SNDCTL_DSP_SETTRIGGER; -unsigned IOCTL_SNDCTL_DSP_GETIPTR = SNDCTL_DSP_GETIPTR; -unsigned IOCTL_SNDCTL_DSP_GETOPTR = SNDCTL_DSP_GETOPTR; -unsigned IOCTL_SNDCTL_DSP_MAPINBUF = SNDCTL_DSP_MAPINBUF; -unsigned IOCTL_SNDCTL_DSP_MAPOUTBUF = SNDCTL_DSP_MAPOUTBUF; -unsigned IOCTL_SNDCTL_DSP_SETSYNCRO = SNDCTL_DSP_SETSYNCRO; -unsigned IOCTL_SNDCTL_DSP_SETDUPLEX = SNDCTL_DSP_SETDUPLEX; -unsigned IOCTL_SNDCTL_DSP_PROFILE = SNDCTL_DSP_PROFILE; -unsigned IOCTL_SNDCTL_DSP_GETODELAY = SNDCTL_DSP_GETODELAY; -unsigned IOCTL_SOUND_MIXER_INFO = SOUND_MIXER_INFO; -unsigned IOCTL_SOUND_OLD_MIXER_INFO = SOUND_OLD_MIXER_INFO; -unsigned IOCTL_OSS_GETVERSION = OSS_GETVERSION; -unsigned IOCTL_SNDCTL_SYSINFO = SNDCTL_SYSINFO; -unsigned IOCTL_SNDCTL_AUDIOINFO = SNDCTL_AUDIOINFO; -unsigned IOCTL_SNDCTL_ENGINEINFO = SNDCTL_ENGINEINFO; -unsigned IOCTL_SNDCTL_DSP_GETPLAYVOL = SNDCTL_DSP_GETPLAYVOL; -unsigned IOCTL_SNDCTL_DSP_SETPLAYVOL = SNDCTL_DSP_SETPLAYVOL; -unsigned IOCTL_SNDCTL_DSP_GETRECVOL = SNDCTL_DSP_GETRECVOL; -unsigned IOCTL_SNDCTL_DSP_SETRECVOL = SNDCTL_DSP_SETRECVOL; -unsigned IOCTL_SNDCTL_DSP_SKIP = SNDCTL_DSP_SKIP; -unsigned IOCTL_SNDCTL_DSP_SILENCE = SNDCTL_DSP_SILENCE; - -const int si_SEGV_MAPERR = SEGV_MAPERR; -const int si_SEGV_ACCERR = SEGV_ACCERR; - -const int modctl_load = MODCTL_LOAD; -const int modctl_unload = MODCTL_UNLOAD; -const int modctl_stat = MODCTL_STAT; -const int modctl_exists = MODCTL_EXISTS; - -const unsigned SHA1_CTX_sz = sizeof(SHA1_CTX); -const unsigned SHA1_return_length = SHA1_DIGEST_STRING_LENGTH; - -const unsigned MD4_CTX_sz = sizeof(MD4_CTX); -const unsigned MD4_return_length = MD4_DIGEST_STRING_LENGTH; - -const unsigned RMD160_CTX_sz = sizeof(RMD160_CTX); -const unsigned RMD160_return_length = RMD160_DIGEST_STRING_LENGTH; - -const unsigned MD5_CTX_sz = sizeof(MD5_CTX); -const unsigned MD5_return_length = MD5_DIGEST_STRING_LENGTH; - -const unsigned fpos_t_sz = sizeof(fpos_t); - -const unsigned MD2_CTX_sz = sizeof(MD2_CTX); -const unsigned MD2_return_length = MD2_DIGEST_STRING_LENGTH; - -#define SHA2_CONST(LEN) \ - const unsigned SHA##LEN##_CTX_sz = sizeof(SHA##LEN##_CTX); \ - const unsigned SHA##LEN##_return_length = SHA##LEN##_DIGEST_STRING_LENGTH; \ - const unsigned SHA##LEN##_block_length = SHA##LEN##_BLOCK_LENGTH; \ - const unsigned SHA##LEN##_digest_length = SHA##LEN##_DIGEST_LENGTH - -SHA2_CONST(224); -SHA2_CONST(256); -SHA2_CONST(384); -SHA2_CONST(512); - -#undef SHA2_CONST - -const int unvis_valid = UNVIS_VALID; -const int unvis_validpush = UNVIS_VALIDPUSH; -} // namespace __sanitizer - -using namespace __sanitizer; - -COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); - -COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); -CHECK_TYPE_SIZE(pthread_key_t); - -// There are more undocumented fields in dl_phdr_info that we are not interested -// in. -COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); - -CHECK_TYPE_SIZE(glob_t); -CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); -CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); -CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); -CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); -CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); -CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); -CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); -CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); -CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); - -CHECK_TYPE_SIZE(addrinfo); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); - -CHECK_TYPE_SIZE(hostent); -CHECK_SIZE_AND_OFFSET(hostent, h_name); -CHECK_SIZE_AND_OFFSET(hostent, h_aliases); -CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); -CHECK_SIZE_AND_OFFSET(hostent, h_length); -CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); - -CHECK_TYPE_SIZE(iovec); -CHECK_SIZE_AND_OFFSET(iovec, iov_base); -CHECK_SIZE_AND_OFFSET(iovec, iov_len); - -CHECK_TYPE_SIZE(msghdr); -CHECK_SIZE_AND_OFFSET(msghdr, msg_name); -CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); -CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_control); -CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); - -CHECK_TYPE_SIZE(cmsghdr); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); - -COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); -CHECK_SIZE_AND_OFFSET(dirent, d_fileno); -CHECK_SIZE_AND_OFFSET(dirent, d_reclen); - -CHECK_TYPE_SIZE(ifconf); -CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); -CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); - -CHECK_TYPE_SIZE(pollfd); -CHECK_SIZE_AND_OFFSET(pollfd, fd); -CHECK_SIZE_AND_OFFSET(pollfd, events); -CHECK_SIZE_AND_OFFSET(pollfd, revents); - -CHECK_TYPE_SIZE(nfds_t); - -CHECK_TYPE_SIZE(sigset_t); - -COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); -// Can't write checks for sa_handler and sa_sigaction due to them being -// preprocessor macros. -CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); - -CHECK_TYPE_SIZE(wordexp_t); -CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); -CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); -CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); - -COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE)); -CHECK_SIZE_AND_OFFSET(FILE, _p); -CHECK_SIZE_AND_OFFSET(FILE, _r); -CHECK_SIZE_AND_OFFSET(FILE, _w); -CHECK_SIZE_AND_OFFSET(FILE, _flags); -CHECK_SIZE_AND_OFFSET(FILE, _file); -CHECK_SIZE_AND_OFFSET(FILE, _bf); -CHECK_SIZE_AND_OFFSET(FILE, _lbfsize); -CHECK_SIZE_AND_OFFSET(FILE, _cookie); -CHECK_SIZE_AND_OFFSET(FILE, _close); -CHECK_SIZE_AND_OFFSET(FILE, _read); -CHECK_SIZE_AND_OFFSET(FILE, _seek); -CHECK_SIZE_AND_OFFSET(FILE, _write); -CHECK_SIZE_AND_OFFSET(FILE, _ext); -CHECK_SIZE_AND_OFFSET(FILE, _up); -CHECK_SIZE_AND_OFFSET(FILE, _ur); -CHECK_SIZE_AND_OFFSET(FILE, _ubuf); -CHECK_SIZE_AND_OFFSET(FILE, _nbuf); -CHECK_SIZE_AND_OFFSET(FILE, _flush); -CHECK_SIZE_AND_OFFSET(FILE, _lb_unused); -CHECK_SIZE_AND_OFFSET(FILE, _blksize); -CHECK_SIZE_AND_OFFSET(FILE, _offset); - -CHECK_TYPE_SIZE(tm); -CHECK_SIZE_AND_OFFSET(tm, tm_sec); -CHECK_SIZE_AND_OFFSET(tm, tm_min); -CHECK_SIZE_AND_OFFSET(tm, tm_hour); -CHECK_SIZE_AND_OFFSET(tm, tm_mday); -CHECK_SIZE_AND_OFFSET(tm, tm_mon); -CHECK_SIZE_AND_OFFSET(tm, tm_year); -CHECK_SIZE_AND_OFFSET(tm, tm_wday); -CHECK_SIZE_AND_OFFSET(tm, tm_yday); -CHECK_SIZE_AND_OFFSET(tm, tm_isdst); -CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); -CHECK_SIZE_AND_OFFSET(tm, tm_zone); - -CHECK_TYPE_SIZE(ether_addr); - -CHECK_TYPE_SIZE(ipc_perm); -CHECK_SIZE_AND_OFFSET(ipc_perm, _key); -CHECK_SIZE_AND_OFFSET(ipc_perm, _seq); -CHECK_SIZE_AND_OFFSET(ipc_perm, uid); -CHECK_SIZE_AND_OFFSET(ipc_perm, gid); -CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); -CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); -CHECK_SIZE_AND_OFFSET(ipc_perm, mode); - -CHECK_TYPE_SIZE(shmid_ds); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); - -CHECK_TYPE_SIZE(clock_t); - -CHECK_TYPE_SIZE(ifaddrs); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); -// Compare against the union, because we can't reach into the union in a -// compliant way. -#ifdef ifa_dstaddr -#undef ifa_dstaddr -#endif -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); - -CHECK_TYPE_SIZE(timeb); -CHECK_SIZE_AND_OFFSET(timeb, time); -CHECK_SIZE_AND_OFFSET(timeb, millitm); -CHECK_SIZE_AND_OFFSET(timeb, timezone); -CHECK_SIZE_AND_OFFSET(timeb, dstflag); - -CHECK_TYPE_SIZE(passwd); -CHECK_SIZE_AND_OFFSET(passwd, pw_name); -CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); -CHECK_SIZE_AND_OFFSET(passwd, pw_uid); -CHECK_SIZE_AND_OFFSET(passwd, pw_gid); -CHECK_SIZE_AND_OFFSET(passwd, pw_dir); -CHECK_SIZE_AND_OFFSET(passwd, pw_shell); - -CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); - -CHECK_TYPE_SIZE(group); -CHECK_SIZE_AND_OFFSET(group, gr_name); -CHECK_SIZE_AND_OFFSET(group, gr_passwd); -CHECK_SIZE_AND_OFFSET(group, gr_gid); -CHECK_SIZE_AND_OFFSET(group, gr_mem); - -CHECK_TYPE_SIZE(modctl_load_t); -CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_filename); -CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_flags); -CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_props); -CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_propslen); - -#endif // SANITIZER_NETBSD diff --git a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cpp b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cpp new file mode 100644 index 000000000000..f01de6c995e6 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cpp @@ -0,0 +1,2395 @@ +//===-- sanitizer_platform_limits_netbsd.cpp ------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific NetBSD data structures. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_NETBSD + +#define _KMEMUSER +#define RAY_DO_SIGLEV + +// clang-format off +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__x86_64__) +#include +#endif +// clang-format on + +// Include these after system headers to avoid name clashes and ambiguities. +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform_limits_netbsd.h" + +namespace __sanitizer { +unsigned struct_utsname_sz = sizeof(struct utsname); +unsigned struct_stat_sz = sizeof(struct stat); +unsigned struct_rusage_sz = sizeof(struct rusage); +unsigned struct_tm_sz = sizeof(struct tm); +unsigned struct_passwd_sz = sizeof(struct passwd); +unsigned struct_group_sz = sizeof(struct group); +unsigned siginfo_t_sz = sizeof(siginfo_t); +unsigned struct_sigaction_sz = sizeof(struct sigaction); +unsigned struct_itimerval_sz = sizeof(struct itimerval); +unsigned pthread_t_sz = sizeof(pthread_t); +unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); +unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); +unsigned pid_t_sz = sizeof(pid_t); +unsigned timeval_sz = sizeof(timeval); +unsigned uid_t_sz = sizeof(uid_t); +unsigned gid_t_sz = sizeof(gid_t); +unsigned mbstate_t_sz = sizeof(mbstate_t); +unsigned sigset_t_sz = sizeof(sigset_t); +unsigned struct_timezone_sz = sizeof(struct timezone); +unsigned struct_tms_sz = sizeof(struct tms); +unsigned struct_sigevent_sz = sizeof(struct sigevent); +unsigned struct_sched_param_sz = sizeof(struct sched_param); +unsigned struct_sockaddr_sz = sizeof(struct sockaddr); +unsigned ucontext_t_sz = sizeof(ucontext_t); +unsigned struct_rlimit_sz = sizeof(struct rlimit); +unsigned struct_timespec_sz = sizeof(struct timespec); +unsigned struct_sembuf_sz = sizeof(struct sembuf); +unsigned struct_kevent_sz = sizeof(struct kevent); +unsigned struct_FTS_sz = sizeof(FTS); +unsigned struct_FTSENT_sz = sizeof(FTSENT); +unsigned struct_regex_sz = sizeof(regex_t); +unsigned struct_regmatch_sz = sizeof(regmatch_t); +unsigned struct_fstab_sz = sizeof(struct fstab); +unsigned struct_utimbuf_sz = sizeof(struct utimbuf); +unsigned struct_itimerspec_sz = sizeof(struct itimerspec); +unsigned struct_timex_sz = sizeof(struct timex); +unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); +unsigned struct_mq_attr_sz = sizeof(struct mq_attr); +unsigned struct_statvfs_sz = sizeof(struct statvfs); +unsigned struct_sigaltstack_sz = sizeof(stack_t); + +const uptr sig_ign = (uptr)SIG_IGN; +const uptr sig_dfl = (uptr)SIG_DFL; +const uptr sig_err = (uptr)SIG_ERR; +const uptr sa_siginfo = (uptr)SA_SIGINFO; + +const unsigned long __sanitizer_bufsiz = BUFSIZ; + +int ptrace_pt_io = PT_IO; +int ptrace_pt_lwpinfo = PT_LWPINFO; +int ptrace_pt_set_event_mask = PT_SET_EVENT_MASK; +int ptrace_pt_get_event_mask = PT_GET_EVENT_MASK; +int ptrace_pt_get_process_state = PT_GET_PROCESS_STATE; +int ptrace_pt_set_siginfo = PT_SET_SIGINFO; +int ptrace_pt_get_siginfo = PT_GET_SIGINFO; +int ptrace_piod_read_d = PIOD_READ_D; +int ptrace_piod_write_d = PIOD_WRITE_D; +int ptrace_piod_read_i = PIOD_READ_I; +int ptrace_piod_write_i = PIOD_WRITE_I; +int ptrace_piod_read_auxv = PIOD_READ_AUXV; + +#if defined(PT_SETREGS) && defined(PT_GETREGS) +int ptrace_pt_setregs = PT_SETREGS; +int ptrace_pt_getregs = PT_GETREGS; +#else +int ptrace_pt_setregs = -1; +int ptrace_pt_getregs = -1; +#endif + +#if defined(PT_SETFPREGS) && defined(PT_GETFPREGS) +int ptrace_pt_setfpregs = PT_SETFPREGS; +int ptrace_pt_getfpregs = PT_GETFPREGS; +#else +int ptrace_pt_setfpregs = -1; +int ptrace_pt_getfpregs = -1; +#endif + +#if defined(PT_SETDBREGS) && defined(PT_GETDBREGS) +int ptrace_pt_setdbregs = PT_SETDBREGS; +int ptrace_pt_getdbregs = PT_GETDBREGS; +#else +int ptrace_pt_setdbregs = -1; +int ptrace_pt_getdbregs = -1; +#endif + +unsigned struct_ptrace_ptrace_io_desc_struct_sz = sizeof(struct ptrace_io_desc); +unsigned struct_ptrace_ptrace_lwpinfo_struct_sz = sizeof(struct ptrace_lwpinfo); +unsigned struct_ptrace_ptrace_event_struct_sz = sizeof(ptrace_event_t); +unsigned struct_ptrace_ptrace_siginfo_struct_sz = sizeof(ptrace_siginfo_t); + +#if defined(PT_SETREGS) +unsigned struct_ptrace_reg_struct_sz = sizeof(struct reg); +#else +unsigned struct_ptrace_reg_struct_sz = -1; +#endif + +#if defined(PT_SETFPREGS) +unsigned struct_ptrace_fpreg_struct_sz = sizeof(struct fpreg); +#else +unsigned struct_ptrace_fpreg_struct_sz = -1; +#endif + +#if defined(PT_SETDBREGS) +unsigned struct_ptrace_dbreg_struct_sz = sizeof(struct dbreg); +#else +unsigned struct_ptrace_dbreg_struct_sz = -1; +#endif + +int shmctl_ipc_stat = (int)IPC_STAT; + +unsigned struct_utmp_sz = sizeof(struct utmp); +unsigned struct_utmpx_sz = sizeof(struct utmpx); + +int map_fixed = MAP_FIXED; + +int af_inet = (int)AF_INET; +int af_inet6 = (int)AF_INET6; + +uptr __sanitizer_in_addr_sz(int af) { + if (af == AF_INET) + return sizeof(struct in_addr); + else if (af == AF_INET6) + return sizeof(struct in6_addr); + else + return 0; +} + +unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); + +int glob_nomatch = GLOB_NOMATCH; +int glob_altdirfunc = GLOB_ALTDIRFUNC; + +unsigned path_max = PATH_MAX; + +int struct_ttyent_sz = sizeof(struct ttyent); + +struct __sanitizer_nvlist_ref_t { + void *buf; + uptr len; + int flags; +}; + +typedef __sanitizer_nvlist_ref_t nvlist_ref_t; + +// ioctl arguments +unsigned struct_altqreq_sz = sizeof(altqreq); +unsigned struct_amr_user_ioctl_sz = sizeof(amr_user_ioctl); +unsigned struct_ap_control_sz = sizeof(ap_control); +unsigned struct_apm_ctl_sz = sizeof(apm_ctl); +unsigned struct_apm_event_info_sz = sizeof(apm_event_info); +unsigned struct_apm_power_info_sz = sizeof(apm_power_info); +unsigned struct_atabusiodetach_args_sz = sizeof(atabusiodetach_args); +unsigned struct_atabusioscan_args_sz = sizeof(atabusioscan_args); +unsigned struct_ath_diag_sz = sizeof(ath_diag); +unsigned struct_atm_flowmap_sz = sizeof(atm_flowmap); +unsigned struct_audio_buf_info_sz = sizeof(audio_buf_info); +unsigned struct_audio_device_sz = sizeof(audio_device); +unsigned struct_audio_encoding_sz = sizeof(audio_encoding); +unsigned struct_audio_info_sz = sizeof(audio_info); +unsigned struct_audio_offset_sz = sizeof(audio_offset); +unsigned struct_bio_locate_sz = sizeof(bio_locate); +unsigned struct_bioc_alarm_sz = sizeof(bioc_alarm); +unsigned struct_bioc_blink_sz = sizeof(bioc_blink); +unsigned struct_bioc_disk_sz = sizeof(bioc_disk); +unsigned struct_bioc_inq_sz = sizeof(bioc_inq); +unsigned struct_bioc_setstate_sz = sizeof(bioc_setstate); +unsigned struct_bioc_vol_sz = sizeof(bioc_vol); +unsigned struct_bioc_volops_sz = sizeof(bioc_volops); +unsigned struct_bktr_chnlset_sz = sizeof(bktr_chnlset); +unsigned struct_bktr_remote_sz = sizeof(bktr_remote); +unsigned struct_blue_conf_sz = sizeof(blue_conf); +unsigned struct_blue_interface_sz = sizeof(blue_interface); +unsigned struct_blue_stats_sz = sizeof(blue_stats); +unsigned struct_bpf_dltlist_sz = sizeof(bpf_dltlist); +unsigned struct_bpf_program_sz = sizeof(bpf_program); +unsigned struct_bpf_stat_old_sz = sizeof(bpf_stat_old); +unsigned struct_bpf_stat_sz = sizeof(bpf_stat); +unsigned struct_bpf_version_sz = sizeof(bpf_version); +unsigned struct_btreq_sz = sizeof(btreq); +unsigned struct_btsco_info_sz = sizeof(btsco_info); +unsigned struct_buffmem_desc_sz = sizeof(buffmem_desc); +unsigned struct_cbq_add_class_sz = sizeof(cbq_add_class); +unsigned struct_cbq_add_filter_sz = sizeof(cbq_add_filter); +unsigned struct_cbq_delete_class_sz = sizeof(cbq_delete_class); +unsigned struct_cbq_delete_filter_sz = sizeof(cbq_delete_filter); +unsigned struct_cbq_getstats_sz = sizeof(cbq_getstats); +unsigned struct_cbq_interface_sz = sizeof(cbq_interface); +unsigned struct_cbq_modify_class_sz = sizeof(cbq_modify_class); +unsigned struct_ccd_ioctl_sz = sizeof(ccd_ioctl); +unsigned struct_cdnr_add_element_sz = sizeof(cdnr_add_element); +unsigned struct_cdnr_add_filter_sz = sizeof(cdnr_add_filter); +unsigned struct_cdnr_add_tbmeter_sz = sizeof(cdnr_add_tbmeter); +unsigned struct_cdnr_add_trtcm_sz = sizeof(cdnr_add_trtcm); +unsigned struct_cdnr_add_tswtcm_sz = sizeof(cdnr_add_tswtcm); +unsigned struct_cdnr_delete_element_sz = sizeof(cdnr_delete_element); +unsigned struct_cdnr_delete_filter_sz = sizeof(cdnr_delete_filter); +unsigned struct_cdnr_get_stats_sz = sizeof(cdnr_get_stats); +unsigned struct_cdnr_interface_sz = sizeof(cdnr_interface); +unsigned struct_cdnr_modify_tbmeter_sz = sizeof(cdnr_modify_tbmeter); +unsigned struct_cdnr_modify_trtcm_sz = sizeof(cdnr_modify_trtcm); +unsigned struct_cdnr_modify_tswtcm_sz = sizeof(cdnr_modify_tswtcm); +unsigned struct_cdnr_tbmeter_stats_sz = sizeof(cdnr_tbmeter_stats); +unsigned struct_cdnr_tcm_stats_sz = sizeof(cdnr_tcm_stats); +unsigned struct_cgd_ioctl_sz = sizeof(cgd_ioctl); +unsigned struct_cgd_user_sz = sizeof(cgd_user); +unsigned struct_changer_element_status_request_sz = + sizeof(changer_element_status_request); +unsigned struct_changer_exchange_request_sz = sizeof(changer_exchange_request); +unsigned struct_changer_move_request_sz = sizeof(changer_move_request); +unsigned struct_changer_params_sz = sizeof(changer_params); +unsigned struct_changer_position_request_sz = sizeof(changer_position_request); +unsigned struct_changer_set_voltag_request_sz = + sizeof(changer_set_voltag_request); +unsigned struct_clockctl_adjtime_sz = sizeof(clockctl_adjtime); +unsigned struct_clockctl_clock_settime_sz = sizeof(clockctl_clock_settime); +unsigned struct_clockctl_ntp_adjtime_sz = sizeof(clockctl_ntp_adjtime); +unsigned struct_clockctl_settimeofday_sz = sizeof(clockctl_settimeofday); +unsigned struct_cnwistats_sz = sizeof(cnwistats); +unsigned struct_cnwitrail_sz = sizeof(cnwitrail); +unsigned struct_cnwstatus_sz = sizeof(cnwstatus); +unsigned struct_count_info_sz = sizeof(count_info); +unsigned struct_cpu_ucode_sz = sizeof(cpu_ucode); +unsigned struct_cpu_ucode_version_sz = sizeof(cpu_ucode_version); +unsigned struct_crypt_kop_sz = sizeof(crypt_kop); +unsigned struct_crypt_mkop_sz = sizeof(crypt_mkop); +unsigned struct_crypt_mop_sz = sizeof(crypt_mop); +unsigned struct_crypt_op_sz = sizeof(crypt_op); +unsigned struct_crypt_result_sz = sizeof(crypt_result); +unsigned struct_crypt_sfop_sz = sizeof(crypt_sfop); +unsigned struct_crypt_sgop_sz = sizeof(crypt_sgop); +unsigned struct_cryptret_sz = sizeof(cryptret); +unsigned struct_devdetachargs_sz = sizeof(devdetachargs); +unsigned struct_devlistargs_sz = sizeof(devlistargs); +unsigned struct_devpmargs_sz = sizeof(devpmargs); +unsigned struct_devrescanargs_sz = sizeof(devrescanargs); +unsigned struct_disk_badsecinfo_sz = sizeof(disk_badsecinfo); +unsigned struct_disk_strategy_sz = sizeof(disk_strategy); +unsigned struct_disklabel_sz = sizeof(disklabel); +unsigned struct_dkbad_sz = sizeof(dkbad); +unsigned struct_dkwedge_info_sz = sizeof(dkwedge_info); +unsigned struct_dkwedge_list_sz = sizeof(dkwedge_list); +unsigned struct_dmio_setfunc_sz = sizeof(dmio_setfunc); +unsigned struct_dmx_pes_filter_params_sz = sizeof(dmx_pes_filter_params); +unsigned struct_dmx_sct_filter_params_sz = sizeof(dmx_sct_filter_params); +unsigned struct_dmx_stc_sz = sizeof(dmx_stc); +unsigned struct_dvb_diseqc_master_cmd_sz = sizeof(dvb_diseqc_master_cmd); +unsigned struct_dvb_diseqc_slave_reply_sz = sizeof(dvb_diseqc_slave_reply); +unsigned struct_dvb_frontend_event_sz = sizeof(dvb_frontend_event); +unsigned struct_dvb_frontend_info_sz = sizeof(dvb_frontend_info); +unsigned struct_dvb_frontend_parameters_sz = sizeof(dvb_frontend_parameters); +unsigned struct_eccapreq_sz = sizeof(eccapreq); +unsigned struct_fbcmap_sz = sizeof(fbcmap); +unsigned struct_fbcurpos_sz = sizeof(fbcurpos); +unsigned struct_fbcursor_sz = sizeof(fbcursor); +unsigned struct_fbgattr_sz = sizeof(fbgattr); +unsigned struct_fbsattr_sz = sizeof(fbsattr); +unsigned struct_fbtype_sz = sizeof(fbtype); +unsigned struct_fdformat_cmd_sz = sizeof(fdformat_cmd); +unsigned struct_fdformat_parms_sz = sizeof(fdformat_parms); +unsigned struct_fifoq_conf_sz = sizeof(fifoq_conf); +unsigned struct_fifoq_getstats_sz = sizeof(fifoq_getstats); +unsigned struct_fifoq_interface_sz = sizeof(fifoq_interface); +unsigned struct_format_op_sz = sizeof(format_op); +unsigned struct_fss_get_sz = sizeof(fss_get); +unsigned struct_fss_set_sz = sizeof(fss_set); +unsigned struct_gpio_attach_sz = sizeof(gpio_attach); +unsigned struct_gpio_info_sz = sizeof(gpio_info); +unsigned struct_gpio_req_sz = sizeof(gpio_req); +unsigned struct_gpio_set_sz = sizeof(gpio_set); +unsigned struct_hfsc_add_class_sz = sizeof(hfsc_add_class); +unsigned struct_hfsc_add_filter_sz = sizeof(hfsc_add_filter); +unsigned struct_hfsc_attach_sz = sizeof(hfsc_attach); +unsigned struct_hfsc_class_stats_sz = sizeof(hfsc_class_stats); +unsigned struct_hfsc_delete_class_sz = sizeof(hfsc_delete_class); +unsigned struct_hfsc_delete_filter_sz = sizeof(hfsc_delete_filter); +unsigned struct_hfsc_interface_sz = sizeof(hfsc_interface); +unsigned struct_hfsc_modify_class_sz = sizeof(hfsc_modify_class); +unsigned struct_hpcfb_dsp_op_sz = sizeof(hpcfb_dsp_op); +unsigned struct_hpcfb_dspconf_sz = sizeof(hpcfb_dspconf); +unsigned struct_hpcfb_fbconf_sz = sizeof(hpcfb_fbconf); +unsigned struct_if_addrprefreq_sz = sizeof(if_addrprefreq); +unsigned struct_if_clonereq_sz = sizeof(if_clonereq); +unsigned struct_if_laddrreq_sz = sizeof(if_laddrreq); +unsigned struct_ifaddr_sz = sizeof(ifaddr); +unsigned struct_ifaliasreq_sz = sizeof(ifaliasreq); +unsigned struct_ifcapreq_sz = sizeof(ifcapreq); +unsigned struct_ifconf_sz = sizeof(ifconf); +unsigned struct_ifdatareq_sz = sizeof(ifdatareq); +unsigned struct_ifdrv_sz = sizeof(ifdrv); +unsigned struct_ifmediareq_sz = sizeof(ifmediareq); +unsigned struct_ifpppcstatsreq_sz = sizeof(ifpppcstatsreq); +unsigned struct_ifpppstatsreq_sz = sizeof(ifpppstatsreq); +unsigned struct_ifreq_sz = sizeof(ifreq); +unsigned struct_in6_addrpolicy_sz = sizeof(in6_addrpolicy); +unsigned struct_in6_ndireq_sz = sizeof(in6_ndireq); +unsigned struct_ioc_load_unload_sz = sizeof(ioc_load_unload); +unsigned struct_ioc_patch_sz = sizeof(ioc_patch); +unsigned struct_ioc_play_blocks_sz = sizeof(ioc_play_blocks); +unsigned struct_ioc_play_msf_sz = sizeof(ioc_play_msf); +unsigned struct_ioc_play_track_sz = sizeof(ioc_play_track); +unsigned struct_ioc_read_subchannel_sz = sizeof(ioc_read_subchannel); +unsigned struct_ioc_read_toc_entry_sz = sizeof(ioc_read_toc_entry); +unsigned struct_ioc_toc_header_sz = sizeof(ioc_toc_header); +unsigned struct_ioc_vol_sz = sizeof(ioc_vol); +unsigned struct_ioctl_pt_sz = sizeof(ioctl_pt); +unsigned struct_ioppt_sz = sizeof(ioppt); +unsigned struct_iovec_sz = sizeof(iovec); +unsigned struct_ipfobj_sz = sizeof(ipfobj); +unsigned struct_irda_params_sz = sizeof(irda_params); +unsigned struct_isp_fc_device_sz = sizeof(isp_fc_device); +unsigned struct_isp_fc_tsk_mgmt_sz = sizeof(isp_fc_tsk_mgmt); +unsigned struct_isp_hba_device_sz = sizeof(isp_hba_device); +unsigned struct_isv_cmd_sz = sizeof(isv_cmd); +unsigned struct_jobs_add_class_sz = sizeof(jobs_add_class); +unsigned struct_jobs_add_filter_sz = sizeof(jobs_add_filter); +unsigned struct_jobs_attach_sz = sizeof(jobs_attach); +unsigned struct_jobs_class_stats_sz = sizeof(jobs_class_stats); +unsigned struct_jobs_delete_class_sz = sizeof(jobs_delete_class); +unsigned struct_jobs_delete_filter_sz = sizeof(jobs_delete_filter); +unsigned struct_jobs_interface_sz = sizeof(jobs_interface); +unsigned struct_jobs_modify_class_sz = sizeof(jobs_modify_class); +unsigned struct_kbentry_sz = sizeof(kbentry); +unsigned struct_kfilter_mapping_sz = sizeof(kfilter_mapping); +unsigned struct_kiockeymap_sz = sizeof(kiockeymap); +unsigned struct_ksyms_gsymbol_sz = sizeof(ksyms_gsymbol); +unsigned struct_ksyms_gvalue_sz = sizeof(ksyms_gvalue); +unsigned struct_ksyms_ogsymbol_sz = sizeof(ksyms_ogsymbol); +unsigned struct_kttcp_io_args_sz = sizeof(kttcp_io_args); +unsigned struct_ltchars_sz = sizeof(ltchars); +unsigned struct_lua_create_sz = sizeof(struct lua_create); +unsigned struct_lua_info_sz = sizeof(struct lua_info); +unsigned struct_lua_load_sz = sizeof(struct lua_load); +unsigned struct_lua_require_sz = sizeof(lua_require); +unsigned struct_mbpp_param_sz = sizeof(mbpp_param); +unsigned struct_md_conf_sz = sizeof(md_conf); +unsigned struct_meteor_capframe_sz = sizeof(meteor_capframe); +unsigned struct_meteor_counts_sz = sizeof(meteor_counts); +unsigned struct_meteor_geomet_sz = sizeof(meteor_geomet); +unsigned struct_meteor_pixfmt_sz = sizeof(meteor_pixfmt); +unsigned struct_meteor_video_sz = sizeof(meteor_video); +unsigned struct_mlx_cinfo_sz = sizeof(mlx_cinfo); +unsigned struct_mlx_pause_sz = sizeof(mlx_pause); +unsigned struct_mlx_rebuild_request_sz = sizeof(mlx_rebuild_request); +unsigned struct_mlx_rebuild_status_sz = sizeof(mlx_rebuild_status); +unsigned struct_mlx_usercommand_sz = sizeof(mlx_usercommand); +unsigned struct_mly_user_command_sz = sizeof(mly_user_command); +unsigned struct_mly_user_health_sz = sizeof(mly_user_health); +unsigned struct_mtget_sz = sizeof(mtget); +unsigned struct_mtop_sz = sizeof(mtop); +unsigned struct_npf_ioctl_table_sz = sizeof(npf_ioctl_table); +unsigned struct_npioctl_sz = sizeof(npioctl); +unsigned struct_nvme_pt_command_sz = sizeof(nvme_pt_command); +unsigned struct_ochanger_element_status_request_sz = + sizeof(ochanger_element_status_request); +unsigned struct_ofiocdesc_sz = sizeof(ofiocdesc); +unsigned struct_okiockey_sz = sizeof(okiockey); +unsigned struct_ortentry_sz = sizeof(ortentry); +unsigned struct_oscsi_addr_sz = sizeof(oscsi_addr); +unsigned struct_oss_audioinfo_sz = sizeof(oss_audioinfo); +unsigned struct_oss_sysinfo_sz = sizeof(oss_sysinfo); +unsigned struct_pciio_bdf_cfgreg_sz = sizeof(pciio_bdf_cfgreg); +unsigned struct_pciio_businfo_sz = sizeof(pciio_businfo); +unsigned struct_pciio_cfgreg_sz = sizeof(pciio_cfgreg); +unsigned struct_pciio_drvname_sz = sizeof(pciio_drvname); +unsigned struct_pciio_drvnameonbus_sz = sizeof(pciio_drvnameonbus); +unsigned struct_pcvtid_sz = sizeof(pcvtid); +unsigned struct_pf_osfp_ioctl_sz = sizeof(pf_osfp_ioctl); +unsigned struct_pf_status_sz = sizeof(pf_status); +unsigned struct_pfioc_altq_sz = sizeof(pfioc_altq); +unsigned struct_pfioc_if_sz = sizeof(pfioc_if); +unsigned struct_pfioc_iface_sz = sizeof(pfioc_iface); +unsigned struct_pfioc_limit_sz = sizeof(pfioc_limit); +unsigned struct_pfioc_natlook_sz = sizeof(pfioc_natlook); +unsigned struct_pfioc_pooladdr_sz = sizeof(pfioc_pooladdr); +unsigned struct_pfioc_qstats_sz = sizeof(pfioc_qstats); +unsigned struct_pfioc_rule_sz = sizeof(pfioc_rule); +unsigned struct_pfioc_ruleset_sz = sizeof(pfioc_ruleset); +unsigned struct_pfioc_src_node_kill_sz = sizeof(pfioc_src_node_kill); +unsigned struct_pfioc_src_nodes_sz = sizeof(pfioc_src_nodes); +unsigned struct_pfioc_state_kill_sz = sizeof(pfioc_state_kill); +unsigned struct_pfioc_state_sz = sizeof(pfioc_state); +unsigned struct_pfioc_states_sz = sizeof(pfioc_states); +unsigned struct_pfioc_table_sz = sizeof(pfioc_table); +unsigned struct_pfioc_tm_sz = sizeof(pfioc_tm); +unsigned struct_pfioc_trans_sz = sizeof(pfioc_trans); +unsigned struct_plistref_sz = sizeof(plistref); +unsigned struct_power_type_sz = sizeof(power_type); +unsigned struct_ppp_idle_sz = sizeof(ppp_idle); +unsigned struct_ppp_option_data_sz = sizeof(ppp_option_data); +unsigned struct_ppp_rawin_sz = sizeof(ppp_rawin); +unsigned struct_pppoeconnectionstate_sz = sizeof(pppoeconnectionstate); +unsigned struct_pppoediscparms_sz = sizeof(pppoediscparms); +unsigned struct_priq_add_class_sz = sizeof(priq_add_class); +unsigned struct_priq_add_filter_sz = sizeof(priq_add_filter); +unsigned struct_priq_class_stats_sz = sizeof(priq_class_stats); +unsigned struct_priq_delete_class_sz = sizeof(priq_delete_class); +unsigned struct_priq_delete_filter_sz = sizeof(priq_delete_filter); +unsigned struct_priq_interface_sz = sizeof(priq_interface); +unsigned struct_priq_modify_class_sz = sizeof(priq_modify_class); +unsigned struct_ptmget_sz = sizeof(ptmget); +unsigned struct_radio_info_sz = sizeof(radio_info); +unsigned struct_red_conf_sz = sizeof(red_conf); +unsigned struct_red_interface_sz = sizeof(red_interface); +unsigned struct_red_stats_sz = sizeof(red_stats); +unsigned struct_redparams_sz = sizeof(redparams); +unsigned struct_rf_pmparams_sz = sizeof(rf_pmparams); +unsigned struct_rf_pmstat_sz = sizeof(rf_pmstat); +unsigned struct_rf_recon_req_sz = sizeof(rf_recon_req); +unsigned struct_rio_conf_sz = sizeof(rio_conf); +unsigned struct_rio_interface_sz = sizeof(rio_interface); +unsigned struct_rio_stats_sz = sizeof(rio_stats); +unsigned struct_scan_io_sz = sizeof(scan_io); +unsigned struct_scbusaccel_args_sz = sizeof(scbusaccel_args); +unsigned struct_scbusiodetach_args_sz = sizeof(scbusiodetach_args); +unsigned struct_scbusioscan_args_sz = sizeof(scbusioscan_args); +unsigned struct_scsi_addr_sz = sizeof(scsi_addr); +unsigned struct_seq_event_rec_sz = sizeof(seq_event_rec); +unsigned struct_session_op_sz = sizeof(session_op); +unsigned struct_sgttyb_sz = sizeof(sgttyb); +unsigned struct_sioc_sg_req_sz = sizeof(sioc_sg_req); +unsigned struct_sioc_vif_req_sz = sizeof(sioc_vif_req); +unsigned struct_smbioc_flags_sz = sizeof(smbioc_flags); +unsigned struct_smbioc_lookup_sz = sizeof(smbioc_lookup); +unsigned struct_smbioc_oshare_sz = sizeof(smbioc_oshare); +unsigned struct_smbioc_ossn_sz = sizeof(smbioc_ossn); +unsigned struct_smbioc_rq_sz = sizeof(smbioc_rq); +unsigned struct_smbioc_rw_sz = sizeof(smbioc_rw); +unsigned struct_spppauthcfg_sz = sizeof(spppauthcfg); +unsigned struct_spppauthfailuresettings_sz = sizeof(spppauthfailuresettings); +unsigned struct_spppauthfailurestats_sz = sizeof(spppauthfailurestats); +unsigned struct_spppdnsaddrs_sz = sizeof(spppdnsaddrs); +unsigned struct_spppdnssettings_sz = sizeof(spppdnssettings); +unsigned struct_spppidletimeout_sz = sizeof(spppidletimeout); +unsigned struct_spppkeepalivesettings_sz = sizeof(spppkeepalivesettings); +unsigned struct_sppplcpcfg_sz = sizeof(sppplcpcfg); +unsigned struct_spppstatus_sz = sizeof(spppstatus); +unsigned struct_spppstatusncp_sz = sizeof(spppstatusncp); +unsigned struct_srt_rt_sz = sizeof(srt_rt); +unsigned struct_stic_xinfo_sz = sizeof(stic_xinfo); +unsigned struct_sun_dkctlr_sz = sizeof(sun_dkctlr); +unsigned struct_sun_dkgeom_sz = sizeof(sun_dkgeom); +unsigned struct_sun_dkpart_sz = sizeof(sun_dkpart); +unsigned struct_synth_info_sz = sizeof(synth_info); +unsigned struct_tbrreq_sz = sizeof(tbrreq); +unsigned struct_tchars_sz = sizeof(tchars); +unsigned struct_termios_sz = sizeof(termios); +unsigned struct_timeval_sz = sizeof(timeval); +unsigned struct_twe_drivecommand_sz = sizeof(twe_drivecommand); +unsigned struct_twe_paramcommand_sz = sizeof(twe_paramcommand); +unsigned struct_twe_usercommand_sz = sizeof(twe_usercommand); +unsigned struct_ukyopon_identify_sz = sizeof(ukyopon_identify); +unsigned struct_urio_command_sz = sizeof(urio_command); +unsigned struct_usb_alt_interface_sz = sizeof(usb_alt_interface); +unsigned struct_usb_bulk_ra_wb_opt_sz = sizeof(usb_bulk_ra_wb_opt); +unsigned struct_usb_config_desc_sz = sizeof(usb_config_desc); +unsigned struct_usb_ctl_report_desc_sz = sizeof(usb_ctl_report_desc); +unsigned struct_usb_ctl_report_sz = sizeof(usb_ctl_report); +unsigned struct_usb_ctl_request_sz = sizeof(usb_ctl_request); +#if defined(__x86_64__) +unsigned struct_nvmm_ioc_capability_sz = sizeof(nvmm_ioc_capability); +unsigned struct_nvmm_ioc_machine_create_sz = sizeof(nvmm_ioc_machine_create); +unsigned struct_nvmm_ioc_machine_destroy_sz = sizeof(nvmm_ioc_machine_destroy); +unsigned struct_nvmm_ioc_machine_configure_sz = + sizeof(nvmm_ioc_machine_configure); +unsigned struct_nvmm_ioc_vcpu_create_sz = sizeof(nvmm_ioc_vcpu_create); +unsigned struct_nvmm_ioc_vcpu_destroy_sz = sizeof(nvmm_ioc_vcpu_destroy); +unsigned struct_nvmm_ioc_vcpu_setstate_sz = sizeof(nvmm_ioc_vcpu_destroy); +unsigned struct_nvmm_ioc_vcpu_getstate_sz = sizeof(nvmm_ioc_vcpu_getstate); +unsigned struct_nvmm_ioc_vcpu_inject_sz = sizeof(nvmm_ioc_vcpu_inject); +unsigned struct_nvmm_ioc_vcpu_run_sz = sizeof(nvmm_ioc_vcpu_run); +unsigned struct_nvmm_ioc_gpa_map_sz = sizeof(nvmm_ioc_gpa_map); +unsigned struct_nvmm_ioc_gpa_unmap_sz = sizeof(nvmm_ioc_gpa_unmap); +unsigned struct_nvmm_ioc_hva_map_sz = sizeof(nvmm_ioc_hva_map); +unsigned struct_nvmm_ioc_hva_unmap_sz = sizeof(nvmm_ioc_hva_unmap); +unsigned struct_nvmm_ioc_ctl_sz = sizeof(nvmm_ioc_ctl); +#endif +unsigned struct_spi_ioctl_configure_sz = sizeof(spi_ioctl_configure); +unsigned struct_spi_ioctl_transfer_sz = sizeof(spi_ioctl_transfer); +unsigned struct_autofs_daemon_request_sz = sizeof(autofs_daemon_request); +unsigned struct_autofs_daemon_done_sz = sizeof(autofs_daemon_done); +unsigned struct_sctp_connectx_addrs_sz = sizeof(sctp_connectx_addrs); +unsigned struct_usb_device_info_old_sz = sizeof(usb_device_info_old); +unsigned struct_usb_device_info_sz = sizeof(usb_device_info); +unsigned struct_usb_device_stats_sz = sizeof(usb_device_stats); +unsigned struct_usb_endpoint_desc_sz = sizeof(usb_endpoint_desc); +unsigned struct_usb_full_desc_sz = sizeof(usb_full_desc); +unsigned struct_usb_interface_desc_sz = sizeof(usb_interface_desc); +unsigned struct_usb_string_desc_sz = sizeof(usb_string_desc); +unsigned struct_utoppy_readfile_sz = sizeof(utoppy_readfile); +unsigned struct_utoppy_rename_sz = sizeof(utoppy_rename); +unsigned struct_utoppy_stats_sz = sizeof(utoppy_stats); +unsigned struct_utoppy_writefile_sz = sizeof(utoppy_writefile); +unsigned struct_v4l2_audio_sz = sizeof(v4l2_audio); +unsigned struct_v4l2_audioout_sz = sizeof(v4l2_audioout); +unsigned struct_v4l2_buffer_sz = sizeof(v4l2_buffer); +unsigned struct_v4l2_capability_sz = sizeof(v4l2_capability); +unsigned struct_v4l2_control_sz = sizeof(v4l2_control); +unsigned struct_v4l2_crop_sz = sizeof(v4l2_crop); +unsigned struct_v4l2_cropcap_sz = sizeof(v4l2_cropcap); +unsigned struct_v4l2_fmtdesc_sz = sizeof(v4l2_fmtdesc); +unsigned struct_v4l2_format_sz = sizeof(v4l2_format); +unsigned struct_v4l2_framebuffer_sz = sizeof(v4l2_framebuffer); +unsigned struct_v4l2_frequency_sz = sizeof(v4l2_frequency); +unsigned struct_v4l2_frmivalenum_sz = sizeof(v4l2_frmivalenum); +unsigned struct_v4l2_frmsizeenum_sz = sizeof(v4l2_frmsizeenum); +unsigned struct_v4l2_input_sz = sizeof(v4l2_input); +unsigned struct_v4l2_jpegcompression_sz = sizeof(v4l2_jpegcompression); +unsigned struct_v4l2_modulator_sz = sizeof(v4l2_modulator); +unsigned struct_v4l2_output_sz = sizeof(v4l2_output); +unsigned struct_v4l2_queryctrl_sz = sizeof(v4l2_queryctrl); +unsigned struct_v4l2_querymenu_sz = sizeof(v4l2_querymenu); +unsigned struct_v4l2_requestbuffers_sz = sizeof(v4l2_requestbuffers); +unsigned struct_v4l2_standard_sz = sizeof(v4l2_standard); +unsigned struct_v4l2_streamparm_sz = sizeof(v4l2_streamparm); +unsigned struct_v4l2_tuner_sz = sizeof(v4l2_tuner); +unsigned struct_vnd_ioctl_sz = sizeof(vnd_ioctl); +unsigned struct_vnd_user_sz = sizeof(vnd_user); +unsigned struct_vt_stat_sz = sizeof(vt_stat); +unsigned struct_wdog_conf_sz = sizeof(wdog_conf); +unsigned struct_wdog_mode_sz = sizeof(wdog_mode); +unsigned struct_ipmi_recv_sz = sizeof(ipmi_recv); +unsigned struct_ipmi_req_sz = sizeof(ipmi_req); +unsigned struct_ipmi_cmdspec_sz = sizeof(ipmi_cmdspec); +unsigned struct_wfq_conf_sz = sizeof(wfq_conf); +unsigned struct_wfq_getqid_sz = sizeof(wfq_getqid); +unsigned struct_wfq_getstats_sz = sizeof(wfq_getstats); +unsigned struct_wfq_interface_sz = sizeof(wfq_interface); +unsigned struct_wfq_setweight_sz = sizeof(wfq_setweight); +unsigned struct_winsize_sz = sizeof(winsize); +unsigned struct_wscons_event_sz = sizeof(wscons_event); +unsigned struct_wsdisplay_addscreendata_sz = sizeof(wsdisplay_addscreendata); +unsigned struct_wsdisplay_char_sz = sizeof(wsdisplay_char); +unsigned struct_wsdisplay_cmap_sz = sizeof(wsdisplay_cmap); +unsigned struct_wsdisplay_curpos_sz = sizeof(wsdisplay_curpos); +unsigned struct_wsdisplay_cursor_sz = sizeof(wsdisplay_cursor); +unsigned struct_wsdisplay_delscreendata_sz = sizeof(wsdisplay_delscreendata); +unsigned struct_wsdisplay_fbinfo_sz = sizeof(wsdisplay_fbinfo); +unsigned struct_wsdisplay_font_sz = sizeof(wsdisplay_font); +unsigned struct_wsdisplay_kbddata_sz = sizeof(wsdisplay_kbddata); +unsigned struct_wsdisplay_msgattrs_sz = sizeof(wsdisplay_msgattrs); +unsigned struct_wsdisplay_param_sz = sizeof(wsdisplay_param); +unsigned struct_wsdisplay_scroll_data_sz = sizeof(wsdisplay_scroll_data); +unsigned struct_wsdisplay_usefontdata_sz = sizeof(wsdisplay_usefontdata); +unsigned struct_wsdisplayio_blit_sz = sizeof(wsdisplayio_blit); +unsigned struct_wsdisplayio_bus_id_sz = sizeof(wsdisplayio_bus_id); +unsigned struct_wsdisplayio_edid_info_sz = sizeof(wsdisplayio_edid_info); +unsigned struct_wsdisplayio_fbinfo_sz = sizeof(wsdisplayio_fbinfo); +unsigned struct_wskbd_bell_data_sz = sizeof(wskbd_bell_data); +unsigned struct_wskbd_keyrepeat_data_sz = sizeof(wskbd_keyrepeat_data); +unsigned struct_wskbd_map_data_sz = sizeof(wskbd_map_data); +unsigned struct_wskbd_scroll_data_sz = sizeof(wskbd_scroll_data); +unsigned struct_wsmouse_calibcoords_sz = sizeof(wsmouse_calibcoords); +unsigned struct_wsmouse_id_sz = sizeof(wsmouse_id); +unsigned struct_wsmouse_repeat_sz = sizeof(wsmouse_repeat); +unsigned struct_wsmux_device_list_sz = sizeof(wsmux_device_list); +unsigned struct_wsmux_device_sz = sizeof(wsmux_device); +unsigned struct_xd_iocmd_sz = sizeof(xd_iocmd); + +unsigned struct_scsireq_sz = sizeof(struct scsireq); +unsigned struct_tone_sz = sizeof(tone_t); +unsigned union_twe_statrequest_sz = sizeof(union twe_statrequest); +unsigned struct_usb_device_descriptor_sz = sizeof(usb_device_descriptor_t); +unsigned struct_vt_mode_sz = sizeof(struct vt_mode); +unsigned struct__old_mixer_info_sz = sizeof(struct _old_mixer_info); +unsigned struct__agp_allocate_sz = sizeof(struct _agp_allocate); +unsigned struct__agp_bind_sz = sizeof(struct _agp_bind); +unsigned struct__agp_info_sz = sizeof(struct _agp_info); +unsigned struct__agp_setup_sz = sizeof(struct _agp_setup); +unsigned struct__agp_unbind_sz = sizeof(struct _agp_unbind); +unsigned struct_atareq_sz = sizeof(struct atareq); +unsigned struct_cpustate_sz = sizeof(struct cpustate); +unsigned struct_dmx_caps_sz = sizeof(struct dmx_caps); +unsigned enum_dmx_source_sz = sizeof(dmx_source_t); +unsigned union_dvd_authinfo_sz = sizeof(dvd_authinfo); +unsigned union_dvd_struct_sz = sizeof(dvd_struct); +unsigned enum_v4l2_priority_sz = sizeof(enum v4l2_priority); +unsigned struct_envsys_basic_info_sz = sizeof(struct envsys_basic_info); +unsigned struct_envsys_tre_data_sz = sizeof(struct envsys_tre_data); +unsigned enum_fe_sec_mini_cmd_sz = sizeof(enum fe_sec_mini_cmd); +unsigned enum_fe_sec_tone_mode_sz = sizeof(enum fe_sec_tone_mode); +unsigned enum_fe_sec_voltage_sz = sizeof(enum fe_sec_voltage); +unsigned enum_fe_status_sz = sizeof(enum fe_status); +unsigned struct_gdt_ctrt_sz = sizeof(struct gdt_ctrt); +unsigned struct_gdt_event_sz = sizeof(struct gdt_event); +unsigned struct_gdt_osv_sz = sizeof(struct gdt_osv); +unsigned struct_gdt_rescan_sz = sizeof(struct gdt_rescan); +unsigned struct_gdt_statist_sz = sizeof(struct gdt_statist); +unsigned struct_gdt_ucmd_sz = sizeof(struct gdt_ucmd); +unsigned struct_iscsi_conn_status_parameters_sz = + sizeof(iscsi_conn_status_parameters_t); +unsigned struct_iscsi_get_version_parameters_sz = + sizeof(iscsi_get_version_parameters_t); +unsigned struct_iscsi_iocommand_parameters_sz = + sizeof(iscsi_iocommand_parameters_t); +unsigned struct_iscsi_login_parameters_sz = sizeof(iscsi_login_parameters_t); +unsigned struct_iscsi_logout_parameters_sz = sizeof(iscsi_logout_parameters_t); +unsigned struct_iscsi_register_event_parameters_sz = + sizeof(iscsi_register_event_parameters_t); +unsigned struct_iscsi_remove_parameters_sz = sizeof(iscsi_remove_parameters_t); +unsigned struct_iscsi_send_targets_parameters_sz = + sizeof(iscsi_send_targets_parameters_t); +unsigned struct_iscsi_set_node_name_parameters_sz = + sizeof(iscsi_set_node_name_parameters_t); +unsigned struct_iscsi_wait_event_parameters_sz = + sizeof(iscsi_wait_event_parameters_t); +unsigned struct_isp_stats_sz = sizeof(isp_stats_t); +unsigned struct_lsenable_sz = sizeof(struct lsenable); +unsigned struct_lsdisable_sz = sizeof(struct lsdisable); +unsigned struct_audio_format_query_sz = sizeof(audio_format_query); +unsigned struct_mixer_ctrl_sz = sizeof(struct mixer_ctrl); +unsigned struct_mixer_devinfo_sz = sizeof(struct mixer_devinfo); +unsigned struct_mpu_command_rec_sz = sizeof(mpu_command_rec); +unsigned struct_rndstat_sz = sizeof(rndstat_t); +unsigned struct_rndstat_name_sz = sizeof(rndstat_name_t); +unsigned struct_rndctl_sz = sizeof(rndctl_t); +unsigned struct_rnddata_sz = sizeof(rnddata_t); +unsigned struct_rndpoolstat_sz = sizeof(rndpoolstat_t); +unsigned struct_rndstat_est_sz = sizeof(rndstat_est_t); +unsigned struct_rndstat_est_name_sz = sizeof(rndstat_est_name_t); +unsigned struct_pps_params_sz = sizeof(pps_params_t); +unsigned struct_pps_info_sz = sizeof(pps_info_t); +unsigned struct_mixer_info_sz = sizeof(struct mixer_info); +unsigned struct_RF_SparetWait_sz = sizeof(RF_SparetWait_t); +unsigned struct_RF_ComponentLabel_sz = sizeof(RF_ComponentLabel_t); +unsigned struct_RF_SingleComponent_sz = sizeof(RF_SingleComponent_t); +unsigned struct_RF_ProgressInfo_sz = sizeof(RF_ProgressInfo_t); +unsigned struct_nvlist_ref_sz = sizeof(struct __sanitizer_nvlist_ref_t); +unsigned struct_StringList_sz = sizeof(StringList); + +const unsigned IOCTL_NOT_PRESENT = 0; + +unsigned IOCTL_AFM_ADDFMAP = AFM_ADDFMAP; +unsigned IOCTL_AFM_DELFMAP = AFM_DELFMAP; +unsigned IOCTL_AFM_CLEANFMAP = AFM_CLEANFMAP; +unsigned IOCTL_AFM_GETFMAP = AFM_GETFMAP; +unsigned IOCTL_ALTQGTYPE = ALTQGTYPE; +unsigned IOCTL_ALTQTBRSET = ALTQTBRSET; +unsigned IOCTL_ALTQTBRGET = ALTQTBRGET; +unsigned IOCTL_BLUE_IF_ATTACH = BLUE_IF_ATTACH; +unsigned IOCTL_BLUE_IF_DETACH = BLUE_IF_DETACH; +unsigned IOCTL_BLUE_ENABLE = BLUE_ENABLE; +unsigned IOCTL_BLUE_DISABLE = BLUE_DISABLE; +unsigned IOCTL_BLUE_CONFIG = BLUE_CONFIG; +unsigned IOCTL_BLUE_GETSTATS = BLUE_GETSTATS; +unsigned IOCTL_CBQ_IF_ATTACH = CBQ_IF_ATTACH; +unsigned IOCTL_CBQ_IF_DETACH = CBQ_IF_DETACH; +unsigned IOCTL_CBQ_ENABLE = CBQ_ENABLE; +unsigned IOCTL_CBQ_DISABLE = CBQ_DISABLE; +unsigned IOCTL_CBQ_CLEAR_HIERARCHY = CBQ_CLEAR_HIERARCHY; +unsigned IOCTL_CBQ_ADD_CLASS = CBQ_ADD_CLASS; +unsigned IOCTL_CBQ_DEL_CLASS = CBQ_DEL_CLASS; +unsigned IOCTL_CBQ_MODIFY_CLASS = CBQ_MODIFY_CLASS; +unsigned IOCTL_CBQ_ADD_FILTER = CBQ_ADD_FILTER; +unsigned IOCTL_CBQ_DEL_FILTER = CBQ_DEL_FILTER; +unsigned IOCTL_CBQ_GETSTATS = CBQ_GETSTATS; +unsigned IOCTL_CDNR_IF_ATTACH = CDNR_IF_ATTACH; +unsigned IOCTL_CDNR_IF_DETACH = CDNR_IF_DETACH; +unsigned IOCTL_CDNR_ENABLE = CDNR_ENABLE; +unsigned IOCTL_CDNR_DISABLE = CDNR_DISABLE; +unsigned IOCTL_CDNR_ADD_FILTER = CDNR_ADD_FILTER; +unsigned IOCTL_CDNR_DEL_FILTER = CDNR_DEL_FILTER; +unsigned IOCTL_CDNR_GETSTATS = CDNR_GETSTATS; +unsigned IOCTL_CDNR_ADD_ELEM = CDNR_ADD_ELEM; +unsigned IOCTL_CDNR_DEL_ELEM = CDNR_DEL_ELEM; +unsigned IOCTL_CDNR_ADD_TBM = CDNR_ADD_TBM; +unsigned IOCTL_CDNR_MOD_TBM = CDNR_MOD_TBM; +unsigned IOCTL_CDNR_TBM_STATS = CDNR_TBM_STATS; +unsigned IOCTL_CDNR_ADD_TCM = CDNR_ADD_TCM; +unsigned IOCTL_CDNR_MOD_TCM = CDNR_MOD_TCM; +unsigned IOCTL_CDNR_TCM_STATS = CDNR_TCM_STATS; +unsigned IOCTL_CDNR_ADD_TSW = CDNR_ADD_TSW; +unsigned IOCTL_CDNR_MOD_TSW = CDNR_MOD_TSW; +unsigned IOCTL_FIFOQ_IF_ATTACH = FIFOQ_IF_ATTACH; +unsigned IOCTL_FIFOQ_IF_DETACH = FIFOQ_IF_DETACH; +unsigned IOCTL_FIFOQ_ENABLE = FIFOQ_ENABLE; +unsigned IOCTL_FIFOQ_DISABLE = FIFOQ_DISABLE; +unsigned IOCTL_FIFOQ_CONFIG = FIFOQ_CONFIG; +unsigned IOCTL_FIFOQ_GETSTATS = FIFOQ_GETSTATS; +unsigned IOCTL_HFSC_IF_ATTACH = HFSC_IF_ATTACH; +unsigned IOCTL_HFSC_IF_DETACH = HFSC_IF_DETACH; +unsigned IOCTL_HFSC_ENABLE = HFSC_ENABLE; +unsigned IOCTL_HFSC_DISABLE = HFSC_DISABLE; +unsigned IOCTL_HFSC_CLEAR_HIERARCHY = HFSC_CLEAR_HIERARCHY; +unsigned IOCTL_HFSC_ADD_CLASS = HFSC_ADD_CLASS; +unsigned IOCTL_HFSC_DEL_CLASS = HFSC_DEL_CLASS; +unsigned IOCTL_HFSC_MOD_CLASS = HFSC_MOD_CLASS; +unsigned IOCTL_HFSC_ADD_FILTER = HFSC_ADD_FILTER; +unsigned IOCTL_HFSC_DEL_FILTER = HFSC_DEL_FILTER; +unsigned IOCTL_HFSC_GETSTATS = HFSC_GETSTATS; +unsigned IOCTL_JOBS_IF_ATTACH = JOBS_IF_ATTACH; +unsigned IOCTL_JOBS_IF_DETACH = JOBS_IF_DETACH; +unsigned IOCTL_JOBS_ENABLE = JOBS_ENABLE; +unsigned IOCTL_JOBS_DISABLE = JOBS_DISABLE; +unsigned IOCTL_JOBS_CLEAR = JOBS_CLEAR; +unsigned IOCTL_JOBS_ADD_CLASS = JOBS_ADD_CLASS; +unsigned IOCTL_JOBS_DEL_CLASS = JOBS_DEL_CLASS; +unsigned IOCTL_JOBS_MOD_CLASS = JOBS_MOD_CLASS; +unsigned IOCTL_JOBS_ADD_FILTER = JOBS_ADD_FILTER; +unsigned IOCTL_JOBS_DEL_FILTER = JOBS_DEL_FILTER; +unsigned IOCTL_JOBS_GETSTATS = JOBS_GETSTATS; +unsigned IOCTL_PRIQ_IF_ATTACH = PRIQ_IF_ATTACH; +unsigned IOCTL_PRIQ_IF_DETACH = PRIQ_IF_DETACH; +unsigned IOCTL_PRIQ_ENABLE = PRIQ_ENABLE; +unsigned IOCTL_PRIQ_DISABLE = PRIQ_DISABLE; +unsigned IOCTL_PRIQ_CLEAR = PRIQ_CLEAR; +unsigned IOCTL_PRIQ_ADD_CLASS = PRIQ_ADD_CLASS; +unsigned IOCTL_PRIQ_DEL_CLASS = PRIQ_DEL_CLASS; +unsigned IOCTL_PRIQ_MOD_CLASS = PRIQ_MOD_CLASS; +unsigned IOCTL_PRIQ_ADD_FILTER = PRIQ_ADD_FILTER; +unsigned IOCTL_PRIQ_DEL_FILTER = PRIQ_DEL_FILTER; +unsigned IOCTL_PRIQ_GETSTATS = PRIQ_GETSTATS; +unsigned IOCTL_RED_IF_ATTACH = RED_IF_ATTACH; +unsigned IOCTL_RED_IF_DETACH = RED_IF_DETACH; +unsigned IOCTL_RED_ENABLE = RED_ENABLE; +unsigned IOCTL_RED_DISABLE = RED_DISABLE; +unsigned IOCTL_RED_CONFIG = RED_CONFIG; +unsigned IOCTL_RED_GETSTATS = RED_GETSTATS; +unsigned IOCTL_RED_SETDEFAULTS = RED_SETDEFAULTS; +unsigned IOCTL_RIO_IF_ATTACH = RIO_IF_ATTACH; +unsigned IOCTL_RIO_IF_DETACH = RIO_IF_DETACH; +unsigned IOCTL_RIO_ENABLE = RIO_ENABLE; +unsigned IOCTL_RIO_DISABLE = RIO_DISABLE; +unsigned IOCTL_RIO_CONFIG = RIO_CONFIG; +unsigned IOCTL_RIO_GETSTATS = RIO_GETSTATS; +unsigned IOCTL_RIO_SETDEFAULTS = RIO_SETDEFAULTS; +unsigned IOCTL_WFQ_IF_ATTACH = WFQ_IF_ATTACH; +unsigned IOCTL_WFQ_IF_DETACH = WFQ_IF_DETACH; +unsigned IOCTL_WFQ_ENABLE = WFQ_ENABLE; +unsigned IOCTL_WFQ_DISABLE = WFQ_DISABLE; +unsigned IOCTL_WFQ_CONFIG = WFQ_CONFIG; +unsigned IOCTL_WFQ_GET_STATS = WFQ_GET_STATS; +unsigned IOCTL_WFQ_GET_QID = WFQ_GET_QID; +unsigned IOCTL_WFQ_SET_WEIGHT = WFQ_SET_WEIGHT; +unsigned IOCTL_CRIOGET = CRIOGET; +unsigned IOCTL_CIOCFSESSION = CIOCFSESSION; +unsigned IOCTL_CIOCKEY = CIOCKEY; +unsigned IOCTL_CIOCNFKEYM = CIOCNFKEYM; +unsigned IOCTL_CIOCNFSESSION = CIOCNFSESSION; +unsigned IOCTL_CIOCNCRYPTRETM = CIOCNCRYPTRETM; +unsigned IOCTL_CIOCNCRYPTRET = CIOCNCRYPTRET; +unsigned IOCTL_CIOCGSESSION = CIOCGSESSION; +unsigned IOCTL_CIOCNGSESSION = CIOCNGSESSION; +unsigned IOCTL_CIOCCRYPT = CIOCCRYPT; +unsigned IOCTL_CIOCNCRYPTM = CIOCNCRYPTM; +unsigned IOCTL_CIOCASYMFEAT = CIOCASYMFEAT; +unsigned IOCTL_APM_IOC_REJECT = APM_IOC_REJECT; +unsigned IOCTL_APM_IOC_STANDBY = APM_IOC_STANDBY; +unsigned IOCTL_APM_IOC_SUSPEND = APM_IOC_SUSPEND; +unsigned IOCTL_OAPM_IOC_GETPOWER = OAPM_IOC_GETPOWER; +unsigned IOCTL_APM_IOC_GETPOWER = APM_IOC_GETPOWER; +unsigned IOCTL_APM_IOC_NEXTEVENT = APM_IOC_NEXTEVENT; +unsigned IOCTL_APM_IOC_DEV_CTL = APM_IOC_DEV_CTL; +unsigned IOCTL_NETBSD_DM_IOCTL = NETBSD_DM_IOCTL; +unsigned IOCTL_DMIO_SETFUNC = DMIO_SETFUNC; +unsigned IOCTL_DMX_START = DMX_START; +unsigned IOCTL_DMX_STOP = DMX_STOP; +unsigned IOCTL_DMX_SET_FILTER = DMX_SET_FILTER; +unsigned IOCTL_DMX_SET_PES_FILTER = DMX_SET_PES_FILTER; +unsigned IOCTL_DMX_SET_BUFFER_SIZE = DMX_SET_BUFFER_SIZE; +unsigned IOCTL_DMX_GET_STC = DMX_GET_STC; +unsigned IOCTL_DMX_ADD_PID = DMX_ADD_PID; +unsigned IOCTL_DMX_REMOVE_PID = DMX_REMOVE_PID; +unsigned IOCTL_DMX_GET_CAPS = DMX_GET_CAPS; +unsigned IOCTL_DMX_SET_SOURCE = DMX_SET_SOURCE; +unsigned IOCTL_FE_READ_STATUS = FE_READ_STATUS; +unsigned IOCTL_FE_READ_BER = FE_READ_BER; +unsigned IOCTL_FE_READ_SNR = FE_READ_SNR; +unsigned IOCTL_FE_READ_SIGNAL_STRENGTH = FE_READ_SIGNAL_STRENGTH; +unsigned IOCTL_FE_READ_UNCORRECTED_BLOCKS = FE_READ_UNCORRECTED_BLOCKS; +unsigned IOCTL_FE_SET_FRONTEND = FE_SET_FRONTEND; +unsigned IOCTL_FE_GET_FRONTEND = FE_GET_FRONTEND; +unsigned IOCTL_FE_GET_EVENT = FE_GET_EVENT; +unsigned IOCTL_FE_GET_INFO = FE_GET_INFO; +unsigned IOCTL_FE_DISEQC_RESET_OVERLOAD = FE_DISEQC_RESET_OVERLOAD; +unsigned IOCTL_FE_DISEQC_SEND_MASTER_CMD = FE_DISEQC_SEND_MASTER_CMD; +unsigned IOCTL_FE_DISEQC_RECV_SLAVE_REPLY = FE_DISEQC_RECV_SLAVE_REPLY; +unsigned IOCTL_FE_DISEQC_SEND_BURST = FE_DISEQC_SEND_BURST; +unsigned IOCTL_FE_SET_TONE = FE_SET_TONE; +unsigned IOCTL_FE_SET_VOLTAGE = FE_SET_VOLTAGE; +unsigned IOCTL_FE_ENABLE_HIGH_LNB_VOLTAGE = FE_ENABLE_HIGH_LNB_VOLTAGE; +unsigned IOCTL_FE_SET_FRONTEND_TUNE_MODE = FE_SET_FRONTEND_TUNE_MODE; +unsigned IOCTL_FE_DISHNETWORK_SEND_LEGACY_CMD = FE_DISHNETWORK_SEND_LEGACY_CMD; +unsigned IOCTL_FILEMON_SET_FD = FILEMON_SET_FD; +unsigned IOCTL_FILEMON_SET_PID = FILEMON_SET_PID; +unsigned IOCTL_HDAUDIO_FGRP_INFO = HDAUDIO_FGRP_INFO; +unsigned IOCTL_HDAUDIO_FGRP_GETCONFIG = HDAUDIO_FGRP_GETCONFIG; +unsigned IOCTL_HDAUDIO_FGRP_SETCONFIG = HDAUDIO_FGRP_SETCONFIG; +unsigned IOCTL_HDAUDIO_FGRP_WIDGET_INFO = HDAUDIO_FGRP_WIDGET_INFO; +unsigned IOCTL_HDAUDIO_FGRP_CODEC_INFO = HDAUDIO_FGRP_CODEC_INFO; +unsigned IOCTL_HDAUDIO_AFG_WIDGET_INFO = HDAUDIO_AFG_WIDGET_INFO; +unsigned IOCTL_HDAUDIO_AFG_CODEC_INFO = HDAUDIO_AFG_CODEC_INFO; +unsigned IOCTL_CEC_GET_PHYS_ADDR = CEC_GET_PHYS_ADDR; +unsigned IOCTL_CEC_GET_LOG_ADDRS = CEC_GET_LOG_ADDRS; +unsigned IOCTL_CEC_SET_LOG_ADDRS = CEC_SET_LOG_ADDRS; +unsigned IOCTL_CEC_GET_VENDOR_ID = CEC_GET_VENDOR_ID; +unsigned IOCTL_HPCFBIO_GCONF = HPCFBIO_GCONF; +unsigned IOCTL_HPCFBIO_SCONF = HPCFBIO_SCONF; +unsigned IOCTL_HPCFBIO_GDSPCONF = HPCFBIO_GDSPCONF; +unsigned IOCTL_HPCFBIO_SDSPCONF = HPCFBIO_SDSPCONF; +unsigned IOCTL_HPCFBIO_GOP = HPCFBIO_GOP; +unsigned IOCTL_HPCFBIO_SOP = HPCFBIO_SOP; +unsigned IOCTL_IOPIOCPT = IOPIOCPT; +unsigned IOCTL_IOPIOCGLCT = IOPIOCGLCT; +unsigned IOCTL_IOPIOCGSTATUS = IOPIOCGSTATUS; +unsigned IOCTL_IOPIOCRECONFIG = IOPIOCRECONFIG; +unsigned IOCTL_IOPIOCGTIDMAP = IOPIOCGTIDMAP; +unsigned IOCTL_SIOCGATHSTATS = SIOCGATHSTATS; +unsigned IOCTL_SIOCGATHDIAG = SIOCGATHDIAG; +unsigned IOCTL_METEORCAPTUR = METEORCAPTUR; +unsigned IOCTL_METEORCAPFRM = METEORCAPFRM; +unsigned IOCTL_METEORSETGEO = METEORSETGEO; +unsigned IOCTL_METEORGETGEO = METEORGETGEO; +unsigned IOCTL_METEORSTATUS = METEORSTATUS; +unsigned IOCTL_METEORSHUE = METEORSHUE; +unsigned IOCTL_METEORGHUE = METEORGHUE; +unsigned IOCTL_METEORSFMT = METEORSFMT; +unsigned IOCTL_METEORGFMT = METEORGFMT; +unsigned IOCTL_METEORSINPUT = METEORSINPUT; +unsigned IOCTL_METEORGINPUT = METEORGINPUT; +unsigned IOCTL_METEORSCHCV = METEORSCHCV; +unsigned IOCTL_METEORGCHCV = METEORGCHCV; +unsigned IOCTL_METEORSCOUNT = METEORSCOUNT; +unsigned IOCTL_METEORGCOUNT = METEORGCOUNT; +unsigned IOCTL_METEORSFPS = METEORSFPS; +unsigned IOCTL_METEORGFPS = METEORGFPS; +unsigned IOCTL_METEORSSIGNAL = METEORSSIGNAL; +unsigned IOCTL_METEORGSIGNAL = METEORGSIGNAL; +unsigned IOCTL_METEORSVIDEO = METEORSVIDEO; +unsigned IOCTL_METEORGVIDEO = METEORGVIDEO; +unsigned IOCTL_METEORSBRIG = METEORSBRIG; +unsigned IOCTL_METEORGBRIG = METEORGBRIG; +unsigned IOCTL_METEORSCSAT = METEORSCSAT; +unsigned IOCTL_METEORGCSAT = METEORGCSAT; +unsigned IOCTL_METEORSCONT = METEORSCONT; +unsigned IOCTL_METEORGCONT = METEORGCONT; +unsigned IOCTL_METEORSHWS = METEORSHWS; +unsigned IOCTL_METEORGHWS = METEORGHWS; +unsigned IOCTL_METEORSVWS = METEORSVWS; +unsigned IOCTL_METEORGVWS = METEORGVWS; +unsigned IOCTL_METEORSTS = METEORSTS; +unsigned IOCTL_METEORGTS = METEORGTS; +unsigned IOCTL_TVTUNER_SETCHNL = TVTUNER_SETCHNL; +unsigned IOCTL_TVTUNER_GETCHNL = TVTUNER_GETCHNL; +unsigned IOCTL_TVTUNER_SETTYPE = TVTUNER_SETTYPE; +unsigned IOCTL_TVTUNER_GETTYPE = TVTUNER_GETTYPE; +unsigned IOCTL_TVTUNER_GETSTATUS = TVTUNER_GETSTATUS; +unsigned IOCTL_TVTUNER_SETFREQ = TVTUNER_SETFREQ; +unsigned IOCTL_TVTUNER_GETFREQ = TVTUNER_GETFREQ; +unsigned IOCTL_TVTUNER_SETAFC = TVTUNER_SETAFC; +unsigned IOCTL_TVTUNER_GETAFC = TVTUNER_GETAFC; +unsigned IOCTL_RADIO_SETMODE = RADIO_SETMODE; +unsigned IOCTL_RADIO_GETMODE = RADIO_GETMODE; +unsigned IOCTL_RADIO_SETFREQ = RADIO_SETFREQ; +unsigned IOCTL_RADIO_GETFREQ = RADIO_GETFREQ; +unsigned IOCTL_METEORSACTPIXFMT = METEORSACTPIXFMT; +unsigned IOCTL_METEORGACTPIXFMT = METEORGACTPIXFMT; +unsigned IOCTL_METEORGSUPPIXFMT = METEORGSUPPIXFMT; +unsigned IOCTL_TVTUNER_GETCHNLSET = TVTUNER_GETCHNLSET; +unsigned IOCTL_REMOTE_GETKEY = REMOTE_GETKEY; +unsigned IOCTL_GDT_IOCTL_GENERAL = GDT_IOCTL_GENERAL; +unsigned IOCTL_GDT_IOCTL_DRVERS = GDT_IOCTL_DRVERS; +unsigned IOCTL_GDT_IOCTL_CTRTYPE = GDT_IOCTL_CTRTYPE; +unsigned IOCTL_GDT_IOCTL_OSVERS = GDT_IOCTL_OSVERS; +unsigned IOCTL_GDT_IOCTL_CTRCNT = GDT_IOCTL_CTRCNT; +unsigned IOCTL_GDT_IOCTL_EVENT = GDT_IOCTL_EVENT; +unsigned IOCTL_GDT_IOCTL_STATIST = GDT_IOCTL_STATIST; +unsigned IOCTL_GDT_IOCTL_RESCAN = GDT_IOCTL_RESCAN; +unsigned IOCTL_ISP_SDBLEV = ISP_SDBLEV; +unsigned IOCTL_ISP_RESETHBA = ISP_RESETHBA; +unsigned IOCTL_ISP_RESCAN = ISP_RESCAN; +unsigned IOCTL_ISP_SETROLE = ISP_SETROLE; +unsigned IOCTL_ISP_GETROLE = ISP_GETROLE; +unsigned IOCTL_ISP_GET_STATS = ISP_GET_STATS; +unsigned IOCTL_ISP_CLR_STATS = ISP_CLR_STATS; +unsigned IOCTL_ISP_FC_LIP = ISP_FC_LIP; +unsigned IOCTL_ISP_FC_GETDINFO = ISP_FC_GETDINFO; +unsigned IOCTL_ISP_GET_FW_CRASH_DUMP = ISP_GET_FW_CRASH_DUMP; +unsigned IOCTL_ISP_FORCE_CRASH_DUMP = ISP_FORCE_CRASH_DUMP; +unsigned IOCTL_ISP_FC_GETHINFO = ISP_FC_GETHINFO; +unsigned IOCTL_ISP_TSK_MGMT = ISP_TSK_MGMT; +unsigned IOCTL_ISP_FC_GETDLIST = ISP_FC_GETDLIST; +unsigned IOCTL_MLXD_STATUS = MLXD_STATUS; +unsigned IOCTL_MLXD_CHECKASYNC = MLXD_CHECKASYNC; +unsigned IOCTL_MLXD_DETACH = MLXD_DETACH; +unsigned IOCTL_MLX_RESCAN_DRIVES = MLX_RESCAN_DRIVES; +unsigned IOCTL_MLX_PAUSE_CHANNEL = MLX_PAUSE_CHANNEL; +unsigned IOCTL_MLX_COMMAND = MLX_COMMAND; +unsigned IOCTL_MLX_REBUILDASYNC = MLX_REBUILDASYNC; +unsigned IOCTL_MLX_REBUILDSTAT = MLX_REBUILDSTAT; +unsigned IOCTL_MLX_GET_SYSDRIVE = MLX_GET_SYSDRIVE; +unsigned IOCTL_MLX_GET_CINFO = MLX_GET_CINFO; +unsigned IOCTL_NVME_PASSTHROUGH_CMD = NVME_PASSTHROUGH_CMD; +unsigned IOCTL_FWCFGIO_SET_INDEX = FWCFGIO_SET_INDEX; +unsigned IOCTL_IRDA_RESET_PARAMS = IRDA_RESET_PARAMS; +unsigned IOCTL_IRDA_SET_PARAMS = IRDA_SET_PARAMS; +unsigned IOCTL_IRDA_GET_SPEEDMASK = IRDA_GET_SPEEDMASK; +unsigned IOCTL_IRDA_GET_TURNAROUNDMASK = IRDA_GET_TURNAROUNDMASK; +unsigned IOCTL_IRFRAMETTY_GET_DEVICE = IRFRAMETTY_GET_DEVICE; +unsigned IOCTL_IRFRAMETTY_GET_DONGLE = IRFRAMETTY_GET_DONGLE; +unsigned IOCTL_IRFRAMETTY_SET_DONGLE = IRFRAMETTY_SET_DONGLE; +unsigned IOCTL_ISV_CMD = ISV_CMD; +unsigned IOCTL_WTQICMD = WTQICMD; +unsigned IOCTL_ISCSI_GET_VERSION = ISCSI_GET_VERSION; +unsigned IOCTL_ISCSI_LOGIN = ISCSI_LOGIN; +unsigned IOCTL_ISCSI_LOGOUT = ISCSI_LOGOUT; +unsigned IOCTL_ISCSI_ADD_CONNECTION = ISCSI_ADD_CONNECTION; +unsigned IOCTL_ISCSI_RESTORE_CONNECTION = ISCSI_RESTORE_CONNECTION; +unsigned IOCTL_ISCSI_REMOVE_CONNECTION = ISCSI_REMOVE_CONNECTION; +unsigned IOCTL_ISCSI_CONNECTION_STATUS = ISCSI_CONNECTION_STATUS; +unsigned IOCTL_ISCSI_SEND_TARGETS = ISCSI_SEND_TARGETS; +unsigned IOCTL_ISCSI_SET_NODE_NAME = ISCSI_SET_NODE_NAME; +unsigned IOCTL_ISCSI_IO_COMMAND = ISCSI_IO_COMMAND; +unsigned IOCTL_ISCSI_REGISTER_EVENT = ISCSI_REGISTER_EVENT; +unsigned IOCTL_ISCSI_DEREGISTER_EVENT = ISCSI_DEREGISTER_EVENT; +unsigned IOCTL_ISCSI_WAIT_EVENT = ISCSI_WAIT_EVENT; +unsigned IOCTL_ISCSI_POLL_EVENT = ISCSI_POLL_EVENT; +unsigned IOCTL_OFIOCGET = OFIOCGET; +unsigned IOCTL_OFIOCSET = OFIOCSET; +unsigned IOCTL_OFIOCNEXTPROP = OFIOCNEXTPROP; +unsigned IOCTL_OFIOCGETOPTNODE = OFIOCGETOPTNODE; +unsigned IOCTL_OFIOCGETNEXT = OFIOCGETNEXT; +unsigned IOCTL_OFIOCGETCHILD = OFIOCGETCHILD; +unsigned IOCTL_OFIOCFINDDEVICE = OFIOCFINDDEVICE; +unsigned IOCTL_AMR_IO_VERSION = AMR_IO_VERSION; +unsigned IOCTL_AMR_IO_COMMAND = AMR_IO_COMMAND; +unsigned IOCTL_MLYIO_COMMAND = MLYIO_COMMAND; +unsigned IOCTL_MLYIO_HEALTH = MLYIO_HEALTH; +unsigned IOCTL_PCI_IOC_CFGREAD = PCI_IOC_CFGREAD; +unsigned IOCTL_PCI_IOC_CFGWRITE = PCI_IOC_CFGWRITE; +unsigned IOCTL_PCI_IOC_BDF_CFGREAD = PCI_IOC_BDF_CFGREAD; +unsigned IOCTL_PCI_IOC_BDF_CFGWRITE = PCI_IOC_BDF_CFGWRITE; +unsigned IOCTL_PCI_IOC_BUSINFO = PCI_IOC_BUSINFO; +unsigned IOCTL_PCI_IOC_DRVNAME = PCI_IOC_DRVNAME; +unsigned IOCTL_PCI_IOC_DRVNAMEONBUS = PCI_IOC_DRVNAMEONBUS; +unsigned IOCTL_TWEIO_COMMAND = TWEIO_COMMAND; +unsigned IOCTL_TWEIO_STATS = TWEIO_STATS; +unsigned IOCTL_TWEIO_AEN_POLL = TWEIO_AEN_POLL; +unsigned IOCTL_TWEIO_AEN_WAIT = TWEIO_AEN_WAIT; +unsigned IOCTL_TWEIO_SET_PARAM = TWEIO_SET_PARAM; +unsigned IOCTL_TWEIO_GET_PARAM = TWEIO_GET_PARAM; +unsigned IOCTL_TWEIO_RESET = TWEIO_RESET; +unsigned IOCTL_TWEIO_ADD_UNIT = TWEIO_ADD_UNIT; +unsigned IOCTL_TWEIO_DEL_UNIT = TWEIO_DEL_UNIT; +unsigned IOCTL_SIOCSCNWDOMAIN = SIOCSCNWDOMAIN; +unsigned IOCTL_SIOCGCNWDOMAIN = SIOCGCNWDOMAIN; +unsigned IOCTL_SIOCSCNWKEY = SIOCSCNWKEY; +unsigned IOCTL_SIOCGCNWSTATUS = SIOCGCNWSTATUS; +unsigned IOCTL_SIOCGCNWSTATS = SIOCGCNWSTATS; +unsigned IOCTL_SIOCGCNWTRAIL = SIOCGCNWTRAIL; +unsigned IOCTL_SIOCGRAYSIGLEV = SIOCGRAYSIGLEV; +unsigned IOCTL_RAIDFRAME_SHUTDOWN = RAIDFRAME_SHUTDOWN; +unsigned IOCTL_RAIDFRAME_TUR = RAIDFRAME_TUR; +unsigned IOCTL_RAIDFRAME_FAIL_DISK = RAIDFRAME_FAIL_DISK; +unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS = RAIDFRAME_CHECK_RECON_STATUS; +unsigned IOCTL_RAIDFRAME_REWRITEPARITY = RAIDFRAME_REWRITEPARITY; +unsigned IOCTL_RAIDFRAME_COPYBACK = RAIDFRAME_COPYBACK; +unsigned IOCTL_RAIDFRAME_SPARET_WAIT = RAIDFRAME_SPARET_WAIT; +unsigned IOCTL_RAIDFRAME_SEND_SPARET = RAIDFRAME_SEND_SPARET; +unsigned IOCTL_RAIDFRAME_ABORT_SPARET_WAIT = RAIDFRAME_ABORT_SPARET_WAIT; +unsigned IOCTL_RAIDFRAME_START_ATRACE = RAIDFRAME_START_ATRACE; +unsigned IOCTL_RAIDFRAME_STOP_ATRACE = RAIDFRAME_STOP_ATRACE; +unsigned IOCTL_RAIDFRAME_GET_SIZE = RAIDFRAME_GET_SIZE; +unsigned IOCTL_RAIDFRAME_RESET_ACCTOTALS = RAIDFRAME_RESET_ACCTOTALS; +unsigned IOCTL_RAIDFRAME_KEEP_ACCTOTALS = RAIDFRAME_KEEP_ACCTOTALS; +unsigned IOCTL_RAIDFRAME_GET_COMPONENT_LABEL = RAIDFRAME_GET_COMPONENT_LABEL; +unsigned IOCTL_RAIDFRAME_SET_COMPONENT_LABEL = RAIDFRAME_SET_COMPONENT_LABEL; +unsigned IOCTL_RAIDFRAME_INIT_LABELS = RAIDFRAME_INIT_LABELS; +unsigned IOCTL_RAIDFRAME_ADD_HOT_SPARE = RAIDFRAME_ADD_HOT_SPARE; +unsigned IOCTL_RAIDFRAME_REMOVE_HOT_SPARE = RAIDFRAME_REMOVE_HOT_SPARE; +unsigned IOCTL_RAIDFRAME_REBUILD_IN_PLACE = RAIDFRAME_REBUILD_IN_PLACE; +unsigned IOCTL_RAIDFRAME_CHECK_PARITY = RAIDFRAME_CHECK_PARITY; +unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS = + RAIDFRAME_CHECK_PARITYREWRITE_STATUS; +unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS = + RAIDFRAME_CHECK_COPYBACK_STATUS; +unsigned IOCTL_RAIDFRAME_SET_AUTOCONFIG = RAIDFRAME_SET_AUTOCONFIG; +unsigned IOCTL_RAIDFRAME_SET_ROOT = RAIDFRAME_SET_ROOT; +unsigned IOCTL_RAIDFRAME_DELETE_COMPONENT = RAIDFRAME_DELETE_COMPONENT; +unsigned IOCTL_RAIDFRAME_INCORPORATE_HOT_SPARE = + RAIDFRAME_INCORPORATE_HOT_SPARE; +unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS_EXT = + RAIDFRAME_CHECK_RECON_STATUS_EXT; +unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT = + RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT; +unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS_EXT = + RAIDFRAME_CHECK_COPYBACK_STATUS_EXT; +unsigned IOCTL_RAIDFRAME_CONFIGURE = RAIDFRAME_CONFIGURE; +unsigned IOCTL_RAIDFRAME_GET_INFO = RAIDFRAME_GET_INFO; +unsigned IOCTL_RAIDFRAME_PARITYMAP_STATUS = RAIDFRAME_PARITYMAP_STATUS; +unsigned IOCTL_RAIDFRAME_PARITYMAP_GET_DISABLE = + RAIDFRAME_PARITYMAP_GET_DISABLE; +unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_DISABLE = + RAIDFRAME_PARITYMAP_SET_DISABLE; +unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_PARAMS = RAIDFRAME_PARITYMAP_SET_PARAMS; +unsigned IOCTL_RAIDFRAME_SET_LAST_UNIT = RAIDFRAME_SET_LAST_UNIT; +unsigned IOCTL_MBPPIOCSPARAM = MBPPIOCSPARAM; +unsigned IOCTL_MBPPIOCGPARAM = MBPPIOCGPARAM; +unsigned IOCTL_MBPPIOCGSTAT = MBPPIOCGSTAT; +unsigned IOCTL_SESIOC_GETNOBJ = SESIOC_GETNOBJ; +unsigned IOCTL_SESIOC_GETOBJMAP = SESIOC_GETOBJMAP; +unsigned IOCTL_SESIOC_GETENCSTAT = SESIOC_GETENCSTAT; +unsigned IOCTL_SESIOC_SETENCSTAT = SESIOC_SETENCSTAT; +unsigned IOCTL_SESIOC_GETOBJSTAT = SESIOC_GETOBJSTAT; +unsigned IOCTL_SESIOC_SETOBJSTAT = SESIOC_SETOBJSTAT; +unsigned IOCTL_SESIOC_GETTEXT = SESIOC_GETTEXT; +unsigned IOCTL_SESIOC_INIT = SESIOC_INIT; +unsigned IOCTL_SUN_DKIOCGGEOM = SUN_DKIOCGGEOM; +unsigned IOCTL_SUN_DKIOCINFO = SUN_DKIOCINFO; +unsigned IOCTL_SUN_DKIOCGPART = SUN_DKIOCGPART; +unsigned IOCTL_FBIOGTYPE = FBIOGTYPE; +unsigned IOCTL_FBIOPUTCMAP = FBIOPUTCMAP; +unsigned IOCTL_FBIOGETCMAP = FBIOGETCMAP; +unsigned IOCTL_FBIOGATTR = FBIOGATTR; +unsigned IOCTL_FBIOSVIDEO = FBIOSVIDEO; +unsigned IOCTL_FBIOGVIDEO = FBIOGVIDEO; +unsigned IOCTL_FBIOSCURSOR = FBIOSCURSOR; +unsigned IOCTL_FBIOGCURSOR = FBIOGCURSOR; +unsigned IOCTL_FBIOSCURPOS = FBIOSCURPOS; +unsigned IOCTL_FBIOGCURPOS = FBIOGCURPOS; +unsigned IOCTL_FBIOGCURMAX = FBIOGCURMAX; +unsigned IOCTL_KIOCTRANS = KIOCTRANS; +unsigned IOCTL_KIOCSETKEY = KIOCSETKEY; +unsigned IOCTL_KIOCGETKEY = KIOCGETKEY; +unsigned IOCTL_KIOCGTRANS = KIOCGTRANS; +unsigned IOCTL_KIOCCMD = KIOCCMD; +unsigned IOCTL_KIOCTYPE = KIOCTYPE; +unsigned IOCTL_KIOCSDIRECT = KIOCSDIRECT; +unsigned IOCTL_KIOCSKEY = KIOCSKEY; +unsigned IOCTL_KIOCGKEY = KIOCGKEY; +unsigned IOCTL_KIOCSLED = KIOCSLED; +unsigned IOCTL_KIOCGLED = KIOCGLED; +unsigned IOCTL_KIOCLAYOUT = KIOCLAYOUT; +unsigned IOCTL_VUIDSFORMAT = VUIDSFORMAT; +unsigned IOCTL_VUIDGFORMAT = VUIDGFORMAT; +unsigned IOCTL_STICIO_GXINFO = STICIO_GXINFO; +unsigned IOCTL_STICIO_RESET = STICIO_RESET; +unsigned IOCTL_STICIO_STARTQ = STICIO_STARTQ; +unsigned IOCTL_STICIO_STOPQ = STICIO_STOPQ; +unsigned IOCTL_UKYOPON_IDENTIFY = UKYOPON_IDENTIFY; +unsigned IOCTL_URIO_SEND_COMMAND = URIO_SEND_COMMAND; +unsigned IOCTL_URIO_RECV_COMMAND = URIO_RECV_COMMAND; +unsigned IOCTL_USB_REQUEST = USB_REQUEST; +unsigned IOCTL_USB_SETDEBUG = USB_SETDEBUG; +unsigned IOCTL_USB_DISCOVER = USB_DISCOVER; +unsigned IOCTL_USB_DEVICEINFO = USB_DEVICEINFO; +unsigned IOCTL_USB_DEVICEINFO_OLD = USB_DEVICEINFO_OLD; +unsigned IOCTL_USB_DEVICESTATS = USB_DEVICESTATS; +unsigned IOCTL_USB_GET_REPORT_DESC = USB_GET_REPORT_DESC; +unsigned IOCTL_USB_SET_IMMED = USB_SET_IMMED; +unsigned IOCTL_USB_GET_REPORT = USB_GET_REPORT; +unsigned IOCTL_USB_SET_REPORT = USB_SET_REPORT; +unsigned IOCTL_USB_GET_REPORT_ID = USB_GET_REPORT_ID; +unsigned IOCTL_USB_GET_CONFIG = USB_GET_CONFIG; +unsigned IOCTL_USB_SET_CONFIG = USB_SET_CONFIG; +unsigned IOCTL_USB_GET_ALTINTERFACE = USB_GET_ALTINTERFACE; +unsigned IOCTL_USB_SET_ALTINTERFACE = USB_SET_ALTINTERFACE; +unsigned IOCTL_USB_GET_NO_ALT = USB_GET_NO_ALT; +unsigned IOCTL_USB_GET_DEVICE_DESC = USB_GET_DEVICE_DESC; +unsigned IOCTL_USB_GET_CONFIG_DESC = USB_GET_CONFIG_DESC; +unsigned IOCTL_USB_GET_INTERFACE_DESC = USB_GET_INTERFACE_DESC; +unsigned IOCTL_USB_GET_ENDPOINT_DESC = USB_GET_ENDPOINT_DESC; +unsigned IOCTL_USB_GET_FULL_DESC = USB_GET_FULL_DESC; +unsigned IOCTL_USB_GET_STRING_DESC = USB_GET_STRING_DESC; +unsigned IOCTL_USB_DO_REQUEST = USB_DO_REQUEST; +unsigned IOCTL_USB_GET_DEVICEINFO = USB_GET_DEVICEINFO; +unsigned IOCTL_USB_GET_DEVICEINFO_OLD = USB_GET_DEVICEINFO_OLD; +unsigned IOCTL_USB_SET_SHORT_XFER = USB_SET_SHORT_XFER; +unsigned IOCTL_USB_SET_TIMEOUT = USB_SET_TIMEOUT; +unsigned IOCTL_USB_SET_BULK_RA = USB_SET_BULK_RA; +unsigned IOCTL_USB_SET_BULK_WB = USB_SET_BULK_WB; +unsigned IOCTL_USB_SET_BULK_RA_OPT = USB_SET_BULK_RA_OPT; +unsigned IOCTL_USB_SET_BULK_WB_OPT = USB_SET_BULK_WB_OPT; +unsigned IOCTL_USB_GET_CM_OVER_DATA = USB_GET_CM_OVER_DATA; +unsigned IOCTL_USB_SET_CM_OVER_DATA = USB_SET_CM_OVER_DATA; +unsigned IOCTL_UTOPPYIOTURBO = UTOPPYIOTURBO; +unsigned IOCTL_UTOPPYIOCANCEL = UTOPPYIOCANCEL; +unsigned IOCTL_UTOPPYIOREBOOT = UTOPPYIOREBOOT; +unsigned IOCTL_UTOPPYIOSTATS = UTOPPYIOSTATS; +unsigned IOCTL_UTOPPYIORENAME = UTOPPYIORENAME; +unsigned IOCTL_UTOPPYIOMKDIR = UTOPPYIOMKDIR; +unsigned IOCTL_UTOPPYIODELETE = UTOPPYIODELETE; +unsigned IOCTL_UTOPPYIOREADDIR = UTOPPYIOREADDIR; +unsigned IOCTL_UTOPPYIOREADFILE = UTOPPYIOREADFILE; +unsigned IOCTL_UTOPPYIOWRITEFILE = UTOPPYIOWRITEFILE; +unsigned IOCTL_DIOSXDCMD = DIOSXDCMD; +unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; +unsigned IOCTL_VT_SETMODE = VT_SETMODE; +unsigned IOCTL_VT_GETMODE = VT_GETMODE; +unsigned IOCTL_VT_RELDISP = VT_RELDISP; +unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; +unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; +unsigned IOCTL_VT_GETACTIVE = VT_GETACTIVE; +unsigned IOCTL_VT_GETSTATE = VT_GETSTATE; +unsigned IOCTL_KDGETKBENT = KDGETKBENT; +unsigned IOCTL_KDGKBMODE = KDGKBMODE; +unsigned IOCTL_KDSKBMODE = KDSKBMODE; +unsigned IOCTL_KDMKTONE = KDMKTONE; +unsigned IOCTL_KDSETMODE = KDSETMODE; +unsigned IOCTL_KDENABIO = KDENABIO; +unsigned IOCTL_KDDISABIO = KDDISABIO; +unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; +unsigned IOCTL_KDGETLED = KDGETLED; +unsigned IOCTL_KDSETLED = KDSETLED; +unsigned IOCTL_KDSETRAD = KDSETRAD; +unsigned IOCTL_VGAPCVTID = VGAPCVTID; +unsigned IOCTL_CONS_GETVERS = CONS_GETVERS; +unsigned IOCTL_WSKBDIO_GTYPE = WSKBDIO_GTYPE; +unsigned IOCTL_WSKBDIO_BELL = WSKBDIO_BELL; +unsigned IOCTL_WSKBDIO_COMPLEXBELL = WSKBDIO_COMPLEXBELL; +unsigned IOCTL_WSKBDIO_SETBELL = WSKBDIO_SETBELL; +unsigned IOCTL_WSKBDIO_GETBELL = WSKBDIO_GETBELL; +unsigned IOCTL_WSKBDIO_SETDEFAULTBELL = WSKBDIO_SETDEFAULTBELL; +unsigned IOCTL_WSKBDIO_GETDEFAULTBELL = WSKBDIO_GETDEFAULTBELL; +unsigned IOCTL_WSKBDIO_SETKEYREPEAT = WSKBDIO_SETKEYREPEAT; +unsigned IOCTL_WSKBDIO_GETKEYREPEAT = WSKBDIO_GETKEYREPEAT; +unsigned IOCTL_WSKBDIO_SETDEFAULTKEYREPEAT = WSKBDIO_SETDEFAULTKEYREPEAT; +unsigned IOCTL_WSKBDIO_GETDEFAULTKEYREPEAT = WSKBDIO_GETDEFAULTKEYREPEAT; +unsigned IOCTL_WSKBDIO_SETLEDS = WSKBDIO_SETLEDS; +unsigned IOCTL_WSKBDIO_GETLEDS = WSKBDIO_GETLEDS; +unsigned IOCTL_WSKBDIO_GETMAP = WSKBDIO_GETMAP; +unsigned IOCTL_WSKBDIO_SETMAP = WSKBDIO_SETMAP; +unsigned IOCTL_WSKBDIO_GETENCODING = WSKBDIO_GETENCODING; +unsigned IOCTL_WSKBDIO_SETENCODING = WSKBDIO_SETENCODING; +unsigned IOCTL_WSKBDIO_SETMODE = WSKBDIO_SETMODE; +unsigned IOCTL_WSKBDIO_GETMODE = WSKBDIO_GETMODE; +unsigned IOCTL_WSKBDIO_SETKEYCLICK = WSKBDIO_SETKEYCLICK; +unsigned IOCTL_WSKBDIO_GETKEYCLICK = WSKBDIO_GETKEYCLICK; +unsigned IOCTL_WSKBDIO_GETSCROLL = WSKBDIO_GETSCROLL; +unsigned IOCTL_WSKBDIO_SETSCROLL = WSKBDIO_SETSCROLL; +unsigned IOCTL_WSKBDIO_SETVERSION = WSKBDIO_SETVERSION; +unsigned IOCTL_WSMOUSEIO_GTYPE = WSMOUSEIO_GTYPE; +unsigned IOCTL_WSMOUSEIO_SRES = WSMOUSEIO_SRES; +unsigned IOCTL_WSMOUSEIO_SSCALE = WSMOUSEIO_SSCALE; +unsigned IOCTL_WSMOUSEIO_SRATE = WSMOUSEIO_SRATE; +unsigned IOCTL_WSMOUSEIO_SCALIBCOORDS = WSMOUSEIO_SCALIBCOORDS; +unsigned IOCTL_WSMOUSEIO_GCALIBCOORDS = WSMOUSEIO_GCALIBCOORDS; +unsigned IOCTL_WSMOUSEIO_GETID = WSMOUSEIO_GETID; +unsigned IOCTL_WSMOUSEIO_GETREPEAT = WSMOUSEIO_GETREPEAT; +unsigned IOCTL_WSMOUSEIO_SETREPEAT = WSMOUSEIO_SETREPEAT; +unsigned IOCTL_WSMOUSEIO_SETVERSION = WSMOUSEIO_SETVERSION; +unsigned IOCTL_WSDISPLAYIO_GTYPE = WSDISPLAYIO_GTYPE; +unsigned IOCTL_WSDISPLAYIO_GINFO = WSDISPLAYIO_GINFO; +unsigned IOCTL_WSDISPLAYIO_GETCMAP = WSDISPLAYIO_GETCMAP; +unsigned IOCTL_WSDISPLAYIO_PUTCMAP = WSDISPLAYIO_PUTCMAP; +unsigned IOCTL_WSDISPLAYIO_GVIDEO = WSDISPLAYIO_GVIDEO; +unsigned IOCTL_WSDISPLAYIO_SVIDEO = WSDISPLAYIO_SVIDEO; +unsigned IOCTL_WSDISPLAYIO_GCURPOS = WSDISPLAYIO_GCURPOS; +unsigned IOCTL_WSDISPLAYIO_SCURPOS = WSDISPLAYIO_SCURPOS; +unsigned IOCTL_WSDISPLAYIO_GCURMAX = WSDISPLAYIO_GCURMAX; +unsigned IOCTL_WSDISPLAYIO_GCURSOR = WSDISPLAYIO_GCURSOR; +unsigned IOCTL_WSDISPLAYIO_SCURSOR = WSDISPLAYIO_SCURSOR; +unsigned IOCTL_WSDISPLAYIO_GMODE = WSDISPLAYIO_GMODE; +unsigned IOCTL_WSDISPLAYIO_SMODE = WSDISPLAYIO_SMODE; +unsigned IOCTL_WSDISPLAYIO_LDFONT = WSDISPLAYIO_LDFONT; +unsigned IOCTL_WSDISPLAYIO_ADDSCREEN = WSDISPLAYIO_ADDSCREEN; +unsigned IOCTL_WSDISPLAYIO_DELSCREEN = WSDISPLAYIO_DELSCREEN; +unsigned IOCTL_WSDISPLAYIO_SFONT = WSDISPLAYIO_SFONT; +unsigned IOCTL__O_WSDISPLAYIO_SETKEYBOARD = _O_WSDISPLAYIO_SETKEYBOARD; +unsigned IOCTL_WSDISPLAYIO_GETPARAM = WSDISPLAYIO_GETPARAM; +unsigned IOCTL_WSDISPLAYIO_SETPARAM = WSDISPLAYIO_SETPARAM; +unsigned IOCTL_WSDISPLAYIO_GETACTIVESCREEN = WSDISPLAYIO_GETACTIVESCREEN; +unsigned IOCTL_WSDISPLAYIO_GETWSCHAR = WSDISPLAYIO_GETWSCHAR; +unsigned IOCTL_WSDISPLAYIO_PUTWSCHAR = WSDISPLAYIO_PUTWSCHAR; +unsigned IOCTL_WSDISPLAYIO_DGSCROLL = WSDISPLAYIO_DGSCROLL; +unsigned IOCTL_WSDISPLAYIO_DSSCROLL = WSDISPLAYIO_DSSCROLL; +unsigned IOCTL_WSDISPLAYIO_GMSGATTRS = WSDISPLAYIO_GMSGATTRS; +unsigned IOCTL_WSDISPLAYIO_SMSGATTRS = WSDISPLAYIO_SMSGATTRS; +unsigned IOCTL_WSDISPLAYIO_GBORDER = WSDISPLAYIO_GBORDER; +unsigned IOCTL_WSDISPLAYIO_SBORDER = WSDISPLAYIO_SBORDER; +unsigned IOCTL_WSDISPLAYIO_SSPLASH = WSDISPLAYIO_SSPLASH; +unsigned IOCTL_WSDISPLAYIO_SPROGRESS = WSDISPLAYIO_SPROGRESS; +unsigned IOCTL_WSDISPLAYIO_LINEBYTES = WSDISPLAYIO_LINEBYTES; +unsigned IOCTL_WSDISPLAYIO_SETVERSION = WSDISPLAYIO_SETVERSION; +unsigned IOCTL_WSMUXIO_ADD_DEVICE = WSMUXIO_ADD_DEVICE; +unsigned IOCTL_WSMUXIO_REMOVE_DEVICE = WSMUXIO_REMOVE_DEVICE; +unsigned IOCTL_WSMUXIO_LIST_DEVICES = WSMUXIO_LIST_DEVICES; +unsigned IOCTL_WSMUXIO_INJECTEVENT = WSMUXIO_INJECTEVENT; +unsigned IOCTL_WSDISPLAYIO_GET_BUSID = WSDISPLAYIO_GET_BUSID; +unsigned IOCTL_WSDISPLAYIO_GET_EDID = WSDISPLAYIO_GET_EDID; +unsigned IOCTL_WSDISPLAYIO_SET_POLLING = WSDISPLAYIO_SET_POLLING; +unsigned IOCTL_WSDISPLAYIO_GET_FBINFO = WSDISPLAYIO_GET_FBINFO; +unsigned IOCTL_WSDISPLAYIO_DOBLIT = WSDISPLAYIO_DOBLIT; +unsigned IOCTL_WSDISPLAYIO_WAITBLIT = WSDISPLAYIO_WAITBLIT; +unsigned IOCTL_BIOCLOCATE = BIOCLOCATE; +unsigned IOCTL_BIOCINQ = BIOCINQ; +unsigned IOCTL_BIOCDISK_NOVOL = BIOCDISK_NOVOL; +unsigned IOCTL_BIOCDISK = BIOCDISK; +unsigned IOCTL_BIOCVOL = BIOCVOL; +unsigned IOCTL_BIOCALARM = BIOCALARM; +unsigned IOCTL_BIOCBLINK = BIOCBLINK; +unsigned IOCTL_BIOCSETSTATE = BIOCSETSTATE; +unsigned IOCTL_BIOCVOLOPS = BIOCVOLOPS; +unsigned IOCTL_MD_GETCONF = MD_GETCONF; +unsigned IOCTL_MD_SETCONF = MD_SETCONF; +unsigned IOCTL_CCDIOCSET = CCDIOCSET; +unsigned IOCTL_CCDIOCCLR = CCDIOCCLR; +unsigned IOCTL_CGDIOCSET = CGDIOCSET; +unsigned IOCTL_CGDIOCCLR = CGDIOCCLR; +unsigned IOCTL_CGDIOCGET = CGDIOCGET; +unsigned IOCTL_FSSIOCSET = FSSIOCSET; +unsigned IOCTL_FSSIOCGET = FSSIOCGET; +unsigned IOCTL_FSSIOCCLR = FSSIOCCLR; +unsigned IOCTL_FSSIOFSET = FSSIOFSET; +unsigned IOCTL_FSSIOFGET = FSSIOFGET; +unsigned IOCTL_BTDEV_ATTACH = BTDEV_ATTACH; +unsigned IOCTL_BTDEV_DETACH = BTDEV_DETACH; +unsigned IOCTL_BTSCO_GETINFO = BTSCO_GETINFO; +unsigned IOCTL_KTTCP_IO_SEND = KTTCP_IO_SEND; +unsigned IOCTL_KTTCP_IO_RECV = KTTCP_IO_RECV; +unsigned IOCTL_IOC_LOCKSTAT_GVERSION = IOC_LOCKSTAT_GVERSION; +unsigned IOCTL_IOC_LOCKSTAT_ENABLE = IOC_LOCKSTAT_ENABLE; +unsigned IOCTL_IOC_LOCKSTAT_DISABLE = IOC_LOCKSTAT_DISABLE; +unsigned IOCTL_VNDIOCSET = VNDIOCSET; +unsigned IOCTL_VNDIOCCLR = VNDIOCCLR; +unsigned IOCTL_VNDIOCGET = VNDIOCGET; +unsigned IOCTL_SPKRTONE = SPKRTONE; +unsigned IOCTL_SPKRTUNE = SPKRTUNE; +unsigned IOCTL_SPKRGETVOL = SPKRGETVOL; +unsigned IOCTL_SPKRSETVOL = SPKRSETVOL; +#if defined(__x86_64__) +unsigned IOCTL_NVMM_IOC_CAPABILITY = NVMM_IOC_CAPABILITY; +unsigned IOCTL_NVMM_IOC_MACHINE_CREATE = NVMM_IOC_MACHINE_CREATE; +unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY = NVMM_IOC_MACHINE_DESTROY; +unsigned IOCTL_NVMM_IOC_MACHINE_CONFIGURE = NVMM_IOC_MACHINE_CONFIGURE; +unsigned IOCTL_NVMM_IOC_VCPU_CREATE = NVMM_IOC_VCPU_CREATE; +unsigned IOCTL_NVMM_IOC_VCPU_DESTROY = NVMM_IOC_VCPU_DESTROY; +unsigned IOCTL_NVMM_IOC_VCPU_SETSTATE = NVMM_IOC_VCPU_SETSTATE; +unsigned IOCTL_NVMM_IOC_VCPU_GETSTATE = NVMM_IOC_VCPU_GETSTATE; +unsigned IOCTL_NVMM_IOC_VCPU_INJECT = NVMM_IOC_VCPU_INJECT; +unsigned IOCTL_NVMM_IOC_VCPU_RUN = NVMM_IOC_VCPU_RUN; +unsigned IOCTL_NVMM_IOC_GPA_MAP = NVMM_IOC_GPA_MAP; +unsigned IOCTL_NVMM_IOC_GPA_UNMAP = NVMM_IOC_GPA_UNMAP; +unsigned IOCTL_NVMM_IOC_HVA_MAP = NVMM_IOC_HVA_MAP; +unsigned IOCTL_NVMM_IOC_HVA_UNMAP = NVMM_IOC_HVA_UNMAP; +unsigned IOCTL_NVMM_IOC_CTL = NVMM_IOC_CTL; +#endif +unsigned IOCTL_SPI_IOCTL_CONFIGURE = SPI_IOCTL_CONFIGURE; +unsigned IOCTL_SPI_IOCTL_TRANSFER = SPI_IOCTL_TRANSFER; +unsigned IOCTL_AUTOFSREQUEST = AUTOFSREQUEST; +unsigned IOCTL_AUTOFSDONE = AUTOFSDONE; +unsigned IOCTL_BIOCGBLEN = BIOCGBLEN; +unsigned IOCTL_BIOCSBLEN = BIOCSBLEN; +unsigned IOCTL_BIOCSETF = BIOCSETF; +unsigned IOCTL_BIOCFLUSH = BIOCFLUSH; +unsigned IOCTL_BIOCPROMISC = BIOCPROMISC; +unsigned IOCTL_BIOCGDLT = BIOCGDLT; +unsigned IOCTL_BIOCGETIF = BIOCGETIF; +unsigned IOCTL_BIOCSETIF = BIOCSETIF; +unsigned IOCTL_BIOCGSTATS = BIOCGSTATS; +unsigned IOCTL_BIOCGSTATSOLD = BIOCGSTATSOLD; +unsigned IOCTL_BIOCIMMEDIATE = BIOCIMMEDIATE; +unsigned IOCTL_BIOCVERSION = BIOCVERSION; +unsigned IOCTL_BIOCSTCPF = BIOCSTCPF; +unsigned IOCTL_BIOCSUDPF = BIOCSUDPF; +unsigned IOCTL_BIOCGHDRCMPLT = BIOCGHDRCMPLT; +unsigned IOCTL_BIOCSHDRCMPLT = BIOCSHDRCMPLT; +unsigned IOCTL_BIOCSDLT = BIOCSDLT; +unsigned IOCTL_BIOCGDLTLIST = BIOCGDLTLIST; +unsigned IOCTL_BIOCGDIRECTION = BIOCGDIRECTION; +unsigned IOCTL_BIOCSDIRECTION = BIOCSDIRECTION; +unsigned IOCTL_BIOCSRTIMEOUT = BIOCSRTIMEOUT; +unsigned IOCTL_BIOCGRTIMEOUT = BIOCGRTIMEOUT; +unsigned IOCTL_BIOCGFEEDBACK = BIOCGFEEDBACK; +unsigned IOCTL_BIOCSFEEDBACK = BIOCSFEEDBACK; +unsigned IOCTL_GRESADDRS = GRESADDRS; +unsigned IOCTL_GRESADDRD = GRESADDRD; +unsigned IOCTL_GREGADDRS = GREGADDRS; +unsigned IOCTL_GREGADDRD = GREGADDRD; +unsigned IOCTL_GRESPROTO = GRESPROTO; +unsigned IOCTL_GREGPROTO = GREGPROTO; +unsigned IOCTL_GRESSOCK = GRESSOCK; +unsigned IOCTL_GREDSOCK = GREDSOCK; +unsigned IOCTL_PPPIOCGRAWIN = PPPIOCGRAWIN; +unsigned IOCTL_PPPIOCGFLAGS = PPPIOCGFLAGS; +unsigned IOCTL_PPPIOCSFLAGS = PPPIOCSFLAGS; +unsigned IOCTL_PPPIOCGASYNCMAP = PPPIOCGASYNCMAP; +unsigned IOCTL_PPPIOCSASYNCMAP = PPPIOCSASYNCMAP; +unsigned IOCTL_PPPIOCGUNIT = PPPIOCGUNIT; +unsigned IOCTL_PPPIOCGRASYNCMAP = PPPIOCGRASYNCMAP; +unsigned IOCTL_PPPIOCSRASYNCMAP = PPPIOCSRASYNCMAP; +unsigned IOCTL_PPPIOCGMRU = PPPIOCGMRU; +unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU; +unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID; +unsigned IOCTL_PPPIOCGXASYNCMAP = PPPIOCGXASYNCMAP; +unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP; +unsigned IOCTL_PPPIOCXFERUNIT = PPPIOCXFERUNIT; +unsigned IOCTL_PPPIOCSCOMPRESS = PPPIOCSCOMPRESS; +unsigned IOCTL_PPPIOCGNPMODE = PPPIOCGNPMODE; +unsigned IOCTL_PPPIOCSNPMODE = PPPIOCSNPMODE; +unsigned IOCTL_PPPIOCGIDLE = PPPIOCGIDLE; +unsigned IOCTL_PPPIOCGMTU = PPPIOCGMTU; +unsigned IOCTL_PPPIOCSMTU = PPPIOCSMTU; +unsigned IOCTL_SIOCGPPPSTATS = SIOCGPPPSTATS; +unsigned IOCTL_SIOCGPPPCSTATS = SIOCGPPPCSTATS; +unsigned IOCTL_IOC_NPF_VERSION = IOC_NPF_VERSION; +unsigned IOCTL_IOC_NPF_SWITCH = IOC_NPF_SWITCH; +unsigned IOCTL_IOC_NPF_LOAD = IOC_NPF_LOAD; +unsigned IOCTL_IOC_NPF_TABLE = IOC_NPF_TABLE; +unsigned IOCTL_IOC_NPF_STATS = IOC_NPF_STATS; +unsigned IOCTL_IOC_NPF_SAVE = IOC_NPF_SAVE; +unsigned IOCTL_IOC_NPF_RULE = IOC_NPF_RULE; +unsigned IOCTL_IOC_NPF_CONN_LOOKUP = IOC_NPF_CONN_LOOKUP; +unsigned IOCTL_PPPOESETPARMS = PPPOESETPARMS; +unsigned IOCTL_PPPOEGETPARMS = PPPOEGETPARMS; +unsigned IOCTL_PPPOEGETSESSION = PPPOEGETSESSION; +unsigned IOCTL_SPPPGETAUTHCFG = SPPPGETAUTHCFG; +unsigned IOCTL_SPPPSETAUTHCFG = SPPPSETAUTHCFG; +unsigned IOCTL_SPPPGETLCPCFG = SPPPGETLCPCFG; +unsigned IOCTL_SPPPSETLCPCFG = SPPPSETLCPCFG; +unsigned IOCTL_SPPPGETSTATUS = SPPPGETSTATUS; +unsigned IOCTL_SPPPGETSTATUSNCP = SPPPGETSTATUSNCP; +unsigned IOCTL_SPPPGETIDLETO = SPPPGETIDLETO; +unsigned IOCTL_SPPPSETIDLETO = SPPPSETIDLETO; +unsigned IOCTL_SPPPGETAUTHFAILURES = SPPPGETAUTHFAILURES; +unsigned IOCTL_SPPPSETAUTHFAILURE = SPPPSETAUTHFAILURE; +unsigned IOCTL_SPPPSETDNSOPTS = SPPPSETDNSOPTS; +unsigned IOCTL_SPPPGETDNSOPTS = SPPPGETDNSOPTS; +unsigned IOCTL_SPPPGETDNSADDRS = SPPPGETDNSADDRS; +unsigned IOCTL_SPPPSETKEEPALIVE = SPPPSETKEEPALIVE; +unsigned IOCTL_SPPPGETKEEPALIVE = SPPPGETKEEPALIVE; +unsigned IOCTL_SRT_GETNRT = SRT_GETNRT; +unsigned IOCTL_SRT_GETRT = SRT_GETRT; +unsigned IOCTL_SRT_SETRT = SRT_SETRT; +unsigned IOCTL_SRT_DELRT = SRT_DELRT; +unsigned IOCTL_SRT_SFLAGS = SRT_SFLAGS; +unsigned IOCTL_SRT_GFLAGS = SRT_GFLAGS; +unsigned IOCTL_SRT_SGFLAGS = SRT_SGFLAGS; +unsigned IOCTL_SRT_DEBUG = SRT_DEBUG; +unsigned IOCTL_TAPGIFNAME = TAPGIFNAME; +unsigned IOCTL_TUNSDEBUG = TUNSDEBUG; +unsigned IOCTL_TUNGDEBUG = TUNGDEBUG; +unsigned IOCTL_TUNSIFMODE = TUNSIFMODE; +unsigned IOCTL_TUNSLMODE = TUNSLMODE; +unsigned IOCTL_TUNSIFHEAD = TUNSIFHEAD; +unsigned IOCTL_TUNGIFHEAD = TUNGIFHEAD; +unsigned IOCTL_DIOCSTART = DIOCSTART; +unsigned IOCTL_DIOCSTOP = DIOCSTOP; +unsigned IOCTL_DIOCADDRULE = DIOCADDRULE; +unsigned IOCTL_DIOCGETRULES = DIOCGETRULES; +unsigned IOCTL_DIOCGETRULE = DIOCGETRULE; +unsigned IOCTL_DIOCSETLCK = DIOCSETLCK; +unsigned IOCTL_DIOCCLRSTATES = DIOCCLRSTATES; +unsigned IOCTL_DIOCGETSTATE = DIOCGETSTATE; +unsigned IOCTL_DIOCSETSTATUSIF = DIOCSETSTATUSIF; +unsigned IOCTL_DIOCGETSTATUS = DIOCGETSTATUS; +unsigned IOCTL_DIOCCLRSTATUS = DIOCCLRSTATUS; +unsigned IOCTL_DIOCNATLOOK = DIOCNATLOOK; +unsigned IOCTL_DIOCSETDEBUG = DIOCSETDEBUG; +unsigned IOCTL_DIOCGETSTATES = DIOCGETSTATES; +unsigned IOCTL_DIOCCHANGERULE = DIOCCHANGERULE; +unsigned IOCTL_DIOCSETTIMEOUT = DIOCSETTIMEOUT; +unsigned IOCTL_DIOCGETTIMEOUT = DIOCGETTIMEOUT; +unsigned IOCTL_DIOCADDSTATE = DIOCADDSTATE; +unsigned IOCTL_DIOCCLRRULECTRS = DIOCCLRRULECTRS; +unsigned IOCTL_DIOCGETLIMIT = DIOCGETLIMIT; +unsigned IOCTL_DIOCSETLIMIT = DIOCSETLIMIT; +unsigned IOCTL_DIOCKILLSTATES = DIOCKILLSTATES; +unsigned IOCTL_DIOCSTARTALTQ = DIOCSTARTALTQ; +unsigned IOCTL_DIOCSTOPALTQ = DIOCSTOPALTQ; +unsigned IOCTL_DIOCADDALTQ = DIOCADDALTQ; +unsigned IOCTL_DIOCGETALTQS = DIOCGETALTQS; +unsigned IOCTL_DIOCGETALTQ = DIOCGETALTQ; +unsigned IOCTL_DIOCCHANGEALTQ = DIOCCHANGEALTQ; +unsigned IOCTL_DIOCGETQSTATS = DIOCGETQSTATS; +unsigned IOCTL_DIOCBEGINADDRS = DIOCBEGINADDRS; +unsigned IOCTL_DIOCADDADDR = DIOCADDADDR; +unsigned IOCTL_DIOCGETADDRS = DIOCGETADDRS; +unsigned IOCTL_DIOCGETADDR = DIOCGETADDR; +unsigned IOCTL_DIOCCHANGEADDR = DIOCCHANGEADDR; +unsigned IOCTL_DIOCADDSTATES = DIOCADDSTATES; +unsigned IOCTL_DIOCGETRULESETS = DIOCGETRULESETS; +unsigned IOCTL_DIOCGETRULESET = DIOCGETRULESET; +unsigned IOCTL_DIOCRCLRTABLES = DIOCRCLRTABLES; +unsigned IOCTL_DIOCRADDTABLES = DIOCRADDTABLES; +unsigned IOCTL_DIOCRDELTABLES = DIOCRDELTABLES; +unsigned IOCTL_DIOCRGETTABLES = DIOCRGETTABLES; +unsigned IOCTL_DIOCRGETTSTATS = DIOCRGETTSTATS; +unsigned IOCTL_DIOCRCLRTSTATS = DIOCRCLRTSTATS; +unsigned IOCTL_DIOCRCLRADDRS = DIOCRCLRADDRS; +unsigned IOCTL_DIOCRADDADDRS = DIOCRADDADDRS; +unsigned IOCTL_DIOCRDELADDRS = DIOCRDELADDRS; +unsigned IOCTL_DIOCRSETADDRS = DIOCRSETADDRS; +unsigned IOCTL_DIOCRGETADDRS = DIOCRGETADDRS; +unsigned IOCTL_DIOCRGETASTATS = DIOCRGETASTATS; +unsigned IOCTL_DIOCRCLRASTATS = DIOCRCLRASTATS; +unsigned IOCTL_DIOCRTSTADDRS = DIOCRTSTADDRS; +unsigned IOCTL_DIOCRSETTFLAGS = DIOCRSETTFLAGS; +unsigned IOCTL_DIOCRINADEFINE = DIOCRINADEFINE; +unsigned IOCTL_DIOCOSFPFLUSH = DIOCOSFPFLUSH; +unsigned IOCTL_DIOCOSFPADD = DIOCOSFPADD; +unsigned IOCTL_DIOCOSFPGET = DIOCOSFPGET; +unsigned IOCTL_DIOCXBEGIN = DIOCXBEGIN; +unsigned IOCTL_DIOCXCOMMIT = DIOCXCOMMIT; +unsigned IOCTL_DIOCXROLLBACK = DIOCXROLLBACK; +unsigned IOCTL_DIOCGETSRCNODES = DIOCGETSRCNODES; +unsigned IOCTL_DIOCCLRSRCNODES = DIOCCLRSRCNODES; +unsigned IOCTL_DIOCSETHOSTID = DIOCSETHOSTID; +unsigned IOCTL_DIOCIGETIFACES = DIOCIGETIFACES; +unsigned IOCTL_DIOCSETIFFLAG = DIOCSETIFFLAG; +unsigned IOCTL_DIOCCLRIFFLAG = DIOCCLRIFFLAG; +unsigned IOCTL_DIOCKILLSRCNODES = DIOCKILLSRCNODES; +unsigned IOCTL_SLIOCGUNIT = SLIOCGUNIT; +unsigned IOCTL_SIOCGBTINFO = SIOCGBTINFO; +unsigned IOCTL_SIOCGBTINFOA = SIOCGBTINFOA; +unsigned IOCTL_SIOCNBTINFO = SIOCNBTINFO; +unsigned IOCTL_SIOCSBTFLAGS = SIOCSBTFLAGS; +unsigned IOCTL_SIOCSBTPOLICY = SIOCSBTPOLICY; +unsigned IOCTL_SIOCSBTPTYPE = SIOCSBTPTYPE; +unsigned IOCTL_SIOCGBTSTATS = SIOCGBTSTATS; +unsigned IOCTL_SIOCZBTSTATS = SIOCZBTSTATS; +unsigned IOCTL_SIOCBTDUMP = SIOCBTDUMP; +unsigned IOCTL_SIOCSBTSCOMTU = SIOCSBTSCOMTU; +unsigned IOCTL_SIOCGBTFEAT = SIOCGBTFEAT; +unsigned IOCTL_SIOCADNAT = SIOCADNAT; +unsigned IOCTL_SIOCRMNAT = SIOCRMNAT; +unsigned IOCTL_SIOCGNATS = SIOCGNATS; +unsigned IOCTL_SIOCGNATL = SIOCGNATL; +unsigned IOCTL_SIOCPURGENAT = SIOCPURGENAT; +unsigned IOCTL_SIOCCONNECTX = SIOCCONNECTX; +unsigned IOCTL_SIOCCONNECTXDEL = SIOCCONNECTXDEL; +unsigned IOCTL_SIOCSIFINFO_FLAGS = SIOCSIFINFO_FLAGS; +unsigned IOCTL_SIOCAADDRCTL_POLICY = SIOCAADDRCTL_POLICY; +unsigned IOCTL_SIOCDADDRCTL_POLICY = SIOCDADDRCTL_POLICY; +unsigned IOCTL_SMBIOC_OPENSESSION = SMBIOC_OPENSESSION; +unsigned IOCTL_SMBIOC_OPENSHARE = SMBIOC_OPENSHARE; +unsigned IOCTL_SMBIOC_REQUEST = SMBIOC_REQUEST; +unsigned IOCTL_SMBIOC_SETFLAGS = SMBIOC_SETFLAGS; +unsigned IOCTL_SMBIOC_LOOKUP = SMBIOC_LOOKUP; +unsigned IOCTL_SMBIOC_READ = SMBIOC_READ; +unsigned IOCTL_SMBIOC_WRITE = SMBIOC_WRITE; +unsigned IOCTL_AGPIOC_INFO = AGPIOC_INFO; +unsigned IOCTL_AGPIOC_ACQUIRE = AGPIOC_ACQUIRE; +unsigned IOCTL_AGPIOC_RELEASE = AGPIOC_RELEASE; +unsigned IOCTL_AGPIOC_SETUP = AGPIOC_SETUP; +unsigned IOCTL_AGPIOC_ALLOCATE = AGPIOC_ALLOCATE; +unsigned IOCTL_AGPIOC_DEALLOCATE = AGPIOC_DEALLOCATE; +unsigned IOCTL_AGPIOC_BIND = AGPIOC_BIND; +unsigned IOCTL_AGPIOC_UNBIND = AGPIOC_UNBIND; +unsigned IOCTL_AUDIO_GETINFO = AUDIO_GETINFO; +unsigned IOCTL_AUDIO_SETINFO = AUDIO_SETINFO; +unsigned IOCTL_AUDIO_DRAIN = AUDIO_DRAIN; +unsigned IOCTL_AUDIO_FLUSH = AUDIO_FLUSH; +unsigned IOCTL_AUDIO_WSEEK = AUDIO_WSEEK; +unsigned IOCTL_AUDIO_RERROR = AUDIO_RERROR; +unsigned IOCTL_AUDIO_GETDEV = AUDIO_GETDEV; +unsigned IOCTL_AUDIO_GETENC = AUDIO_GETENC; +unsigned IOCTL_AUDIO_GETFD = AUDIO_GETFD; +unsigned IOCTL_AUDIO_SETFD = AUDIO_SETFD; +unsigned IOCTL_AUDIO_PERROR = AUDIO_PERROR; +unsigned IOCTL_AUDIO_GETIOFFS = AUDIO_GETIOFFS; +unsigned IOCTL_AUDIO_GETOOFFS = AUDIO_GETOOFFS; +unsigned IOCTL_AUDIO_GETPROPS = AUDIO_GETPROPS; +unsigned IOCTL_AUDIO_GETBUFINFO = AUDIO_GETBUFINFO; +unsigned IOCTL_AUDIO_SETCHAN = AUDIO_SETCHAN; +unsigned IOCTL_AUDIO_GETCHAN = AUDIO_GETCHAN; +unsigned IOCTL_AUDIO_QUERYFORMAT = AUDIO_QUERYFORMAT; +unsigned IOCTL_AUDIO_GETFORMAT = AUDIO_GETFORMAT; +unsigned IOCTL_AUDIO_SETFORMAT = AUDIO_SETFORMAT; +unsigned IOCTL_AUDIO_MIXER_READ = AUDIO_MIXER_READ; +unsigned IOCTL_AUDIO_MIXER_WRITE = AUDIO_MIXER_WRITE; +unsigned IOCTL_AUDIO_MIXER_DEVINFO = AUDIO_MIXER_DEVINFO; +unsigned IOCTL_ATAIOCCOMMAND = ATAIOCCOMMAND; +unsigned IOCTL_ATABUSIOSCAN = ATABUSIOSCAN; +unsigned IOCTL_ATABUSIORESET = ATABUSIORESET; +unsigned IOCTL_ATABUSIODETACH = ATABUSIODETACH; +unsigned IOCTL_CDIOCPLAYTRACKS = CDIOCPLAYTRACKS; +unsigned IOCTL_CDIOCPLAYBLOCKS = CDIOCPLAYBLOCKS; +unsigned IOCTL_CDIOCREADSUBCHANNEL = CDIOCREADSUBCHANNEL; +unsigned IOCTL_CDIOREADTOCHEADER = CDIOREADTOCHEADER; +unsigned IOCTL_CDIOREADTOCENTRIES = CDIOREADTOCENTRIES; +unsigned IOCTL_CDIOREADMSADDR = CDIOREADMSADDR; +unsigned IOCTL_CDIOCSETPATCH = CDIOCSETPATCH; +unsigned IOCTL_CDIOCGETVOL = CDIOCGETVOL; +unsigned IOCTL_CDIOCSETVOL = CDIOCSETVOL; +unsigned IOCTL_CDIOCSETMONO = CDIOCSETMONO; +unsigned IOCTL_CDIOCSETSTEREO = CDIOCSETSTEREO; +unsigned IOCTL_CDIOCSETMUTE = CDIOCSETMUTE; +unsigned IOCTL_CDIOCSETLEFT = CDIOCSETLEFT; +unsigned IOCTL_CDIOCSETRIGHT = CDIOCSETRIGHT; +unsigned IOCTL_CDIOCSETDEBUG = CDIOCSETDEBUG; +unsigned IOCTL_CDIOCCLRDEBUG = CDIOCCLRDEBUG; +unsigned IOCTL_CDIOCPAUSE = CDIOCPAUSE; +unsigned IOCTL_CDIOCRESUME = CDIOCRESUME; +unsigned IOCTL_CDIOCRESET = CDIOCRESET; +unsigned IOCTL_CDIOCSTART = CDIOCSTART; +unsigned IOCTL_CDIOCSTOP = CDIOCSTOP; +unsigned IOCTL_CDIOCEJECT = CDIOCEJECT; +unsigned IOCTL_CDIOCALLOW = CDIOCALLOW; +unsigned IOCTL_CDIOCPREVENT = CDIOCPREVENT; +unsigned IOCTL_CDIOCCLOSE = CDIOCCLOSE; +unsigned IOCTL_CDIOCPLAYMSF = CDIOCPLAYMSF; +unsigned IOCTL_CDIOCLOADUNLOAD = CDIOCLOADUNLOAD; +unsigned IOCTL_CHIOMOVE = CHIOMOVE; +unsigned IOCTL_CHIOEXCHANGE = CHIOEXCHANGE; +unsigned IOCTL_CHIOPOSITION = CHIOPOSITION; +unsigned IOCTL_CHIOGPICKER = CHIOGPICKER; +unsigned IOCTL_CHIOSPICKER = CHIOSPICKER; +unsigned IOCTL_CHIOGPARAMS = CHIOGPARAMS; +unsigned IOCTL_CHIOIELEM = CHIOIELEM; +unsigned IOCTL_OCHIOGSTATUS = OCHIOGSTATUS; +unsigned IOCTL_CHIOGSTATUS = CHIOGSTATUS; +unsigned IOCTL_CHIOSVOLTAG = CHIOSVOLTAG; +unsigned IOCTL_CLOCKCTL_SETTIMEOFDAY = CLOCKCTL_SETTIMEOFDAY; +unsigned IOCTL_CLOCKCTL_ADJTIME = CLOCKCTL_ADJTIME; +unsigned IOCTL_CLOCKCTL_CLOCK_SETTIME = CLOCKCTL_CLOCK_SETTIME; +unsigned IOCTL_CLOCKCTL_NTP_ADJTIME = CLOCKCTL_NTP_ADJTIME; +unsigned IOCTL_IOC_CPU_SETSTATE = IOC_CPU_SETSTATE; +unsigned IOCTL_IOC_CPU_GETSTATE = IOC_CPU_GETSTATE; +unsigned IOCTL_IOC_CPU_GETCOUNT = IOC_CPU_GETCOUNT; +unsigned IOCTL_IOC_CPU_MAPID = IOC_CPU_MAPID; +unsigned IOCTL_IOC_CPU_UCODE_GET_VERSION = IOC_CPU_UCODE_GET_VERSION; +unsigned IOCTL_IOC_CPU_UCODE_APPLY = IOC_CPU_UCODE_APPLY; +unsigned IOCTL_DIOCGDINFO = DIOCGDINFO; +unsigned IOCTL_DIOCSDINFO = DIOCSDINFO; +unsigned IOCTL_DIOCWDINFO = DIOCWDINFO; +unsigned IOCTL_DIOCRFORMAT = DIOCRFORMAT; +unsigned IOCTL_DIOCWFORMAT = DIOCWFORMAT; +unsigned IOCTL_DIOCSSTEP = DIOCSSTEP; +unsigned IOCTL_DIOCSRETRIES = DIOCSRETRIES; +unsigned IOCTL_DIOCKLABEL = DIOCKLABEL; +unsigned IOCTL_DIOCWLABEL = DIOCWLABEL; +unsigned IOCTL_DIOCSBAD = DIOCSBAD; +unsigned IOCTL_DIOCEJECT = DIOCEJECT; +unsigned IOCTL_ODIOCEJECT = ODIOCEJECT; +unsigned IOCTL_DIOCLOCK = DIOCLOCK; +unsigned IOCTL_DIOCGDEFLABEL = DIOCGDEFLABEL; +unsigned IOCTL_DIOCCLRLABEL = DIOCCLRLABEL; +unsigned IOCTL_DIOCGCACHE = DIOCGCACHE; +unsigned IOCTL_DIOCSCACHE = DIOCSCACHE; +unsigned IOCTL_DIOCCACHESYNC = DIOCCACHESYNC; +unsigned IOCTL_DIOCBSLIST = DIOCBSLIST; +unsigned IOCTL_DIOCBSFLUSH = DIOCBSFLUSH; +unsigned IOCTL_DIOCAWEDGE = DIOCAWEDGE; +unsigned IOCTL_DIOCGWEDGEINFO = DIOCGWEDGEINFO; +unsigned IOCTL_DIOCDWEDGE = DIOCDWEDGE; +unsigned IOCTL_DIOCLWEDGES = DIOCLWEDGES; +unsigned IOCTL_DIOCGSTRATEGY = DIOCGSTRATEGY; +unsigned IOCTL_DIOCSSTRATEGY = DIOCSSTRATEGY; +unsigned IOCTL_DIOCGDISKINFO = DIOCGDISKINFO; +unsigned IOCTL_DIOCTUR = DIOCTUR; +unsigned IOCTL_DIOCMWEDGES = DIOCMWEDGES; +unsigned IOCTL_DIOCGSECTORSIZE = DIOCGSECTORSIZE; +unsigned IOCTL_DIOCGMEDIASIZE = DIOCGMEDIASIZE; +unsigned IOCTL_DIOCRMWEDGES = DIOCRMWEDGES; +unsigned IOCTL_DRVDETACHDEV = DRVDETACHDEV; +unsigned IOCTL_DRVRESCANBUS = DRVRESCANBUS; +unsigned IOCTL_DRVCTLCOMMAND = DRVCTLCOMMAND; +unsigned IOCTL_DRVRESUMEDEV = DRVRESUMEDEV; +unsigned IOCTL_DRVLISTDEV = DRVLISTDEV; +unsigned IOCTL_DRVGETEVENT = DRVGETEVENT; +unsigned IOCTL_DRVSUSPENDDEV = DRVSUSPENDDEV; +unsigned IOCTL_DVD_READ_STRUCT = DVD_READ_STRUCT; +unsigned IOCTL_DVD_WRITE_STRUCT = DVD_WRITE_STRUCT; +unsigned IOCTL_DVD_AUTH = DVD_AUTH; +unsigned IOCTL_ENVSYS_GETDICTIONARY = ENVSYS_GETDICTIONARY; +unsigned IOCTL_ENVSYS_SETDICTIONARY = ENVSYS_SETDICTIONARY; +unsigned IOCTL_ENVSYS_REMOVEPROPS = ENVSYS_REMOVEPROPS; +unsigned IOCTL_ENVSYS_GTREDATA = ENVSYS_GTREDATA; +unsigned IOCTL_ENVSYS_GTREINFO = ENVSYS_GTREINFO; +unsigned IOCTL_KFILTER_BYFILTER = KFILTER_BYFILTER; +unsigned IOCTL_KFILTER_BYNAME = KFILTER_BYNAME; +unsigned IOCTL_FDIOCGETOPTS = FDIOCGETOPTS; +unsigned IOCTL_FDIOCSETOPTS = FDIOCSETOPTS; +unsigned IOCTL_FDIOCSETFORMAT = FDIOCSETFORMAT; +unsigned IOCTL_FDIOCGETFORMAT = FDIOCGETFORMAT; +unsigned IOCTL_FDIOCFORMAT_TRACK = FDIOCFORMAT_TRACK; +unsigned IOCTL_FIOCLEX = FIOCLEX; +unsigned IOCTL_FIONCLEX = FIONCLEX; +unsigned IOCTL_FIOSEEKDATA = FIOSEEKDATA; +unsigned IOCTL_FIOSEEKHOLE = FIOSEEKHOLE; +unsigned IOCTL_FIONREAD = FIONREAD; +unsigned IOCTL_FIONBIO = FIONBIO; +unsigned IOCTL_FIOASYNC = FIOASYNC; +unsigned IOCTL_FIOSETOWN = FIOSETOWN; +unsigned IOCTL_FIOGETOWN = FIOGETOWN; +unsigned IOCTL_OFIOGETBMAP = OFIOGETBMAP; +unsigned IOCTL_FIOGETBMAP = FIOGETBMAP; +unsigned IOCTL_FIONWRITE = FIONWRITE; +unsigned IOCTL_FIONSPACE = FIONSPACE; +unsigned IOCTL_GPIOINFO = GPIOINFO; +unsigned IOCTL_GPIOSET = GPIOSET; +unsigned IOCTL_GPIOUNSET = GPIOUNSET; +unsigned IOCTL_GPIOREAD = GPIOREAD; +unsigned IOCTL_GPIOWRITE = GPIOWRITE; +unsigned IOCTL_GPIOTOGGLE = GPIOTOGGLE; +unsigned IOCTL_GPIOATTACH = GPIOATTACH; +unsigned IOCTL_PTIOCNETBSD = PTIOCNETBSD; +unsigned IOCTL_PTIOCSUNOS = PTIOCSUNOS; +unsigned IOCTL_PTIOCLINUX = PTIOCLINUX; +unsigned IOCTL_PTIOCFREEBSD = PTIOCFREEBSD; +unsigned IOCTL_PTIOCULTRIX = PTIOCULTRIX; +unsigned IOCTL_TIOCHPCL = TIOCHPCL; +unsigned IOCTL_TIOCGETP = TIOCGETP; +unsigned IOCTL_TIOCSETP = TIOCSETP; +unsigned IOCTL_TIOCSETN = TIOCSETN; +unsigned IOCTL_TIOCSETC = TIOCSETC; +unsigned IOCTL_TIOCGETC = TIOCGETC; +unsigned IOCTL_TIOCLBIS = TIOCLBIS; +unsigned IOCTL_TIOCLBIC = TIOCLBIC; +unsigned IOCTL_TIOCLSET = TIOCLSET; +unsigned IOCTL_TIOCLGET = TIOCLGET; +unsigned IOCTL_TIOCSLTC = TIOCSLTC; +unsigned IOCTL_TIOCGLTC = TIOCGLTC; +unsigned IOCTL_OTIOCCONS = OTIOCCONS; +unsigned IOCTL_JOY_SETTIMEOUT = JOY_SETTIMEOUT; +unsigned IOCTL_JOY_GETTIMEOUT = JOY_GETTIMEOUT; +unsigned IOCTL_JOY_SET_X_OFFSET = JOY_SET_X_OFFSET; +unsigned IOCTL_JOY_SET_Y_OFFSET = JOY_SET_Y_OFFSET; +unsigned IOCTL_JOY_GET_X_OFFSET = JOY_GET_X_OFFSET; +unsigned IOCTL_JOY_GET_Y_OFFSET = JOY_GET_Y_OFFSET; +unsigned IOCTL_OKIOCGSYMBOL = OKIOCGSYMBOL; +unsigned IOCTL_OKIOCGVALUE = OKIOCGVALUE; +unsigned IOCTL_KIOCGSIZE = KIOCGSIZE; +unsigned IOCTL_KIOCGVALUE = KIOCGVALUE; +unsigned IOCTL_KIOCGSYMBOL = KIOCGSYMBOL; +unsigned IOCTL_LUAINFO = LUAINFO; +unsigned IOCTL_LUACREATE = LUACREATE; +unsigned IOCTL_LUADESTROY = LUADESTROY; +unsigned IOCTL_LUAREQUIRE = LUAREQUIRE; +unsigned IOCTL_LUALOAD = LUALOAD; +unsigned IOCTL_MIDI_PRETIME = MIDI_PRETIME; +unsigned IOCTL_MIDI_MPUMODE = MIDI_MPUMODE; +unsigned IOCTL_MIDI_MPUCMD = MIDI_MPUCMD; +unsigned IOCTL_SEQUENCER_RESET = SEQUENCER_RESET; +unsigned IOCTL_SEQUENCER_SYNC = SEQUENCER_SYNC; +unsigned IOCTL_SEQUENCER_INFO = SEQUENCER_INFO; +unsigned IOCTL_SEQUENCER_CTRLRATE = SEQUENCER_CTRLRATE; +unsigned IOCTL_SEQUENCER_GETOUTCOUNT = SEQUENCER_GETOUTCOUNT; +unsigned IOCTL_SEQUENCER_GETINCOUNT = SEQUENCER_GETINCOUNT; +unsigned IOCTL_SEQUENCER_RESETSAMPLES = SEQUENCER_RESETSAMPLES; +unsigned IOCTL_SEQUENCER_NRSYNTHS = SEQUENCER_NRSYNTHS; +unsigned IOCTL_SEQUENCER_NRMIDIS = SEQUENCER_NRMIDIS; +unsigned IOCTL_SEQUENCER_THRESHOLD = SEQUENCER_THRESHOLD; +unsigned IOCTL_SEQUENCER_MEMAVL = SEQUENCER_MEMAVL; +unsigned IOCTL_SEQUENCER_PANIC = SEQUENCER_PANIC; +unsigned IOCTL_SEQUENCER_OUTOFBAND = SEQUENCER_OUTOFBAND; +unsigned IOCTL_SEQUENCER_GETTIME = SEQUENCER_GETTIME; +unsigned IOCTL_SEQUENCER_TMR_TIMEBASE = SEQUENCER_TMR_TIMEBASE; +unsigned IOCTL_SEQUENCER_TMR_START = SEQUENCER_TMR_START; +unsigned IOCTL_SEQUENCER_TMR_STOP = SEQUENCER_TMR_STOP; +unsigned IOCTL_SEQUENCER_TMR_CONTINUE = SEQUENCER_TMR_CONTINUE; +unsigned IOCTL_SEQUENCER_TMR_TEMPO = SEQUENCER_TMR_TEMPO; +unsigned IOCTL_SEQUENCER_TMR_SOURCE = SEQUENCER_TMR_SOURCE; +unsigned IOCTL_SEQUENCER_TMR_METRONOME = SEQUENCER_TMR_METRONOME; +unsigned IOCTL_SEQUENCER_TMR_SELECT = SEQUENCER_TMR_SELECT; +unsigned IOCTL_MTIOCTOP = MTIOCTOP; +unsigned IOCTL_MTIOCGET = MTIOCGET; +unsigned IOCTL_MTIOCIEOT = MTIOCIEOT; +unsigned IOCTL_MTIOCEEOT = MTIOCEEOT; +unsigned IOCTL_MTIOCRDSPOS = MTIOCRDSPOS; +unsigned IOCTL_MTIOCRDHPOS = MTIOCRDHPOS; +unsigned IOCTL_MTIOCSLOCATE = MTIOCSLOCATE; +unsigned IOCTL_MTIOCHLOCATE = MTIOCHLOCATE; +unsigned IOCTL_POWER_EVENT_RECVDICT = POWER_EVENT_RECVDICT; +unsigned IOCTL_POWER_IOC_GET_TYPE = POWER_IOC_GET_TYPE; +unsigned IOCTL_RIOCGINFO = RIOCGINFO; +unsigned IOCTL_RIOCSINFO = RIOCSINFO; +unsigned IOCTL_RIOCSSRCH = RIOCSSRCH; +unsigned IOCTL_RNDGETENTCNT = RNDGETENTCNT; +unsigned IOCTL_RNDGETSRCNUM = RNDGETSRCNUM; +unsigned IOCTL_RNDGETSRCNAME = RNDGETSRCNAME; +unsigned IOCTL_RNDCTL = RNDCTL; +unsigned IOCTL_RNDADDDATA = RNDADDDATA; +unsigned IOCTL_RNDGETPOOLSTAT = RNDGETPOOLSTAT; +unsigned IOCTL_RNDGETESTNUM = RNDGETESTNUM; +unsigned IOCTL_RNDGETESTNAME = RNDGETESTNAME; +unsigned IOCTL_SCIOCGET = SCIOCGET; +unsigned IOCTL_SCIOCSET = SCIOCSET; +unsigned IOCTL_SCIOCRESTART = SCIOCRESTART; +unsigned IOCTL_SCIOC_USE_ADF = SCIOC_USE_ADF; +unsigned IOCTL_SCIOCCOMMAND = SCIOCCOMMAND; +unsigned IOCTL_SCIOCDEBUG = SCIOCDEBUG; +unsigned IOCTL_SCIOCIDENTIFY = SCIOCIDENTIFY; +unsigned IOCTL_OSCIOCIDENTIFY = OSCIOCIDENTIFY; +unsigned IOCTL_SCIOCDECONFIG = SCIOCDECONFIG; +unsigned IOCTL_SCIOCRECONFIG = SCIOCRECONFIG; +unsigned IOCTL_SCIOCRESET = SCIOCRESET; +unsigned IOCTL_SCBUSIOSCAN = SCBUSIOSCAN; +unsigned IOCTL_SCBUSIORESET = SCBUSIORESET; +unsigned IOCTL_SCBUSIODETACH = SCBUSIODETACH; +unsigned IOCTL_SCBUSACCEL = SCBUSACCEL; +unsigned IOCTL_SCBUSIOLLSCAN = SCBUSIOLLSCAN; +unsigned IOCTL_SIOCSHIWAT = SIOCSHIWAT; +unsigned IOCTL_SIOCGHIWAT = SIOCGHIWAT; +unsigned IOCTL_SIOCSLOWAT = SIOCSLOWAT; +unsigned IOCTL_SIOCGLOWAT = SIOCGLOWAT; +unsigned IOCTL_SIOCATMARK = SIOCATMARK; +unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; +unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; +unsigned IOCTL_SIOCPEELOFF = SIOCPEELOFF; +unsigned IOCTL_SIOCADDRT = SIOCADDRT; +unsigned IOCTL_SIOCDELRT = SIOCDELRT; +unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; +unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; +unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; +unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; +unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; +unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; +unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; +unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; +unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; +unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; +unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; +unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; +unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; +unsigned IOCTL_SIOCDIFADDR = SIOCDIFADDR; +unsigned IOCTL_SIOCAIFADDR = SIOCAIFADDR; +unsigned IOCTL_SIOCGIFALIAS = SIOCGIFALIAS; +unsigned IOCTL_SIOCGIFAFLAG_IN = SIOCGIFAFLAG_IN; +unsigned IOCTL_SIOCALIFADDR = SIOCALIFADDR; +unsigned IOCTL_SIOCGLIFADDR = SIOCGLIFADDR; +unsigned IOCTL_SIOCDLIFADDR = SIOCDLIFADDR; +unsigned IOCTL_SIOCSIFADDRPREF = SIOCSIFADDRPREF; +unsigned IOCTL_SIOCGIFADDRPREF = SIOCGIFADDRPREF; +unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; +unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; +unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; +unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; +unsigned IOCTL_SIOCSIFMEDIA = SIOCSIFMEDIA; +unsigned IOCTL_SIOCGIFMEDIA = SIOCGIFMEDIA; +unsigned IOCTL_SIOCSIFGENERIC = SIOCSIFGENERIC; +unsigned IOCTL_SIOCGIFGENERIC = SIOCGIFGENERIC; +unsigned IOCTL_SIOCSIFPHYADDR = SIOCSIFPHYADDR; +unsigned IOCTL_SIOCGIFPSRCADDR = SIOCGIFPSRCADDR; +unsigned IOCTL_SIOCGIFPDSTADDR = SIOCGIFPDSTADDR; +unsigned IOCTL_SIOCDIFPHYADDR = SIOCDIFPHYADDR; +unsigned IOCTL_SIOCSLIFPHYADDR = SIOCSLIFPHYADDR; +unsigned IOCTL_SIOCGLIFPHYADDR = SIOCGLIFPHYADDR; +unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; +unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; +unsigned IOCTL_SIOCSDRVSPEC = SIOCSDRVSPEC; +unsigned IOCTL_SIOCGDRVSPEC = SIOCGDRVSPEC; +unsigned IOCTL_SIOCIFCREATE = SIOCIFCREATE; +unsigned IOCTL_SIOCIFDESTROY = SIOCIFDESTROY; +unsigned IOCTL_SIOCIFGCLONERS = SIOCIFGCLONERS; +unsigned IOCTL_SIOCGIFDLT = SIOCGIFDLT; +unsigned IOCTL_SIOCGIFCAP = SIOCGIFCAP; +unsigned IOCTL_SIOCSIFCAP = SIOCSIFCAP; +unsigned IOCTL_SIOCSVH = SIOCSVH; +unsigned IOCTL_SIOCGVH = SIOCGVH; +unsigned IOCTL_SIOCINITIFADDR = SIOCINITIFADDR; +unsigned IOCTL_SIOCGIFDATA = SIOCGIFDATA; +unsigned IOCTL_SIOCZIFDATA = SIOCZIFDATA; +unsigned IOCTL_SIOCGLINKSTR = SIOCGLINKSTR; +unsigned IOCTL_SIOCSLINKSTR = SIOCSLINKSTR; +unsigned IOCTL_SIOCGETHERCAP = SIOCGETHERCAP; +unsigned IOCTL_SIOCGIFINDEX = SIOCGIFINDEX; +unsigned IOCTL_SIOCSETHERCAP = SIOCSETHERCAP; +unsigned IOCTL_SIOCSIFDESCR = SIOCSIFDESCR; +unsigned IOCTL_SIOCGIFDESCR = SIOCGIFDESCR; +unsigned IOCTL_SIOCGUMBINFO = SIOCGUMBINFO; +unsigned IOCTL_SIOCSUMBPARAM = SIOCSUMBPARAM; +unsigned IOCTL_SIOCGUMBPARAM = SIOCGUMBPARAM; +unsigned IOCTL_SIOCSETPFSYNC = SIOCSETPFSYNC; +unsigned IOCTL_SIOCGETPFSYNC = SIOCGETPFSYNC; +unsigned IOCTL_PPS_IOC_CREATE = PPS_IOC_CREATE; +unsigned IOCTL_PPS_IOC_DESTROY = PPS_IOC_DESTROY; +unsigned IOCTL_PPS_IOC_SETPARAMS = PPS_IOC_SETPARAMS; +unsigned IOCTL_PPS_IOC_GETPARAMS = PPS_IOC_GETPARAMS; +unsigned IOCTL_PPS_IOC_GETCAP = PPS_IOC_GETCAP; +unsigned IOCTL_PPS_IOC_FETCH = PPS_IOC_FETCH; +unsigned IOCTL_PPS_IOC_KCBIND = PPS_IOC_KCBIND; +unsigned IOCTL_TIOCEXCL = TIOCEXCL; +unsigned IOCTL_TIOCNXCL = TIOCNXCL; +unsigned IOCTL_TIOCFLUSH = TIOCFLUSH; +unsigned IOCTL_TIOCGETA = TIOCGETA; +unsigned IOCTL_TIOCSETA = TIOCSETA; +unsigned IOCTL_TIOCSETAW = TIOCSETAW; +unsigned IOCTL_TIOCSETAF = TIOCSETAF; +unsigned IOCTL_TIOCGETD = TIOCGETD; +unsigned IOCTL_TIOCSETD = TIOCSETD; +unsigned IOCTL_TIOCGLINED = TIOCGLINED; +unsigned IOCTL_TIOCSLINED = TIOCSLINED; +unsigned IOCTL_TIOCSBRK = TIOCSBRK; +unsigned IOCTL_TIOCCBRK = TIOCCBRK; +unsigned IOCTL_TIOCSDTR = TIOCSDTR; +unsigned IOCTL_TIOCCDTR = TIOCCDTR; +unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; +unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; +unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; +unsigned IOCTL_TIOCSTI = TIOCSTI; +unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; +unsigned IOCTL_TIOCPKT = TIOCPKT; +unsigned IOCTL_TIOCSTOP = TIOCSTOP; +unsigned IOCTL_TIOCSTART = TIOCSTART; +unsigned IOCTL_TIOCMSET = TIOCMSET; +unsigned IOCTL_TIOCMBIS = TIOCMBIS; +unsigned IOCTL_TIOCMBIC = TIOCMBIC; +unsigned IOCTL_TIOCMGET = TIOCMGET; +unsigned IOCTL_TIOCREMOTE = TIOCREMOTE; +unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; +unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; +unsigned IOCTL_TIOCUCNTL = TIOCUCNTL; +unsigned IOCTL_TIOCSTAT = TIOCSTAT; +unsigned IOCTL_TIOCGSID = TIOCGSID; +unsigned IOCTL_TIOCCONS = TIOCCONS; +unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; +unsigned IOCTL_TIOCEXT = TIOCEXT; +unsigned IOCTL_TIOCSIG = TIOCSIG; +unsigned IOCTL_TIOCDRAIN = TIOCDRAIN; +unsigned IOCTL_TIOCGFLAGS = TIOCGFLAGS; +unsigned IOCTL_TIOCSFLAGS = TIOCSFLAGS; +unsigned IOCTL_TIOCDCDTIMESTAMP = TIOCDCDTIMESTAMP; +unsigned IOCTL_TIOCRCVFRAME = TIOCRCVFRAME; +unsigned IOCTL_TIOCXMTFRAME = TIOCXMTFRAME; +unsigned IOCTL_TIOCPTMGET = TIOCPTMGET; +unsigned IOCTL_TIOCGRANTPT = TIOCGRANTPT; +unsigned IOCTL_TIOCPTSNAME = TIOCPTSNAME; +unsigned IOCTL_TIOCSQSIZE = TIOCSQSIZE; +unsigned IOCTL_TIOCGQSIZE = TIOCGQSIZE; +unsigned IOCTL_VERIEXEC_LOAD = VERIEXEC_LOAD; +unsigned IOCTL_VERIEXEC_TABLESIZE = VERIEXEC_TABLESIZE; +unsigned IOCTL_VERIEXEC_DELETE = VERIEXEC_DELETE; +unsigned IOCTL_VERIEXEC_QUERY = VERIEXEC_QUERY; +unsigned IOCTL_VERIEXEC_DUMP = VERIEXEC_DUMP; +unsigned IOCTL_VERIEXEC_FLUSH = VERIEXEC_FLUSH; +unsigned IOCTL_VIDIOC_QUERYCAP = VIDIOC_QUERYCAP; +unsigned IOCTL_VIDIOC_RESERVED = VIDIOC_RESERVED; +unsigned IOCTL_VIDIOC_ENUM_FMT = VIDIOC_ENUM_FMT; +unsigned IOCTL_VIDIOC_G_FMT = VIDIOC_G_FMT; +unsigned IOCTL_VIDIOC_S_FMT = VIDIOC_S_FMT; +unsigned IOCTL_VIDIOC_REQBUFS = VIDIOC_REQBUFS; +unsigned IOCTL_VIDIOC_QUERYBUF = VIDIOC_QUERYBUF; +unsigned IOCTL_VIDIOC_G_FBUF = VIDIOC_G_FBUF; +unsigned IOCTL_VIDIOC_S_FBUF = VIDIOC_S_FBUF; +unsigned IOCTL_VIDIOC_OVERLAY = VIDIOC_OVERLAY; +unsigned IOCTL_VIDIOC_QBUF = VIDIOC_QBUF; +unsigned IOCTL_VIDIOC_DQBUF = VIDIOC_DQBUF; +unsigned IOCTL_VIDIOC_STREAMON = VIDIOC_STREAMON; +unsigned IOCTL_VIDIOC_STREAMOFF = VIDIOC_STREAMOFF; +unsigned IOCTL_VIDIOC_G_PARM = VIDIOC_G_PARM; +unsigned IOCTL_VIDIOC_S_PARM = VIDIOC_S_PARM; +unsigned IOCTL_VIDIOC_G_STD = VIDIOC_G_STD; +unsigned IOCTL_VIDIOC_S_STD = VIDIOC_S_STD; +unsigned IOCTL_VIDIOC_ENUMSTD = VIDIOC_ENUMSTD; +unsigned IOCTL_VIDIOC_ENUMINPUT = VIDIOC_ENUMINPUT; +unsigned IOCTL_VIDIOC_G_CTRL = VIDIOC_G_CTRL; +unsigned IOCTL_VIDIOC_S_CTRL = VIDIOC_S_CTRL; +unsigned IOCTL_VIDIOC_G_TUNER = VIDIOC_G_TUNER; +unsigned IOCTL_VIDIOC_S_TUNER = VIDIOC_S_TUNER; +unsigned IOCTL_VIDIOC_G_AUDIO = VIDIOC_G_AUDIO; +unsigned IOCTL_VIDIOC_S_AUDIO = VIDIOC_S_AUDIO; +unsigned IOCTL_VIDIOC_QUERYCTRL = VIDIOC_QUERYCTRL; +unsigned IOCTL_VIDIOC_QUERYMENU = VIDIOC_QUERYMENU; +unsigned IOCTL_VIDIOC_G_INPUT = VIDIOC_G_INPUT; +unsigned IOCTL_VIDIOC_S_INPUT = VIDIOC_S_INPUT; +unsigned IOCTL_VIDIOC_G_OUTPUT = VIDIOC_G_OUTPUT; +unsigned IOCTL_VIDIOC_S_OUTPUT = VIDIOC_S_OUTPUT; +unsigned IOCTL_VIDIOC_ENUMOUTPUT = VIDIOC_ENUMOUTPUT; +unsigned IOCTL_VIDIOC_G_AUDOUT = VIDIOC_G_AUDOUT; +unsigned IOCTL_VIDIOC_S_AUDOUT = VIDIOC_S_AUDOUT; +unsigned IOCTL_VIDIOC_G_MODULATOR = VIDIOC_G_MODULATOR; +unsigned IOCTL_VIDIOC_S_MODULATOR = VIDIOC_S_MODULATOR; +unsigned IOCTL_VIDIOC_G_FREQUENCY = VIDIOC_G_FREQUENCY; +unsigned IOCTL_VIDIOC_S_FREQUENCY = VIDIOC_S_FREQUENCY; +unsigned IOCTL_VIDIOC_CROPCAP = VIDIOC_CROPCAP; +unsigned IOCTL_VIDIOC_G_CROP = VIDIOC_G_CROP; +unsigned IOCTL_VIDIOC_S_CROP = VIDIOC_S_CROP; +unsigned IOCTL_VIDIOC_G_JPEGCOMP = VIDIOC_G_JPEGCOMP; +unsigned IOCTL_VIDIOC_S_JPEGCOMP = VIDIOC_S_JPEGCOMP; +unsigned IOCTL_VIDIOC_QUERYSTD = VIDIOC_QUERYSTD; +unsigned IOCTL_VIDIOC_TRY_FMT = VIDIOC_TRY_FMT; +unsigned IOCTL_VIDIOC_ENUMAUDIO = VIDIOC_ENUMAUDIO; +unsigned IOCTL_VIDIOC_ENUMAUDOUT = VIDIOC_ENUMAUDOUT; +unsigned IOCTL_VIDIOC_G_PRIORITY = VIDIOC_G_PRIORITY; +unsigned IOCTL_VIDIOC_S_PRIORITY = VIDIOC_S_PRIORITY; +unsigned IOCTL_VIDIOC_ENUM_FRAMESIZES = VIDIOC_ENUM_FRAMESIZES; +unsigned IOCTL_VIDIOC_ENUM_FRAMEINTERVALS = VIDIOC_ENUM_FRAMEINTERVALS; +unsigned IOCTL_WDOGIOC_GMODE = WDOGIOC_GMODE; +unsigned IOCTL_WDOGIOC_SMODE = WDOGIOC_SMODE; +unsigned IOCTL_WDOGIOC_WHICH = WDOGIOC_WHICH; +unsigned IOCTL_WDOGIOC_TICKLE = WDOGIOC_TICKLE; +unsigned IOCTL_WDOGIOC_GTICKLER = WDOGIOC_GTICKLER; +unsigned IOCTL_WDOGIOC_GWDOGS = WDOGIOC_GWDOGS; +unsigned IOCTL_KCOV_IOC_SETBUFSIZE = KCOV_IOC_SETBUFSIZE; +unsigned IOCTL_KCOV_IOC_ENABLE = KCOV_IOC_ENABLE; +unsigned IOCTL_KCOV_IOC_DISABLE = KCOV_IOC_DISABLE; +unsigned IOCTL_IPMICTL_RECEIVE_MSG_TRUNC = IPMICTL_RECEIVE_MSG_TRUNC; +unsigned IOCTL_IPMICTL_RECEIVE_MSG = IPMICTL_RECEIVE_MSG; +unsigned IOCTL_IPMICTL_SEND_COMMAND = IPMICTL_SEND_COMMAND; +unsigned IOCTL_IPMICTL_REGISTER_FOR_CMD = IPMICTL_REGISTER_FOR_CMD; +unsigned IOCTL_IPMICTL_UNREGISTER_FOR_CMD = IPMICTL_UNREGISTER_FOR_CMD; +unsigned IOCTL_IPMICTL_SET_GETS_EVENTS_CMD = IPMICTL_SET_GETS_EVENTS_CMD; +unsigned IOCTL_IPMICTL_SET_MY_ADDRESS_CMD = IPMICTL_SET_MY_ADDRESS_CMD; +unsigned IOCTL_IPMICTL_GET_MY_ADDRESS_CMD = IPMICTL_GET_MY_ADDRESS_CMD; +unsigned IOCTL_IPMICTL_SET_MY_LUN_CMD = IPMICTL_SET_MY_LUN_CMD; +unsigned IOCTL_IPMICTL_GET_MY_LUN_CMD = IPMICTL_GET_MY_LUN_CMD; +unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; +unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; +unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; +unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE; +unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; +unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; +unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; +unsigned IOCTL_SOUND_PCM_READ_BITS = SOUND_PCM_READ_BITS; +unsigned IOCTL_SNDCTL_DSP_CHANNELS = SNDCTL_DSP_CHANNELS; +unsigned IOCTL_SOUND_PCM_READ_CHANNELS = SOUND_PCM_READ_CHANNELS; +unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER; +unsigned IOCTL_SOUND_PCM_READ_FILTER = SOUND_PCM_READ_FILTER; +unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; +unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; +unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; +unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; +unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE; +unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; +unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; +unsigned IOCTL_SNDCTL_DSP_GETCAPS = SNDCTL_DSP_GETCAPS; +unsigned IOCTL_SNDCTL_DSP_GETTRIGGER = SNDCTL_DSP_GETTRIGGER; +unsigned IOCTL_SNDCTL_DSP_SETTRIGGER = SNDCTL_DSP_SETTRIGGER; +unsigned IOCTL_SNDCTL_DSP_GETIPTR = SNDCTL_DSP_GETIPTR; +unsigned IOCTL_SNDCTL_DSP_GETOPTR = SNDCTL_DSP_GETOPTR; +unsigned IOCTL_SNDCTL_DSP_MAPINBUF = SNDCTL_DSP_MAPINBUF; +unsigned IOCTL_SNDCTL_DSP_MAPOUTBUF = SNDCTL_DSP_MAPOUTBUF; +unsigned IOCTL_SNDCTL_DSP_SETSYNCRO = SNDCTL_DSP_SETSYNCRO; +unsigned IOCTL_SNDCTL_DSP_SETDUPLEX = SNDCTL_DSP_SETDUPLEX; +unsigned IOCTL_SNDCTL_DSP_PROFILE = SNDCTL_DSP_PROFILE; +unsigned IOCTL_SNDCTL_DSP_GETODELAY = SNDCTL_DSP_GETODELAY; +unsigned IOCTL_SOUND_MIXER_INFO = SOUND_MIXER_INFO; +unsigned IOCTL_SOUND_OLD_MIXER_INFO = SOUND_OLD_MIXER_INFO; +unsigned IOCTL_OSS_GETVERSION = OSS_GETVERSION; +unsigned IOCTL_SNDCTL_SYSINFO = SNDCTL_SYSINFO; +unsigned IOCTL_SNDCTL_AUDIOINFO = SNDCTL_AUDIOINFO; +unsigned IOCTL_SNDCTL_ENGINEINFO = SNDCTL_ENGINEINFO; +unsigned IOCTL_SNDCTL_DSP_GETPLAYVOL = SNDCTL_DSP_GETPLAYVOL; +unsigned IOCTL_SNDCTL_DSP_SETPLAYVOL = SNDCTL_DSP_SETPLAYVOL; +unsigned IOCTL_SNDCTL_DSP_GETRECVOL = SNDCTL_DSP_GETRECVOL; +unsigned IOCTL_SNDCTL_DSP_SETRECVOL = SNDCTL_DSP_SETRECVOL; +unsigned IOCTL_SNDCTL_DSP_SKIP = SNDCTL_DSP_SKIP; +unsigned IOCTL_SNDCTL_DSP_SILENCE = SNDCTL_DSP_SILENCE; + +const int si_SEGV_MAPERR = SEGV_MAPERR; +const int si_SEGV_ACCERR = SEGV_ACCERR; + +const int modctl_load = MODCTL_LOAD; +const int modctl_unload = MODCTL_UNLOAD; +const int modctl_stat = MODCTL_STAT; +const int modctl_exists = MODCTL_EXISTS; + +const unsigned SHA1_CTX_sz = sizeof(SHA1_CTX); +const unsigned SHA1_return_length = SHA1_DIGEST_STRING_LENGTH; + +const unsigned MD4_CTX_sz = sizeof(MD4_CTX); +const unsigned MD4_return_length = MD4_DIGEST_STRING_LENGTH; + +const unsigned RMD160_CTX_sz = sizeof(RMD160_CTX); +const unsigned RMD160_return_length = RMD160_DIGEST_STRING_LENGTH; + +const unsigned MD5_CTX_sz = sizeof(MD5_CTX); +const unsigned MD5_return_length = MD5_DIGEST_STRING_LENGTH; + +const unsigned fpos_t_sz = sizeof(fpos_t); + +const unsigned MD2_CTX_sz = sizeof(MD2_CTX); +const unsigned MD2_return_length = MD2_DIGEST_STRING_LENGTH; + +#define SHA2_CONST(LEN) \ + const unsigned SHA##LEN##_CTX_sz = sizeof(SHA##LEN##_CTX); \ + const unsigned SHA##LEN##_return_length = SHA##LEN##_DIGEST_STRING_LENGTH; \ + const unsigned SHA##LEN##_block_length = SHA##LEN##_BLOCK_LENGTH; \ + const unsigned SHA##LEN##_digest_length = SHA##LEN##_DIGEST_LENGTH + +SHA2_CONST(224); +SHA2_CONST(256); +SHA2_CONST(384); +SHA2_CONST(512); + +#undef SHA2_CONST + +const int unvis_valid = UNVIS_VALID; +const int unvis_validpush = UNVIS_VALIDPUSH; +} // namespace __sanitizer + +using namespace __sanitizer; + +COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); + +COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); +CHECK_TYPE_SIZE(pthread_key_t); + +// There are more undocumented fields in dl_phdr_info that we are not interested +// in. +COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); + +CHECK_TYPE_SIZE(glob_t); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); +CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); +CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); +CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); +CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); + +CHECK_TYPE_SIZE(addrinfo); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); + +CHECK_TYPE_SIZE(hostent); +CHECK_SIZE_AND_OFFSET(hostent, h_name); +CHECK_SIZE_AND_OFFSET(hostent, h_aliases); +CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); +CHECK_SIZE_AND_OFFSET(hostent, h_length); +CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); + +CHECK_TYPE_SIZE(iovec); +CHECK_SIZE_AND_OFFSET(iovec, iov_base); +CHECK_SIZE_AND_OFFSET(iovec, iov_len); + +CHECK_TYPE_SIZE(msghdr); +CHECK_SIZE_AND_OFFSET(msghdr, msg_name); +CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_control); +CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); + +CHECK_TYPE_SIZE(cmsghdr); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); + +COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); +CHECK_SIZE_AND_OFFSET(dirent, d_fileno); +CHECK_SIZE_AND_OFFSET(dirent, d_reclen); + +CHECK_TYPE_SIZE(ifconf); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); + +CHECK_TYPE_SIZE(pollfd); +CHECK_SIZE_AND_OFFSET(pollfd, fd); +CHECK_SIZE_AND_OFFSET(pollfd, events); +CHECK_SIZE_AND_OFFSET(pollfd, revents); + +CHECK_TYPE_SIZE(nfds_t); + +CHECK_TYPE_SIZE(sigset_t); + +COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); +// Can't write checks for sa_handler and sa_sigaction due to them being +// preprocessor macros. +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); + +CHECK_TYPE_SIZE(wordexp_t); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); + +COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE)); +CHECK_SIZE_AND_OFFSET(FILE, _p); +CHECK_SIZE_AND_OFFSET(FILE, _r); +CHECK_SIZE_AND_OFFSET(FILE, _w); +CHECK_SIZE_AND_OFFSET(FILE, _flags); +CHECK_SIZE_AND_OFFSET(FILE, _file); +CHECK_SIZE_AND_OFFSET(FILE, _bf); +CHECK_SIZE_AND_OFFSET(FILE, _lbfsize); +CHECK_SIZE_AND_OFFSET(FILE, _cookie); +CHECK_SIZE_AND_OFFSET(FILE, _close); +CHECK_SIZE_AND_OFFSET(FILE, _read); +CHECK_SIZE_AND_OFFSET(FILE, _seek); +CHECK_SIZE_AND_OFFSET(FILE, _write); +CHECK_SIZE_AND_OFFSET(FILE, _ext); +CHECK_SIZE_AND_OFFSET(FILE, _up); +CHECK_SIZE_AND_OFFSET(FILE, _ur); +CHECK_SIZE_AND_OFFSET(FILE, _ubuf); +CHECK_SIZE_AND_OFFSET(FILE, _nbuf); +CHECK_SIZE_AND_OFFSET(FILE, _flush); +CHECK_SIZE_AND_OFFSET(FILE, _lb_unused); +CHECK_SIZE_AND_OFFSET(FILE, _blksize); +CHECK_SIZE_AND_OFFSET(FILE, _offset); + +CHECK_TYPE_SIZE(tm); +CHECK_SIZE_AND_OFFSET(tm, tm_sec); +CHECK_SIZE_AND_OFFSET(tm, tm_min); +CHECK_SIZE_AND_OFFSET(tm, tm_hour); +CHECK_SIZE_AND_OFFSET(tm, tm_mday); +CHECK_SIZE_AND_OFFSET(tm, tm_mon); +CHECK_SIZE_AND_OFFSET(tm, tm_year); +CHECK_SIZE_AND_OFFSET(tm, tm_wday); +CHECK_SIZE_AND_OFFSET(tm, tm_yday); +CHECK_SIZE_AND_OFFSET(tm, tm_isdst); +CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); +CHECK_SIZE_AND_OFFSET(tm, tm_zone); + +CHECK_TYPE_SIZE(ether_addr); + +CHECK_TYPE_SIZE(ipc_perm); +CHECK_SIZE_AND_OFFSET(ipc_perm, _key); +CHECK_SIZE_AND_OFFSET(ipc_perm, _seq); +CHECK_SIZE_AND_OFFSET(ipc_perm, uid); +CHECK_SIZE_AND_OFFSET(ipc_perm, gid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); +CHECK_SIZE_AND_OFFSET(ipc_perm, mode); + +CHECK_TYPE_SIZE(shmid_ds); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); + +CHECK_TYPE_SIZE(clock_t); + +CHECK_TYPE_SIZE(ifaddrs); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); +// Compare against the union, because we can't reach into the union in a +// compliant way. +#ifdef ifa_dstaddr +#undef ifa_dstaddr +#endif +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); + +CHECK_TYPE_SIZE(timeb); +CHECK_SIZE_AND_OFFSET(timeb, time); +CHECK_SIZE_AND_OFFSET(timeb, millitm); +CHECK_SIZE_AND_OFFSET(timeb, timezone); +CHECK_SIZE_AND_OFFSET(timeb, dstflag); + +CHECK_TYPE_SIZE(passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_name); +CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_uid); +CHECK_SIZE_AND_OFFSET(passwd, pw_gid); +CHECK_SIZE_AND_OFFSET(passwd, pw_dir); +CHECK_SIZE_AND_OFFSET(passwd, pw_shell); + +CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); + +CHECK_TYPE_SIZE(group); +CHECK_SIZE_AND_OFFSET(group, gr_name); +CHECK_SIZE_AND_OFFSET(group, gr_passwd); +CHECK_SIZE_AND_OFFSET(group, gr_gid); +CHECK_SIZE_AND_OFFSET(group, gr_mem); + +CHECK_TYPE_SIZE(modctl_load_t); +CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_filename); +CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_flags); +CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_props); +CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_propslen); + +#endif // SANITIZER_NETBSD diff --git a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h index add9852ec6c3..4fb3b8c0e06f 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h @@ -849,6 +849,25 @@ extern unsigned struct_usb_config_desc_sz; extern unsigned struct_usb_ctl_report_desc_sz; extern unsigned struct_usb_ctl_report_sz; extern unsigned struct_usb_ctl_request_sz; +#if defined(__x86_64__) +extern unsigned struct_nvmm_ioc_capability_sz; +extern unsigned struct_nvmm_ioc_machine_create_sz; +extern unsigned struct_nvmm_ioc_machine_destroy_sz; +extern unsigned struct_nvmm_ioc_machine_configure_sz; +extern unsigned struct_nvmm_ioc_vcpu_create_sz; +extern unsigned struct_nvmm_ioc_vcpu_destroy_sz; +extern unsigned struct_nvmm_ioc_vcpu_setstate_sz; +extern unsigned struct_nvmm_ioc_vcpu_getstate_sz; +extern unsigned struct_nvmm_ioc_vcpu_inject_sz; +extern unsigned struct_nvmm_ioc_vcpu_run_sz; +extern unsigned struct_nvmm_ioc_gpa_map_sz; +extern unsigned struct_nvmm_ioc_gpa_unmap_sz; +extern unsigned struct_nvmm_ioc_hva_map_sz; +extern unsigned struct_nvmm_ioc_hva_unmap_sz; +extern unsigned struct_nvmm_ioc_ctl_sz; +#endif +extern unsigned struct_spi_ioctl_configure_sz; +extern unsigned struct_spi_ioctl_transfer_sz; extern unsigned struct_autofs_daemon_request_sz; extern unsigned struct_autofs_daemon_done_sz; extern unsigned struct_sctp_connectx_addrs_sz; @@ -891,6 +910,9 @@ extern unsigned struct_vnd_user_sz; extern unsigned struct_vt_stat_sz; extern unsigned struct_wdog_conf_sz; extern unsigned struct_wdog_mode_sz; +extern unsigned struct_ipmi_recv_sz; +extern unsigned struct_ipmi_req_sz; +extern unsigned struct_ipmi_cmdspec_sz; extern unsigned struct_wfq_conf_sz; extern unsigned struct_wfq_getqid_sz; extern unsigned struct_wfq_getstats_sz; @@ -969,6 +991,7 @@ extern unsigned struct_iscsi_wait_event_parameters_sz; extern unsigned struct_isp_stats_sz; extern unsigned struct_lsenable_sz; extern unsigned struct_lsdisable_sz; +extern unsigned struct_audio_format_query_sz; extern unsigned struct_mixer_ctrl_sz; extern unsigned struct_mixer_devinfo_sz; extern unsigned struct_mpu_command_rec_sz; @@ -1575,7 +1598,7 @@ extern unsigned IOCTL_SPKRTONE; extern unsigned IOCTL_SPKRTUNE; extern unsigned IOCTL_SPKRGETVOL; extern unsigned IOCTL_SPKRSETVOL; -#if 0 /* interfaces are WIP */ +#if defined(__x86_64__) extern unsigned IOCTL_NVMM_IOC_CAPABILITY; extern unsigned IOCTL_NVMM_IOC_MACHINE_CREATE; extern unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY; @@ -1590,6 +1613,7 @@ extern unsigned IOCTL_NVMM_IOC_GPA_MAP; extern unsigned IOCTL_NVMM_IOC_GPA_UNMAP; extern unsigned IOCTL_NVMM_IOC_HVA_MAP; extern unsigned IOCTL_NVMM_IOC_HVA_UNMAP; +extern unsigned IOCTL_NVMM_IOC_CTL; #endif extern unsigned IOCTL_AUTOFSREQUEST; extern unsigned IOCTL_AUTOFSDONE; @@ -1808,6 +1832,9 @@ extern unsigned IOCTL_AUDIO_GETPROPS; extern unsigned IOCTL_AUDIO_GETBUFINFO; extern unsigned IOCTL_AUDIO_SETCHAN; extern unsigned IOCTL_AUDIO_GETCHAN; +extern unsigned IOCTL_AUDIO_QUERYFORMAT; +extern unsigned IOCTL_AUDIO_GETFORMAT; +extern unsigned IOCTL_AUDIO_SETFORMAT; extern unsigned IOCTL_AUDIO_MIXER_READ; extern unsigned IOCTL_AUDIO_MIXER_WRITE; extern unsigned IOCTL_AUDIO_MIXER_DEVINFO; @@ -1893,6 +1920,7 @@ extern unsigned IOCTL_DIOCTUR; extern unsigned IOCTL_DIOCMWEDGES; extern unsigned IOCTL_DIOCGSECTORSIZE; extern unsigned IOCTL_DIOCGMEDIASIZE; +extern unsigned IOCTL_DIOCRMWEDGES; extern unsigned IOCTL_DRVDETACHDEV; extern unsigned IOCTL_DRVRESCANBUS; extern unsigned IOCTL_DRVCTLCOMMAND; @@ -1994,6 +2022,8 @@ extern unsigned IOCTL_SEQUENCER_TMR_TEMPO; extern unsigned IOCTL_SEQUENCER_TMR_SOURCE; extern unsigned IOCTL_SEQUENCER_TMR_METRONOME; extern unsigned IOCTL_SEQUENCER_TMR_SELECT; +extern unsigned IOCTL_SPI_IOCTL_CONFIGURE; +extern unsigned IOCTL_SPI_IOCTL_TRANSFER; extern unsigned IOCTL_MTIOCTOP; extern unsigned IOCTL_MTIOCGET; extern unsigned IOCTL_MTIOCIEOT; @@ -2097,6 +2127,8 @@ extern unsigned IOCTL_SIOCSLINKSTR; extern unsigned IOCTL_SIOCGETHERCAP; extern unsigned IOCTL_SIOCGIFINDEX; extern unsigned IOCTL_SIOCSETHERCAP; +extern unsigned IOCTL_SIOCSIFDESCR; +extern unsigned IOCTL_SIOCGIFDESCR; extern unsigned IOCTL_SIOCGUMBINFO; extern unsigned IOCTL_SIOCSUMBPARAM; extern unsigned IOCTL_SIOCGUMBPARAM; @@ -2221,6 +2253,19 @@ extern unsigned IOCTL_WDOGIOC_WHICH; extern unsigned IOCTL_WDOGIOC_TICKLE; extern unsigned IOCTL_WDOGIOC_GTICKLER; extern unsigned IOCTL_WDOGIOC_GWDOGS; +extern unsigned IOCTL_KCOV_IOC_SETBUFSIZE; +extern unsigned IOCTL_KCOV_IOC_ENABLE; +extern unsigned IOCTL_KCOV_IOC_DISABLE; +extern unsigned IOCTL_IPMICTL_RECEIVE_MSG_TRUNC; +extern unsigned IOCTL_IPMICTL_RECEIVE_MSG; +extern unsigned IOCTL_IPMICTL_SEND_COMMAND; +extern unsigned IOCTL_IPMICTL_REGISTER_FOR_CMD; +extern unsigned IOCTL_IPMICTL_UNREGISTER_FOR_CMD; +extern unsigned IOCTL_IPMICTL_SET_GETS_EVENTS_CMD; +extern unsigned IOCTL_IPMICTL_SET_MY_ADDRESS_CMD; +extern unsigned IOCTL_IPMICTL_GET_MY_ADDRESS_CMD; +extern unsigned IOCTL_IPMICTL_SET_MY_LUN_CMD; +extern unsigned IOCTL_IPMICTL_GET_MY_LUN_CMD; extern unsigned IOCTL_SNDCTL_DSP_RESET; extern unsigned IOCTL_SNDCTL_DSP_SYNC; extern unsigned IOCTL_SNDCTL_DSP_SPEED; diff --git a/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cc b/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cc deleted file mode 100644 index 5a1b07fa9c5e..000000000000 --- a/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cc +++ /dev/null @@ -1,278 +0,0 @@ -//===-- sanitizer_platform_limits_openbsd.cc ------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of Sanitizer common code. -// -// Sizes and layouts of platform-specific NetBSD data structures. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_OPENBSD -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Include these after system headers to avoid name clashes and ambiguities. -#include "sanitizer_internal_defs.h" -#include "sanitizer_platform_limits_openbsd.h" - -namespace __sanitizer { -unsigned struct_utsname_sz = sizeof(struct utsname); -unsigned struct_stat_sz = sizeof(struct stat); -unsigned struct_rusage_sz = sizeof(struct rusage); -unsigned struct_tm_sz = sizeof(struct tm); -unsigned struct_passwd_sz = sizeof(struct passwd); -unsigned struct_group_sz = sizeof(struct group); -unsigned siginfo_t_sz = sizeof(siginfo_t); -unsigned struct_sigaction_sz = sizeof(struct sigaction); -unsigned struct_itimerval_sz = sizeof(struct itimerval); -unsigned pthread_t_sz = sizeof(pthread_t); -unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); -unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); -unsigned pid_t_sz = sizeof(pid_t); -unsigned timeval_sz = sizeof(timeval); -unsigned uid_t_sz = sizeof(uid_t); -unsigned gid_t_sz = sizeof(gid_t); -unsigned mbstate_t_sz = sizeof(mbstate_t); -unsigned sigset_t_sz = sizeof(sigset_t); -unsigned struct_timezone_sz = sizeof(struct timezone); -unsigned struct_tms_sz = sizeof(struct tms); -unsigned struct_sched_param_sz = sizeof(struct sched_param); -unsigned struct_sockaddr_sz = sizeof(struct sockaddr); -unsigned struct_rlimit_sz = sizeof(struct rlimit); -unsigned struct_timespec_sz = sizeof(struct timespec); -unsigned struct_utimbuf_sz = sizeof(struct utimbuf); -unsigned struct_itimerspec_sz = sizeof(struct itimerspec); -unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); -unsigned struct_statvfs_sz = sizeof(struct statvfs); - -const uptr sig_ign = (uptr)SIG_IGN; -const uptr sig_dfl = (uptr)SIG_DFL; -const uptr sig_err = (uptr)SIG_ERR; -const uptr sa_siginfo = (uptr)SA_SIGINFO; - -int shmctl_ipc_stat = (int)IPC_STAT; - -unsigned struct_utmp_sz = sizeof(struct utmp); - -int map_fixed = MAP_FIXED; - -int af_inet = (int)AF_INET; -int af_inet6 = (int)AF_INET6; - -uptr __sanitizer_in_addr_sz(int af) { - if (af == AF_INET) - return sizeof(struct in_addr); - else if (af == AF_INET6) - return sizeof(struct in6_addr); - else - return 0; -} - -unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); - -int glob_nomatch = GLOB_NOMATCH; -int glob_altdirfunc = GLOB_ALTDIRFUNC; - -unsigned path_max = PATH_MAX; - -const int si_SEGV_MAPERR = SEGV_MAPERR; -const int si_SEGV_ACCERR = SEGV_ACCERR; -} // namespace __sanitizer - -using namespace __sanitizer; - -COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); - -COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); -CHECK_TYPE_SIZE(pthread_key_t); - -CHECK_TYPE_SIZE(dl_phdr_info); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); - -CHECK_TYPE_SIZE(glob_t); -CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); -CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); -CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); -CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); -CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); -CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); -CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); -CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); -CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); - -CHECK_TYPE_SIZE(addrinfo); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_next); - -CHECK_TYPE_SIZE(hostent); -CHECK_SIZE_AND_OFFSET(hostent, h_name); -CHECK_SIZE_AND_OFFSET(hostent, h_aliases); -CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); -CHECK_SIZE_AND_OFFSET(hostent, h_length); -CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); - -CHECK_TYPE_SIZE(iovec); -CHECK_SIZE_AND_OFFSET(iovec, iov_base); -CHECK_SIZE_AND_OFFSET(iovec, iov_len); - -CHECK_TYPE_SIZE(msghdr); -CHECK_SIZE_AND_OFFSET(msghdr, msg_name); -CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); -CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_control); -CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); - -CHECK_TYPE_SIZE(cmsghdr); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); - -COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); -CHECK_SIZE_AND_OFFSET(dirent, d_fileno); -CHECK_SIZE_AND_OFFSET(dirent, d_off); -CHECK_SIZE_AND_OFFSET(dirent, d_reclen); - -CHECK_TYPE_SIZE(ifconf); -CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); -CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); - -CHECK_TYPE_SIZE(pollfd); -CHECK_SIZE_AND_OFFSET(pollfd, fd); -CHECK_SIZE_AND_OFFSET(pollfd, events); -CHECK_SIZE_AND_OFFSET(pollfd, revents); - -CHECK_TYPE_SIZE(nfds_t); - -CHECK_TYPE_SIZE(sigset_t); - -COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); -// Can't write checks for sa_handler and sa_sigaction due to them being -// preprocessor macros. -CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); - -CHECK_TYPE_SIZE(tm); -CHECK_SIZE_AND_OFFSET(tm, tm_sec); -CHECK_SIZE_AND_OFFSET(tm, tm_min); -CHECK_SIZE_AND_OFFSET(tm, tm_hour); -CHECK_SIZE_AND_OFFSET(tm, tm_mday); -CHECK_SIZE_AND_OFFSET(tm, tm_mon); -CHECK_SIZE_AND_OFFSET(tm, tm_year); -CHECK_SIZE_AND_OFFSET(tm, tm_wday); -CHECK_SIZE_AND_OFFSET(tm, tm_yday); -CHECK_SIZE_AND_OFFSET(tm, tm_isdst); -CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); -CHECK_SIZE_AND_OFFSET(tm, tm_zone); - -CHECK_TYPE_SIZE(ipc_perm); -CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); -CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); -CHECK_SIZE_AND_OFFSET(ipc_perm, uid); -CHECK_SIZE_AND_OFFSET(ipc_perm, gid); -CHECK_SIZE_AND_OFFSET(ipc_perm, mode); -CHECK_SIZE_AND_OFFSET(ipc_perm, seq); -CHECK_SIZE_AND_OFFSET(ipc_perm, key); - -CHECK_TYPE_SIZE(shmid_ds); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); -CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_atimensec); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); -CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_dtimensec); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); -CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_ctimensec); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); - -CHECK_TYPE_SIZE(clock_t); - -CHECK_TYPE_SIZE(ifaddrs); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); -// Compare against the union, because we can't reach into the union in a -// compliant way. -#ifdef ifa_dstaddr -#undef ifa_dstaddr -#endif -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); - -CHECK_TYPE_SIZE(passwd); -CHECK_SIZE_AND_OFFSET(passwd, pw_name); -CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); -CHECK_SIZE_AND_OFFSET(passwd, pw_uid); -CHECK_SIZE_AND_OFFSET(passwd, pw_gid); -CHECK_SIZE_AND_OFFSET(passwd, pw_dir); -CHECK_SIZE_AND_OFFSET(passwd, pw_shell); - -CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); - -CHECK_TYPE_SIZE(group); -CHECK_SIZE_AND_OFFSET(group, gr_name); -CHECK_SIZE_AND_OFFSET(group, gr_passwd); -CHECK_SIZE_AND_OFFSET(group, gr_gid); -CHECK_SIZE_AND_OFFSET(group, gr_mem); - -#endif // SANITIZER_OPENBSD diff --git a/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cpp b/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cpp new file mode 100644 index 000000000000..12515626ce53 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cpp @@ -0,0 +1,278 @@ +//===-- sanitizer_platform_limits_openbsd.cpp -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific NetBSD data structures. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_OPENBSD +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Include these after system headers to avoid name clashes and ambiguities. +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform_limits_openbsd.h" + +namespace __sanitizer { +unsigned struct_utsname_sz = sizeof(struct utsname); +unsigned struct_stat_sz = sizeof(struct stat); +unsigned struct_rusage_sz = sizeof(struct rusage); +unsigned struct_tm_sz = sizeof(struct tm); +unsigned struct_passwd_sz = sizeof(struct passwd); +unsigned struct_group_sz = sizeof(struct group); +unsigned siginfo_t_sz = sizeof(siginfo_t); +unsigned struct_sigaction_sz = sizeof(struct sigaction); +unsigned struct_itimerval_sz = sizeof(struct itimerval); +unsigned pthread_t_sz = sizeof(pthread_t); +unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); +unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); +unsigned pid_t_sz = sizeof(pid_t); +unsigned timeval_sz = sizeof(timeval); +unsigned uid_t_sz = sizeof(uid_t); +unsigned gid_t_sz = sizeof(gid_t); +unsigned mbstate_t_sz = sizeof(mbstate_t); +unsigned sigset_t_sz = sizeof(sigset_t); +unsigned struct_timezone_sz = sizeof(struct timezone); +unsigned struct_tms_sz = sizeof(struct tms); +unsigned struct_sched_param_sz = sizeof(struct sched_param); +unsigned struct_sockaddr_sz = sizeof(struct sockaddr); +unsigned struct_rlimit_sz = sizeof(struct rlimit); +unsigned struct_timespec_sz = sizeof(struct timespec); +unsigned struct_utimbuf_sz = sizeof(struct utimbuf); +unsigned struct_itimerspec_sz = sizeof(struct itimerspec); +unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); +unsigned struct_statvfs_sz = sizeof(struct statvfs); + +const uptr sig_ign = (uptr)SIG_IGN; +const uptr sig_dfl = (uptr)SIG_DFL; +const uptr sig_err = (uptr)SIG_ERR; +const uptr sa_siginfo = (uptr)SA_SIGINFO; + +int shmctl_ipc_stat = (int)IPC_STAT; + +unsigned struct_utmp_sz = sizeof(struct utmp); + +int map_fixed = MAP_FIXED; + +int af_inet = (int)AF_INET; +int af_inet6 = (int)AF_INET6; + +uptr __sanitizer_in_addr_sz(int af) { + if (af == AF_INET) + return sizeof(struct in_addr); + else if (af == AF_INET6) + return sizeof(struct in6_addr); + else + return 0; +} + +unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); + +int glob_nomatch = GLOB_NOMATCH; +int glob_altdirfunc = GLOB_ALTDIRFUNC; + +unsigned path_max = PATH_MAX; + +const int si_SEGV_MAPERR = SEGV_MAPERR; +const int si_SEGV_ACCERR = SEGV_ACCERR; +} // namespace __sanitizer + +using namespace __sanitizer; + +COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); + +COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); +CHECK_TYPE_SIZE(pthread_key_t); + +CHECK_TYPE_SIZE(dl_phdr_info); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); + +CHECK_TYPE_SIZE(glob_t); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); +CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); +CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); +CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); +CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); + +CHECK_TYPE_SIZE(addrinfo); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_next); + +CHECK_TYPE_SIZE(hostent); +CHECK_SIZE_AND_OFFSET(hostent, h_name); +CHECK_SIZE_AND_OFFSET(hostent, h_aliases); +CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); +CHECK_SIZE_AND_OFFSET(hostent, h_length); +CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); + +CHECK_TYPE_SIZE(iovec); +CHECK_SIZE_AND_OFFSET(iovec, iov_base); +CHECK_SIZE_AND_OFFSET(iovec, iov_len); + +CHECK_TYPE_SIZE(msghdr); +CHECK_SIZE_AND_OFFSET(msghdr, msg_name); +CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_control); +CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); + +CHECK_TYPE_SIZE(cmsghdr); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); + +COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); +CHECK_SIZE_AND_OFFSET(dirent, d_fileno); +CHECK_SIZE_AND_OFFSET(dirent, d_off); +CHECK_SIZE_AND_OFFSET(dirent, d_reclen); + +CHECK_TYPE_SIZE(ifconf); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); + +CHECK_TYPE_SIZE(pollfd); +CHECK_SIZE_AND_OFFSET(pollfd, fd); +CHECK_SIZE_AND_OFFSET(pollfd, events); +CHECK_SIZE_AND_OFFSET(pollfd, revents); + +CHECK_TYPE_SIZE(nfds_t); + +CHECK_TYPE_SIZE(sigset_t); + +COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); +// Can't write checks for sa_handler and sa_sigaction due to them being +// preprocessor macros. +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); + +CHECK_TYPE_SIZE(tm); +CHECK_SIZE_AND_OFFSET(tm, tm_sec); +CHECK_SIZE_AND_OFFSET(tm, tm_min); +CHECK_SIZE_AND_OFFSET(tm, tm_hour); +CHECK_SIZE_AND_OFFSET(tm, tm_mday); +CHECK_SIZE_AND_OFFSET(tm, tm_mon); +CHECK_SIZE_AND_OFFSET(tm, tm_year); +CHECK_SIZE_AND_OFFSET(tm, tm_wday); +CHECK_SIZE_AND_OFFSET(tm, tm_yday); +CHECK_SIZE_AND_OFFSET(tm, tm_isdst); +CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); +CHECK_SIZE_AND_OFFSET(tm, tm_zone); + +CHECK_TYPE_SIZE(ipc_perm); +CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); +CHECK_SIZE_AND_OFFSET(ipc_perm, uid); +CHECK_SIZE_AND_OFFSET(ipc_perm, gid); +CHECK_SIZE_AND_OFFSET(ipc_perm, mode); +CHECK_SIZE_AND_OFFSET(ipc_perm, seq); +CHECK_SIZE_AND_OFFSET(ipc_perm, key); + +CHECK_TYPE_SIZE(shmid_ds); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); +CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_atimensec); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); +CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_dtimensec); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); +CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_ctimensec); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); + +CHECK_TYPE_SIZE(clock_t); + +CHECK_TYPE_SIZE(ifaddrs); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); +// Compare against the union, because we can't reach into the union in a +// compliant way. +#ifdef ifa_dstaddr +#undef ifa_dstaddr +#endif +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); + +CHECK_TYPE_SIZE(passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_name); +CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_uid); +CHECK_SIZE_AND_OFFSET(passwd, pw_gid); +CHECK_SIZE_AND_OFFSET(passwd, pw_dir); +CHECK_SIZE_AND_OFFSET(passwd, pw_shell); + +CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); + +CHECK_TYPE_SIZE(group); +CHECK_SIZE_AND_OFFSET(group, gr_name); +CHECK_SIZE_AND_OFFSET(group, gr_passwd); +CHECK_SIZE_AND_OFFSET(group, gr_gid); +CHECK_SIZE_AND_OFFSET(group, gr_mem); + +#endif // SANITIZER_OPENBSD diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc deleted file mode 100644 index b7fa6e8f7e07..000000000000 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc +++ /dev/null @@ -1,1271 +0,0 @@ -//===-- sanitizer_platform_limits_posix.cc --------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of Sanitizer common code. -// -// Sizes and layouts of platform-specific POSIX data structures. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_LINUX || SANITIZER_MAC -// Tests in this file assume that off_t-dependent data structures match the -// libc ABI. For example, struct dirent here is what readdir() function (as -// exported from libc) returns, and not the user-facing "dirent", which -// depends on _FILE_OFFSET_BITS setting. -// To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below. -#ifdef _FILE_OFFSET_BITS -#undef _FILE_OFFSET_BITS -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if !SANITIZER_MAC -#include -#endif - -#if !SANITIZER_IOS -#include -#endif - -#if !SANITIZER_ANDROID -#include -#include -#include -#include -#endif - -#if SANITIZER_LINUX -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#if SANITIZER_IOS -#undef IOC_DIRMASK -#endif - -#if SANITIZER_LINUX -# include -# include -# if defined(__mips64) || defined(__aarch64__) || defined(__arm__) -# include -# ifdef __arm__ -typedef struct user_fpregs elf_fpregset_t; -# define ARM_VFPREGS_SIZE_ASAN (32 * 8 /*fpregs*/ + 4 /*fpscr*/) -# if !defined(ARM_VFPREGS_SIZE) -# define ARM_VFPREGS_SIZE ARM_VFPREGS_SIZE_ASAN -# endif -# endif -# endif -# include -#endif - -#if !SANITIZER_ANDROID -#include -#include -#include -#endif - -#if SANITIZER_LINUX && !SANITIZER_ANDROID -#include -#include -#include -#include -#include -#include -#include -#if HAVE_RPC_XDR_H -# include -#endif -#include -#include -#include -#include -#include -#include -#if defined(__mips64) -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID - -#if SANITIZER_ANDROID -#include -#include -#include -#include -#endif - -#if SANITIZER_LINUX -#include -#include -#include -#include -#endif // SANITIZER_LINUX - -#if SANITIZER_MAC -#include -#include -#include -#endif - -// Include these after system headers to avoid name clashes and ambiguities. -#include "sanitizer_internal_defs.h" -#include "sanitizer_platform_limits_posix.h" - -namespace __sanitizer { - unsigned struct_utsname_sz = sizeof(struct utsname); - unsigned struct_stat_sz = sizeof(struct stat); -#if !SANITIZER_IOS - unsigned struct_stat64_sz = sizeof(struct stat64); -#endif // !SANITIZER_IOS - unsigned struct_rusage_sz = sizeof(struct rusage); - unsigned struct_tm_sz = sizeof(struct tm); - unsigned struct_passwd_sz = sizeof(struct passwd); - unsigned struct_group_sz = sizeof(struct group); - unsigned siginfo_t_sz = sizeof(siginfo_t); - unsigned struct_sigaction_sz = sizeof(struct sigaction); - unsigned struct_itimerval_sz = sizeof(struct itimerval); - unsigned pthread_t_sz = sizeof(pthread_t); - unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); - unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); - unsigned pid_t_sz = sizeof(pid_t); - unsigned timeval_sz = sizeof(timeval); - unsigned uid_t_sz = sizeof(uid_t); - unsigned gid_t_sz = sizeof(gid_t); - unsigned mbstate_t_sz = sizeof(mbstate_t); - unsigned sigset_t_sz = sizeof(sigset_t); - unsigned struct_timezone_sz = sizeof(struct timezone); - unsigned struct_tms_sz = sizeof(struct tms); - unsigned struct_sigevent_sz = sizeof(struct sigevent); - unsigned struct_sched_param_sz = sizeof(struct sched_param); - unsigned struct_regex_sz = sizeof(regex_t); - unsigned struct_regmatch_sz = sizeof(regmatch_t); - -#if SANITIZER_MAC && !SANITIZER_IOS - unsigned struct_statfs64_sz = sizeof(struct statfs64); -#endif // SANITIZER_MAC && !SANITIZER_IOS - -#if !SANITIZER_ANDROID - unsigned struct_fstab_sz = sizeof(struct fstab); - unsigned struct_statfs_sz = sizeof(struct statfs); - unsigned struct_sockaddr_sz = sizeof(struct sockaddr); - unsigned ucontext_t_sz = sizeof(ucontext_t); -#endif // !SANITIZER_ANDROID - -#if SANITIZER_LINUX - unsigned struct_epoll_event_sz = sizeof(struct epoll_event); - unsigned struct_sysinfo_sz = sizeof(struct sysinfo); - unsigned __user_cap_header_struct_sz = - sizeof(struct __user_cap_header_struct); - unsigned __user_cap_data_struct_sz = sizeof(struct __user_cap_data_struct); - unsigned struct_new_utsname_sz = sizeof(struct new_utsname); - unsigned struct_old_utsname_sz = sizeof(struct old_utsname); - unsigned struct_oldold_utsname_sz = sizeof(struct oldold_utsname); -#endif // SANITIZER_LINUX - -#if SANITIZER_LINUX - unsigned struct_rlimit_sz = sizeof(struct rlimit); - unsigned struct_timespec_sz = sizeof(struct timespec); - unsigned struct_utimbuf_sz = sizeof(struct utimbuf); - unsigned struct_itimerspec_sz = sizeof(struct itimerspec); -#endif // SANITIZER_LINUX - -#if SANITIZER_LINUX && !SANITIZER_ANDROID - // Use pre-computed size of struct ustat to avoid which - // has been removed from glibc 2.28. -#if defined(__aarch64__) || defined(__s390x__) || defined (__mips64) \ - || defined(__powerpc64__) || defined(__arch64__) || defined(__sparcv9) \ - || defined(__x86_64__) -#define SIZEOF_STRUCT_USTAT 32 -#elif defined(__arm__) || defined(__i386__) || defined(__mips__) \ - || defined(__powerpc__) || defined(__s390__) || defined(__sparc__) -#define SIZEOF_STRUCT_USTAT 20 -#else -#error Unknown size of struct ustat -#endif - unsigned struct_ustat_sz = SIZEOF_STRUCT_USTAT; - unsigned struct_rlimit64_sz = sizeof(struct rlimit64); - unsigned struct_statvfs64_sz = sizeof(struct statvfs64); -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID - -#if SANITIZER_LINUX && !SANITIZER_ANDROID - unsigned struct_timex_sz = sizeof(struct timex); - unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); - unsigned struct_mq_attr_sz = sizeof(struct mq_attr); - unsigned struct_statvfs_sz = sizeof(struct statvfs); -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID - - const uptr sig_ign = (uptr)SIG_IGN; - const uptr sig_dfl = (uptr)SIG_DFL; - const uptr sig_err = (uptr)SIG_ERR; - const uptr sa_siginfo = (uptr)SA_SIGINFO; - -#if SANITIZER_LINUX - int e_tabsz = (int)E_TABSZ; -#endif - - -#if SANITIZER_LINUX && !SANITIZER_ANDROID - unsigned struct_shminfo_sz = sizeof(struct shminfo); - unsigned struct_shm_info_sz = sizeof(struct shm_info); - int shmctl_ipc_stat = (int)IPC_STAT; - int shmctl_ipc_info = (int)IPC_INFO; - int shmctl_shm_info = (int)SHM_INFO; - int shmctl_shm_stat = (int)SHM_STAT; -#endif - -#if !SANITIZER_MAC && !SANITIZER_FREEBSD - unsigned struct_utmp_sz = sizeof(struct utmp); -#endif -#if !SANITIZER_ANDROID - unsigned struct_utmpx_sz = sizeof(struct utmpx); -#endif - - int map_fixed = MAP_FIXED; - - int af_inet = (int)AF_INET; - int af_inet6 = (int)AF_INET6; - - uptr __sanitizer_in_addr_sz(int af) { - if (af == AF_INET) - return sizeof(struct in_addr); - else if (af == AF_INET6) - return sizeof(struct in6_addr); - else - return 0; - } - -#if SANITIZER_LINUX -unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr)); -#elif SANITIZER_FREEBSD -unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); -#endif - -#if SANITIZER_LINUX && !SANITIZER_ANDROID - int glob_nomatch = GLOB_NOMATCH; - int glob_altdirfunc = GLOB_ALTDIRFUNC; -#endif - -#if SANITIZER_LINUX && !SANITIZER_ANDROID && \ - (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ - defined(__s390__)) -#if defined(__mips64) || defined(__powerpc64__) || defined(__arm__) - unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs); - unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t); -#elif defined(__aarch64__) - unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs); - unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpsimd_state); -#elif defined(__s390__) - unsigned struct_user_regs_struct_sz = sizeof(struct _user_regs_struct); - unsigned struct_user_fpregs_struct_sz = sizeof(struct _user_fpregs_struct); -#else - unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct); - unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct); -#endif // __mips64 || __powerpc64__ || __aarch64__ -#if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \ - defined(__aarch64__) || defined(__arm__) || defined(__s390__) - unsigned struct_user_fpxregs_struct_sz = 0; -#else - unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct); -#endif // __x86_64 || __mips64 || __powerpc64__ || __aarch64__ || __arm__ -// || __s390__ -#ifdef __arm__ - unsigned struct_user_vfpregs_struct_sz = ARM_VFPREGS_SIZE; -#else - unsigned struct_user_vfpregs_struct_sz = 0; -#endif - - int ptrace_peektext = PTRACE_PEEKTEXT; - int ptrace_peekdata = PTRACE_PEEKDATA; - int ptrace_peekuser = PTRACE_PEEKUSER; -#if (defined(PTRACE_GETREGS) && defined(PTRACE_SETREGS)) || \ - (defined(PT_GETREGS) && defined(PT_SETREGS)) - int ptrace_getregs = PTRACE_GETREGS; - int ptrace_setregs = PTRACE_SETREGS; -#else - int ptrace_getregs = -1; - int ptrace_setregs = -1; -#endif -#if (defined(PTRACE_GETFPREGS) && defined(PTRACE_SETFPREGS)) || \ - (defined(PT_GETFPREGS) && defined(PT_SETFPREGS)) - int ptrace_getfpregs = PTRACE_GETFPREGS; - int ptrace_setfpregs = PTRACE_SETFPREGS; -#else - int ptrace_getfpregs = -1; - int ptrace_setfpregs = -1; -#endif -#if (defined(PTRACE_GETFPXREGS) && defined(PTRACE_SETFPXREGS)) || \ - (defined(PT_GETFPXREGS) && defined(PT_SETFPXREGS)) - int ptrace_getfpxregs = PTRACE_GETFPXREGS; - int ptrace_setfpxregs = PTRACE_SETFPXREGS; -#else - int ptrace_getfpxregs = -1; - int ptrace_setfpxregs = -1; -#endif // PTRACE_GETFPXREGS/PTRACE_SETFPXREGS -#if defined(PTRACE_GETVFPREGS) && defined(PTRACE_SETVFPREGS) - int ptrace_getvfpregs = PTRACE_GETVFPREGS; - int ptrace_setvfpregs = PTRACE_SETVFPREGS; -#else - int ptrace_getvfpregs = -1; - int ptrace_setvfpregs = -1; -#endif - int ptrace_geteventmsg = PTRACE_GETEVENTMSG; -#if (defined(PTRACE_GETSIGINFO) && defined(PTRACE_SETSIGINFO)) || \ - (defined(PT_GETSIGINFO) && defined(PT_SETSIGINFO)) - int ptrace_getsiginfo = PTRACE_GETSIGINFO; - int ptrace_setsiginfo = PTRACE_SETSIGINFO; -#else - int ptrace_getsiginfo = -1; - int ptrace_setsiginfo = -1; -#endif // PTRACE_GETSIGINFO/PTRACE_SETSIGINFO -#if defined(PTRACE_GETREGSET) && defined(PTRACE_SETREGSET) - int ptrace_getregset = PTRACE_GETREGSET; - int ptrace_setregset = PTRACE_SETREGSET; -#else - int ptrace_getregset = -1; - int ptrace_setregset = -1; -#endif // PTRACE_GETREGSET/PTRACE_SETREGSET -#endif - - unsigned path_max = PATH_MAX; - - // ioctl arguments - unsigned struct_ifreq_sz = sizeof(struct ifreq); - unsigned struct_termios_sz = sizeof(struct termios); - unsigned struct_winsize_sz = sizeof(struct winsize); - -#if SANITIZER_LINUX - unsigned struct_arpreq_sz = sizeof(struct arpreq); - unsigned struct_cdrom_msf_sz = sizeof(struct cdrom_msf); - unsigned struct_cdrom_multisession_sz = sizeof(struct cdrom_multisession); - unsigned struct_cdrom_read_audio_sz = sizeof(struct cdrom_read_audio); - unsigned struct_cdrom_subchnl_sz = sizeof(struct cdrom_subchnl); - unsigned struct_cdrom_ti_sz = sizeof(struct cdrom_ti); - unsigned struct_cdrom_tocentry_sz = sizeof(struct cdrom_tocentry); - unsigned struct_cdrom_tochdr_sz = sizeof(struct cdrom_tochdr); - unsigned struct_cdrom_volctrl_sz = sizeof(struct cdrom_volctrl); - unsigned struct_ff_effect_sz = sizeof(struct ff_effect); - unsigned struct_floppy_drive_params_sz = sizeof(struct floppy_drive_params); - unsigned struct_floppy_drive_struct_sz = sizeof(struct floppy_drive_struct); - unsigned struct_floppy_fdc_state_sz = sizeof(struct floppy_fdc_state); - unsigned struct_floppy_max_errors_sz = sizeof(struct floppy_max_errors); - unsigned struct_floppy_raw_cmd_sz = sizeof(struct floppy_raw_cmd); - unsigned struct_floppy_struct_sz = sizeof(struct floppy_struct); - unsigned struct_floppy_write_errors_sz = sizeof(struct floppy_write_errors); - unsigned struct_format_descr_sz = sizeof(struct format_descr); - unsigned struct_hd_driveid_sz = sizeof(struct hd_driveid); - unsigned struct_hd_geometry_sz = sizeof(struct hd_geometry); - unsigned struct_input_absinfo_sz = sizeof(struct input_absinfo); - unsigned struct_input_id_sz = sizeof(struct input_id); - unsigned struct_mtpos_sz = sizeof(struct mtpos); - unsigned struct_rtentry_sz = sizeof(struct rtentry); - unsigned struct_termio_sz = sizeof(struct termio); - unsigned struct_vt_consize_sz = sizeof(struct vt_consize); - unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes); - unsigned struct_vt_stat_sz = sizeof(struct vt_stat); -#endif // SANITIZER_LINUX - -#if SANITIZER_LINUX -#if SOUND_VERSION >= 0x040000 - unsigned struct_copr_buffer_sz = 0; - unsigned struct_copr_debug_buf_sz = 0; - unsigned struct_copr_msg_sz = 0; -#else - unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer); - unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf); - unsigned struct_copr_msg_sz = sizeof(struct copr_msg); -#endif - unsigned struct_midi_info_sz = sizeof(struct midi_info); - unsigned struct_mtget_sz = sizeof(struct mtget); - unsigned struct_mtop_sz = sizeof(struct mtop); - unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument); - unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec); - unsigned struct_synth_info_sz = sizeof(struct synth_info); - unsigned struct_vt_mode_sz = sizeof(struct vt_mode); -#endif // SANITIZER_LINUX - -#if SANITIZER_LINUX && !SANITIZER_ANDROID - unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct); - unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor); -#if EV_VERSION > (0x010000) - unsigned struct_input_keymap_entry_sz = sizeof(struct input_keymap_entry); -#else - unsigned struct_input_keymap_entry_sz = 0; -#endif - unsigned struct_ipx_config_data_sz = sizeof(struct ipx_config_data); - unsigned struct_kbdiacrs_sz = sizeof(struct kbdiacrs); - unsigned struct_kbentry_sz = sizeof(struct kbentry); - unsigned struct_kbkeycode_sz = sizeof(struct kbkeycode); - unsigned struct_kbsentry_sz = sizeof(struct kbsentry); - unsigned struct_mtconfiginfo_sz = sizeof(struct mtconfiginfo); - unsigned struct_nr_parms_struct_sz = sizeof(struct nr_parms_struct); - unsigned struct_scc_modem_sz = sizeof(struct scc_modem); - unsigned struct_scc_stat_sz = sizeof(struct scc_stat); - unsigned struct_serial_multiport_struct_sz - = sizeof(struct serial_multiport_struct); - unsigned struct_serial_struct_sz = sizeof(struct serial_struct); - unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25); - unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc); - unsigned struct_unimapinit_sz = sizeof(struct unimapinit); -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID - -#if SANITIZER_LINUX && !SANITIZER_ANDROID - unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); - unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); -#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID - -#if !SANITIZER_ANDROID && !SANITIZER_MAC - unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); - unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); -#endif - - const unsigned long __sanitizer_bufsiz = BUFSIZ; - - const unsigned IOCTL_NOT_PRESENT = 0; - - unsigned IOCTL_FIOASYNC = FIOASYNC; - unsigned IOCTL_FIOCLEX = FIOCLEX; - unsigned IOCTL_FIOGETOWN = FIOGETOWN; - unsigned IOCTL_FIONBIO = FIONBIO; - unsigned IOCTL_FIONCLEX = FIONCLEX; - unsigned IOCTL_FIOSETOWN = FIOSETOWN; - unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; - unsigned IOCTL_SIOCATMARK = SIOCATMARK; - unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; - unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; - unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; - unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; - unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; - unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; - unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; - unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; - unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; - unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; - unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; - unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; - unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; - unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; - unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; - unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; - unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; - unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; - unsigned IOCTL_TIOCCONS = TIOCCONS; - unsigned IOCTL_TIOCEXCL = TIOCEXCL; - unsigned IOCTL_TIOCGETD = TIOCGETD; - unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; - unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; - unsigned IOCTL_TIOCMBIC = TIOCMBIC; - unsigned IOCTL_TIOCMBIS = TIOCMBIS; - unsigned IOCTL_TIOCMGET = TIOCMGET; - unsigned IOCTL_TIOCMSET = TIOCMSET; - unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; - unsigned IOCTL_TIOCNXCL = TIOCNXCL; - unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; - unsigned IOCTL_TIOCPKT = TIOCPKT; - unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; - unsigned IOCTL_TIOCSETD = TIOCSETD; - unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; - unsigned IOCTL_TIOCSTI = TIOCSTI; - unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; -#if SANITIZER_LINUX && !SANITIZER_ANDROID - unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; - unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; -#endif - -#if SANITIZER_LINUX - unsigned IOCTL_EVIOCGABS = EVIOCGABS(0); - unsigned IOCTL_EVIOCGBIT = EVIOCGBIT(0, 0); - unsigned IOCTL_EVIOCGEFFECTS = EVIOCGEFFECTS; - unsigned IOCTL_EVIOCGID = EVIOCGID; - unsigned IOCTL_EVIOCGKEY = EVIOCGKEY(0); - unsigned IOCTL_EVIOCGKEYCODE = EVIOCGKEYCODE; - unsigned IOCTL_EVIOCGLED = EVIOCGLED(0); - unsigned IOCTL_EVIOCGNAME = EVIOCGNAME(0); - unsigned IOCTL_EVIOCGPHYS = EVIOCGPHYS(0); - unsigned IOCTL_EVIOCGRAB = EVIOCGRAB; - unsigned IOCTL_EVIOCGREP = EVIOCGREP; - unsigned IOCTL_EVIOCGSND = EVIOCGSND(0); - unsigned IOCTL_EVIOCGSW = EVIOCGSW(0); - unsigned IOCTL_EVIOCGUNIQ = EVIOCGUNIQ(0); - unsigned IOCTL_EVIOCGVERSION = EVIOCGVERSION; - unsigned IOCTL_EVIOCRMFF = EVIOCRMFF; - unsigned IOCTL_EVIOCSABS = EVIOCSABS(0); - unsigned IOCTL_EVIOCSFF = EVIOCSFF; - unsigned IOCTL_EVIOCSKEYCODE = EVIOCSKEYCODE; - unsigned IOCTL_EVIOCSREP = EVIOCSREP; - unsigned IOCTL_BLKFLSBUF = BLKFLSBUF; - unsigned IOCTL_BLKGETSIZE = BLKGETSIZE; - unsigned IOCTL_BLKRAGET = BLKRAGET; - unsigned IOCTL_BLKRASET = BLKRASET; - unsigned IOCTL_BLKROGET = BLKROGET; - unsigned IOCTL_BLKROSET = BLKROSET; - unsigned IOCTL_BLKRRPART = BLKRRPART; - unsigned IOCTL_CDROMAUDIOBUFSIZ = CDROMAUDIOBUFSIZ; - unsigned IOCTL_CDROMEJECT = CDROMEJECT; - unsigned IOCTL_CDROMEJECT_SW = CDROMEJECT_SW; - unsigned IOCTL_CDROMMULTISESSION = CDROMMULTISESSION; - unsigned IOCTL_CDROMPAUSE = CDROMPAUSE; - unsigned IOCTL_CDROMPLAYMSF = CDROMPLAYMSF; - unsigned IOCTL_CDROMPLAYTRKIND = CDROMPLAYTRKIND; - unsigned IOCTL_CDROMREADAUDIO = CDROMREADAUDIO; - unsigned IOCTL_CDROMREADCOOKED = CDROMREADCOOKED; - unsigned IOCTL_CDROMREADMODE1 = CDROMREADMODE1; - unsigned IOCTL_CDROMREADMODE2 = CDROMREADMODE2; - unsigned IOCTL_CDROMREADRAW = CDROMREADRAW; - unsigned IOCTL_CDROMREADTOCENTRY = CDROMREADTOCENTRY; - unsigned IOCTL_CDROMREADTOCHDR = CDROMREADTOCHDR; - unsigned IOCTL_CDROMRESET = CDROMRESET; - unsigned IOCTL_CDROMRESUME = CDROMRESUME; - unsigned IOCTL_CDROMSEEK = CDROMSEEK; - unsigned IOCTL_CDROMSTART = CDROMSTART; - unsigned IOCTL_CDROMSTOP = CDROMSTOP; - unsigned IOCTL_CDROMSUBCHNL = CDROMSUBCHNL; - unsigned IOCTL_CDROMVOLCTRL = CDROMVOLCTRL; - unsigned IOCTL_CDROMVOLREAD = CDROMVOLREAD; - unsigned IOCTL_CDROM_GET_UPC = CDROM_GET_UPC; - unsigned IOCTL_FDCLRPRM = FDCLRPRM; - unsigned IOCTL_FDDEFPRM = FDDEFPRM; - unsigned IOCTL_FDFLUSH = FDFLUSH; - unsigned IOCTL_FDFMTBEG = FDFMTBEG; - unsigned IOCTL_FDFMTEND = FDFMTEND; - unsigned IOCTL_FDFMTTRK = FDFMTTRK; - unsigned IOCTL_FDGETDRVPRM = FDGETDRVPRM; - unsigned IOCTL_FDGETDRVSTAT = FDGETDRVSTAT; - unsigned IOCTL_FDGETDRVTYP = FDGETDRVTYP; - unsigned IOCTL_FDGETFDCSTAT = FDGETFDCSTAT; - unsigned IOCTL_FDGETMAXERRS = FDGETMAXERRS; - unsigned IOCTL_FDGETPRM = FDGETPRM; - unsigned IOCTL_FDMSGOFF = FDMSGOFF; - unsigned IOCTL_FDMSGON = FDMSGON; - unsigned IOCTL_FDPOLLDRVSTAT = FDPOLLDRVSTAT; - unsigned IOCTL_FDRAWCMD = FDRAWCMD; - unsigned IOCTL_FDRESET = FDRESET; - unsigned IOCTL_FDSETDRVPRM = FDSETDRVPRM; - unsigned IOCTL_FDSETEMSGTRESH = FDSETEMSGTRESH; - unsigned IOCTL_FDSETMAXERRS = FDSETMAXERRS; - unsigned IOCTL_FDSETPRM = FDSETPRM; - unsigned IOCTL_FDTWADDLE = FDTWADDLE; - unsigned IOCTL_FDWERRORCLR = FDWERRORCLR; - unsigned IOCTL_FDWERRORGET = FDWERRORGET; - unsigned IOCTL_HDIO_DRIVE_CMD = HDIO_DRIVE_CMD; - unsigned IOCTL_HDIO_GETGEO = HDIO_GETGEO; - unsigned IOCTL_HDIO_GET_32BIT = HDIO_GET_32BIT; - unsigned IOCTL_HDIO_GET_DMA = HDIO_GET_DMA; - unsigned IOCTL_HDIO_GET_IDENTITY = HDIO_GET_IDENTITY; - unsigned IOCTL_HDIO_GET_KEEPSETTINGS = HDIO_GET_KEEPSETTINGS; - unsigned IOCTL_HDIO_GET_MULTCOUNT = HDIO_GET_MULTCOUNT; - unsigned IOCTL_HDIO_GET_NOWERR = HDIO_GET_NOWERR; - unsigned IOCTL_HDIO_GET_UNMASKINTR = HDIO_GET_UNMASKINTR; - unsigned IOCTL_HDIO_SET_32BIT = HDIO_SET_32BIT; - unsigned IOCTL_HDIO_SET_DMA = HDIO_SET_DMA; - unsigned IOCTL_HDIO_SET_KEEPSETTINGS = HDIO_SET_KEEPSETTINGS; - unsigned IOCTL_HDIO_SET_MULTCOUNT = HDIO_SET_MULTCOUNT; - unsigned IOCTL_HDIO_SET_NOWERR = HDIO_SET_NOWERR; - unsigned IOCTL_HDIO_SET_UNMASKINTR = HDIO_SET_UNMASKINTR; - unsigned IOCTL_MTIOCPOS = MTIOCPOS; - unsigned IOCTL_PPPIOCGASYNCMAP = PPPIOCGASYNCMAP; - unsigned IOCTL_PPPIOCGDEBUG = PPPIOCGDEBUG; - unsigned IOCTL_PPPIOCGFLAGS = PPPIOCGFLAGS; - unsigned IOCTL_PPPIOCGUNIT = PPPIOCGUNIT; - unsigned IOCTL_PPPIOCGXASYNCMAP = PPPIOCGXASYNCMAP; - unsigned IOCTL_PPPIOCSASYNCMAP = PPPIOCSASYNCMAP; - unsigned IOCTL_PPPIOCSDEBUG = PPPIOCSDEBUG; - unsigned IOCTL_PPPIOCSFLAGS = PPPIOCSFLAGS; - unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID; - unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU; - unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP; - unsigned IOCTL_SIOCADDRT = SIOCADDRT; - unsigned IOCTL_SIOCDARP = SIOCDARP; - unsigned IOCTL_SIOCDELRT = SIOCDELRT; - unsigned IOCTL_SIOCDRARP = SIOCDRARP; - unsigned IOCTL_SIOCGARP = SIOCGARP; - unsigned IOCTL_SIOCGIFENCAP = SIOCGIFENCAP; - unsigned IOCTL_SIOCGIFHWADDR = SIOCGIFHWADDR; - unsigned IOCTL_SIOCGIFMAP = SIOCGIFMAP; - unsigned IOCTL_SIOCGIFMEM = SIOCGIFMEM; - unsigned IOCTL_SIOCGIFNAME = SIOCGIFNAME; - unsigned IOCTL_SIOCGIFSLAVE = SIOCGIFSLAVE; - unsigned IOCTL_SIOCGRARP = SIOCGRARP; - unsigned IOCTL_SIOCGSTAMP = SIOCGSTAMP; - unsigned IOCTL_SIOCSARP = SIOCSARP; - unsigned IOCTL_SIOCSIFENCAP = SIOCSIFENCAP; - unsigned IOCTL_SIOCSIFHWADDR = SIOCSIFHWADDR; - unsigned IOCTL_SIOCSIFLINK = SIOCSIFLINK; - unsigned IOCTL_SIOCSIFMAP = SIOCSIFMAP; - unsigned IOCTL_SIOCSIFMEM = SIOCSIFMEM; - unsigned IOCTL_SIOCSIFSLAVE = SIOCSIFSLAVE; - unsigned IOCTL_SIOCSRARP = SIOCSRARP; -# if SOUND_VERSION >= 0x040000 - unsigned IOCTL_SNDCTL_COPR_HALT = IOCTL_NOT_PRESENT; - unsigned IOCTL_SNDCTL_COPR_LOAD = IOCTL_NOT_PRESENT; - unsigned IOCTL_SNDCTL_COPR_RCODE = IOCTL_NOT_PRESENT; - unsigned IOCTL_SNDCTL_COPR_RCVMSG = IOCTL_NOT_PRESENT; - unsigned IOCTL_SNDCTL_COPR_RDATA = IOCTL_NOT_PRESENT; - unsigned IOCTL_SNDCTL_COPR_RESET = IOCTL_NOT_PRESENT; - unsigned IOCTL_SNDCTL_COPR_RUN = IOCTL_NOT_PRESENT; - unsigned IOCTL_SNDCTL_COPR_SENDMSG = IOCTL_NOT_PRESENT; - unsigned IOCTL_SNDCTL_COPR_WCODE = IOCTL_NOT_PRESENT; - unsigned IOCTL_SNDCTL_COPR_WDATA = IOCTL_NOT_PRESENT; - unsigned IOCTL_SOUND_PCM_READ_BITS = IOCTL_NOT_PRESENT; - unsigned IOCTL_SOUND_PCM_READ_CHANNELS = IOCTL_NOT_PRESENT; - unsigned IOCTL_SOUND_PCM_READ_FILTER = IOCTL_NOT_PRESENT; - unsigned IOCTL_SOUND_PCM_READ_RATE = IOCTL_NOT_PRESENT; - unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = IOCTL_NOT_PRESENT; - unsigned IOCTL_SOUND_PCM_WRITE_FILTER = IOCTL_NOT_PRESENT; -# else // SOUND_VERSION - unsigned IOCTL_SNDCTL_COPR_HALT = SNDCTL_COPR_HALT; - unsigned IOCTL_SNDCTL_COPR_LOAD = SNDCTL_COPR_LOAD; - unsigned IOCTL_SNDCTL_COPR_RCODE = SNDCTL_COPR_RCODE; - unsigned IOCTL_SNDCTL_COPR_RCVMSG = SNDCTL_COPR_RCVMSG; - unsigned IOCTL_SNDCTL_COPR_RDATA = SNDCTL_COPR_RDATA; - unsigned IOCTL_SNDCTL_COPR_RESET = SNDCTL_COPR_RESET; - unsigned IOCTL_SNDCTL_COPR_RUN = SNDCTL_COPR_RUN; - unsigned IOCTL_SNDCTL_COPR_SENDMSG = SNDCTL_COPR_SENDMSG; - unsigned IOCTL_SNDCTL_COPR_WCODE = SNDCTL_COPR_WCODE; - unsigned IOCTL_SNDCTL_COPR_WDATA = SNDCTL_COPR_WDATA; - unsigned IOCTL_SOUND_PCM_READ_BITS = SOUND_PCM_READ_BITS; - unsigned IOCTL_SOUND_PCM_READ_CHANNELS = SOUND_PCM_READ_CHANNELS; - unsigned IOCTL_SOUND_PCM_READ_FILTER = SOUND_PCM_READ_FILTER; - unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE; - unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = SOUND_PCM_WRITE_CHANNELS; - unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER; -#endif // SOUND_VERSION - unsigned IOCTL_TCFLSH = TCFLSH; - unsigned IOCTL_TCGETA = TCGETA; - unsigned IOCTL_TCGETS = TCGETS; - unsigned IOCTL_TCSBRK = TCSBRK; - unsigned IOCTL_TCSBRKP = TCSBRKP; - unsigned IOCTL_TCSETA = TCSETA; - unsigned IOCTL_TCSETAF = TCSETAF; - unsigned IOCTL_TCSETAW = TCSETAW; - unsigned IOCTL_TCSETS = TCSETS; - unsigned IOCTL_TCSETSF = TCSETSF; - unsigned IOCTL_TCSETSW = TCSETSW; - unsigned IOCTL_TCXONC = TCXONC; - unsigned IOCTL_TIOCGLCKTRMIOS = TIOCGLCKTRMIOS; - unsigned IOCTL_TIOCGSOFTCAR = TIOCGSOFTCAR; - unsigned IOCTL_TIOCINQ = TIOCINQ; - unsigned IOCTL_TIOCLINUX = TIOCLINUX; - unsigned IOCTL_TIOCSERCONFIG = TIOCSERCONFIG; - unsigned IOCTL_TIOCSERGETLSR = TIOCSERGETLSR; - unsigned IOCTL_TIOCSERGWILD = TIOCSERGWILD; - unsigned IOCTL_TIOCSERSWILD = TIOCSERSWILD; - unsigned IOCTL_TIOCSLCKTRMIOS = TIOCSLCKTRMIOS; - unsigned IOCTL_TIOCSSOFTCAR = TIOCSSOFTCAR; - unsigned IOCTL_VT_DISALLOCATE = VT_DISALLOCATE; - unsigned IOCTL_VT_GETSTATE = VT_GETSTATE; - unsigned IOCTL_VT_RESIZE = VT_RESIZE; - unsigned IOCTL_VT_RESIZEX = VT_RESIZEX; - unsigned IOCTL_VT_SENDSIG = VT_SENDSIG; - unsigned IOCTL_MTIOCGET = MTIOCGET; - unsigned IOCTL_MTIOCTOP = MTIOCTOP; - unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; - unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; - unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; - unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; - unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; - unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; - unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; - unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; - unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; - unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; - unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; - unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE; - unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR; - unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO; - unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME; - unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE; - unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT; - unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT; - unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS; - unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS; - unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND; - unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC; - unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE; - unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET; - unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES; - unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC; - unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI; - unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD; - unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO; - unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL; - unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE; - unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME; - unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT; - unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE; - unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START; - unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP; - unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO; - unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE; - unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM; - unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS; - unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS; - unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD; - unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK; - unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE; - unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN; - unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX; - unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE; - unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1; - unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2; - unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3; - unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD; - unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC; - unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE; - unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN; - unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM; - unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV; - unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK; - unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC; - unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER; - unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS; - unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH; - unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE; - unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME; - unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM; - unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS; - unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD; - unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE; - unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN; - unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3; - unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD; - unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC; - unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE; - unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN; - unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM; - unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV; - unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC; - unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER; - unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH; - unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE; - unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME; - unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; - unsigned IOCTL_VT_GETMODE = VT_GETMODE; - unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; - unsigned IOCTL_VT_RELDISP = VT_RELDISP; - unsigned IOCTL_VT_SETMODE = VT_SETMODE; - unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; -#endif // SANITIZER_LINUX - -#if SANITIZER_LINUX && !SANITIZER_ANDROID - unsigned IOCTL_CYGETDEFTHRESH = CYGETDEFTHRESH; - unsigned IOCTL_CYGETDEFTIMEOUT = CYGETDEFTIMEOUT; - unsigned IOCTL_CYGETMON = CYGETMON; - unsigned IOCTL_CYGETTHRESH = CYGETTHRESH; - unsigned IOCTL_CYGETTIMEOUT = CYGETTIMEOUT; - unsigned IOCTL_CYSETDEFTHRESH = CYSETDEFTHRESH; - unsigned IOCTL_CYSETDEFTIMEOUT = CYSETDEFTIMEOUT; - unsigned IOCTL_CYSETTHRESH = CYSETTHRESH; - unsigned IOCTL_CYSETTIMEOUT = CYSETTIMEOUT; - unsigned IOCTL_EQL_EMANCIPATE = EQL_EMANCIPATE; - unsigned IOCTL_EQL_ENSLAVE = EQL_ENSLAVE; - unsigned IOCTL_EQL_GETMASTRCFG = EQL_GETMASTRCFG; - unsigned IOCTL_EQL_GETSLAVECFG = EQL_GETSLAVECFG; - unsigned IOCTL_EQL_SETMASTRCFG = EQL_SETMASTRCFG; - unsigned IOCTL_EQL_SETSLAVECFG = EQL_SETSLAVECFG; -#if EV_VERSION > (0x010000) - unsigned IOCTL_EVIOCGKEYCODE_V2 = EVIOCGKEYCODE_V2; - unsigned IOCTL_EVIOCGPROP = EVIOCGPROP(0); - unsigned IOCTL_EVIOCSKEYCODE_V2 = EVIOCSKEYCODE_V2; -#else - unsigned IOCTL_EVIOCGKEYCODE_V2 = IOCTL_NOT_PRESENT; - unsigned IOCTL_EVIOCGPROP = IOCTL_NOT_PRESENT; - unsigned IOCTL_EVIOCSKEYCODE_V2 = IOCTL_NOT_PRESENT; -#endif - unsigned IOCTL_FS_IOC_GETFLAGS = FS_IOC_GETFLAGS; - unsigned IOCTL_FS_IOC_GETVERSION = FS_IOC_GETVERSION; - unsigned IOCTL_FS_IOC_SETFLAGS = FS_IOC_SETFLAGS; - unsigned IOCTL_FS_IOC_SETVERSION = FS_IOC_SETVERSION; - unsigned IOCTL_GIO_CMAP = GIO_CMAP; - unsigned IOCTL_GIO_FONT = GIO_FONT; - unsigned IOCTL_GIO_UNIMAP = GIO_UNIMAP; - unsigned IOCTL_GIO_UNISCRNMAP = GIO_UNISCRNMAP; - unsigned IOCTL_KDADDIO = KDADDIO; - unsigned IOCTL_KDDELIO = KDDELIO; - unsigned IOCTL_KDGETKEYCODE = KDGETKEYCODE; - unsigned IOCTL_KDGKBDIACR = KDGKBDIACR; - unsigned IOCTL_KDGKBENT = KDGKBENT; - unsigned IOCTL_KDGKBLED = KDGKBLED; - unsigned IOCTL_KDGKBMETA = KDGKBMETA; - unsigned IOCTL_KDGKBSENT = KDGKBSENT; - unsigned IOCTL_KDMAPDISP = KDMAPDISP; - unsigned IOCTL_KDSETKEYCODE = KDSETKEYCODE; - unsigned IOCTL_KDSIGACCEPT = KDSIGACCEPT; - unsigned IOCTL_KDSKBDIACR = KDSKBDIACR; - unsigned IOCTL_KDSKBENT = KDSKBENT; - unsigned IOCTL_KDSKBLED = KDSKBLED; - unsigned IOCTL_KDSKBMETA = KDSKBMETA; - unsigned IOCTL_KDSKBSENT = KDSKBSENT; - unsigned IOCTL_KDUNMAPDISP = KDUNMAPDISP; - unsigned IOCTL_LPABORT = LPABORT; - unsigned IOCTL_LPABORTOPEN = LPABORTOPEN; - unsigned IOCTL_LPCAREFUL = LPCAREFUL; - unsigned IOCTL_LPCHAR = LPCHAR; - unsigned IOCTL_LPGETIRQ = LPGETIRQ; - unsigned IOCTL_LPGETSTATUS = LPGETSTATUS; - unsigned IOCTL_LPRESET = LPRESET; - unsigned IOCTL_LPSETIRQ = LPSETIRQ; - unsigned IOCTL_LPTIME = LPTIME; - unsigned IOCTL_LPWAIT = LPWAIT; - unsigned IOCTL_MTIOCGETCONFIG = MTIOCGETCONFIG; - unsigned IOCTL_MTIOCSETCONFIG = MTIOCSETCONFIG; - unsigned IOCTL_PIO_CMAP = PIO_CMAP; - unsigned IOCTL_PIO_FONT = PIO_FONT; - unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP; - unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR; - unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP; - unsigned IOCTL_SCSI_IOCTL_GET_IDLUN = SCSI_IOCTL_GET_IDLUN; - unsigned IOCTL_SCSI_IOCTL_PROBE_HOST = SCSI_IOCTL_PROBE_HOST; - unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE = SCSI_IOCTL_TAGGED_DISABLE; - unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE = SCSI_IOCTL_TAGGED_ENABLE; - unsigned IOCTL_SIOCAIPXITFCRT = SIOCAIPXITFCRT; - unsigned IOCTL_SIOCAIPXPRISLT = SIOCAIPXPRISLT; - unsigned IOCTL_SIOCAX25ADDUID = SIOCAX25ADDUID; - unsigned IOCTL_SIOCAX25DELUID = SIOCAX25DELUID; - unsigned IOCTL_SIOCAX25GETPARMS = SIOCAX25GETPARMS; - unsigned IOCTL_SIOCAX25GETUID = SIOCAX25GETUID; - unsigned IOCTL_SIOCAX25NOUID = SIOCAX25NOUID; - unsigned IOCTL_SIOCAX25SETPARMS = SIOCAX25SETPARMS; - unsigned IOCTL_SIOCDEVPLIP = SIOCDEVPLIP; - unsigned IOCTL_SIOCIPXCFGDATA = SIOCIPXCFGDATA; - unsigned IOCTL_SIOCNRDECOBS = SIOCNRDECOBS; - unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS; - unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL; - unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS; - unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL; - unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI; - unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI; - unsigned IOCTL_TIOCSSERIAL = TIOCSSERIAL; -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID - -#if SANITIZER_LINUX && !SANITIZER_ANDROID - unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP; - unsigned IOCTL_KDDISABIO = KDDISABIO; - unsigned IOCTL_KDENABIO = KDENABIO; - unsigned IOCTL_KDGETLED = KDGETLED; - unsigned IOCTL_KDGETMODE = KDGETMODE; - unsigned IOCTL_KDGKBMODE = KDGKBMODE; - unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; - unsigned IOCTL_KDMKTONE = KDMKTONE; - unsigned IOCTL_KDSETLED = KDSETLED; - unsigned IOCTL_KDSETMODE = KDSETMODE; - unsigned IOCTL_KDSKBMODE = KDSKBMODE; - unsigned IOCTL_KIOCSOUND = KIOCSOUND; - unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP; - unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; - unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE; -#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID - - const int si_SEGV_MAPERR = SEGV_MAPERR; - const int si_SEGV_ACCERR = SEGV_ACCERR; -} // namespace __sanitizer - -using namespace __sanitizer; - -COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); - -COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); -CHECK_TYPE_SIZE(pthread_key_t); - -#if SANITIZER_LINUX -// FIXME: We define those on Linux and Mac, but only check on Linux. -COMPILER_CHECK(IOC_NRBITS == _IOC_NRBITS); -COMPILER_CHECK(IOC_TYPEBITS == _IOC_TYPEBITS); -COMPILER_CHECK(IOC_SIZEBITS == _IOC_SIZEBITS); -COMPILER_CHECK(IOC_DIRBITS == _IOC_DIRBITS); -COMPILER_CHECK(IOC_NRMASK == _IOC_NRMASK); -COMPILER_CHECK(IOC_TYPEMASK == _IOC_TYPEMASK); -COMPILER_CHECK(IOC_SIZEMASK == _IOC_SIZEMASK); -COMPILER_CHECK(IOC_DIRMASK == _IOC_DIRMASK); -COMPILER_CHECK(IOC_NRSHIFT == _IOC_NRSHIFT); -COMPILER_CHECK(IOC_TYPESHIFT == _IOC_TYPESHIFT); -COMPILER_CHECK(IOC_SIZESHIFT == _IOC_SIZESHIFT); -COMPILER_CHECK(IOC_DIRSHIFT == _IOC_DIRSHIFT); -COMPILER_CHECK(IOC_NONE == _IOC_NONE); -COMPILER_CHECK(IOC_WRITE == _IOC_WRITE); -COMPILER_CHECK(IOC_READ == _IOC_READ); -COMPILER_CHECK(EVIOC_ABS_MAX == ABS_MAX); -COMPILER_CHECK(EVIOC_EV_MAX == EV_MAX); -COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678)); -COMPILER_CHECK(IOC_DIR(0x12345678) == _IOC_DIR(0x12345678)); -COMPILER_CHECK(IOC_NR(0x12345678) == _IOC_NR(0x12345678)); -COMPILER_CHECK(IOC_TYPE(0x12345678) == _IOC_TYPE(0x12345678)); -#endif // SANITIZER_LINUX - -#if SANITIZER_LINUX || SANITIZER_FREEBSD -// There are more undocumented fields in dl_phdr_info that we are not interested -// in. -COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); -#endif // SANITIZER_LINUX || SANITIZER_FREEBSD - -#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID -CHECK_TYPE_SIZE(glob_t); -CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); -CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); -CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); -CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); -CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); -CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); -CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); -CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); -CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); -#endif - -CHECK_TYPE_SIZE(addrinfo); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); - -CHECK_TYPE_SIZE(hostent); -CHECK_SIZE_AND_OFFSET(hostent, h_name); -CHECK_SIZE_AND_OFFSET(hostent, h_aliases); -CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); -CHECK_SIZE_AND_OFFSET(hostent, h_length); -CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); - -CHECK_TYPE_SIZE(iovec); -CHECK_SIZE_AND_OFFSET(iovec, iov_base); -CHECK_SIZE_AND_OFFSET(iovec, iov_len); - -CHECK_TYPE_SIZE(msghdr); -CHECK_SIZE_AND_OFFSET(msghdr, msg_name); -CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); -CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_control); -CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); - -CHECK_TYPE_SIZE(cmsghdr); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); - -#ifndef __GLIBC_PREREQ -#define __GLIBC_PREREQ(x, y) 0 -#endif - -#if SANITIZER_LINUX && (__ANDROID_API__ >= 21 || __GLIBC_PREREQ (2, 14)) -CHECK_TYPE_SIZE(mmsghdr); -CHECK_SIZE_AND_OFFSET(mmsghdr, msg_hdr); -CHECK_SIZE_AND_OFFSET(mmsghdr, msg_len); -#endif - -COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); -CHECK_SIZE_AND_OFFSET(dirent, d_ino); -#if SANITIZER_MAC -CHECK_SIZE_AND_OFFSET(dirent, d_seekoff); -#elif SANITIZER_FREEBSD -// There is no 'd_off' field on FreeBSD. -#else -CHECK_SIZE_AND_OFFSET(dirent, d_off); -#endif -CHECK_SIZE_AND_OFFSET(dirent, d_reclen); - -#if SANITIZER_LINUX && !SANITIZER_ANDROID -COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64)); -CHECK_SIZE_AND_OFFSET(dirent64, d_ino); -CHECK_SIZE_AND_OFFSET(dirent64, d_off); -CHECK_SIZE_AND_OFFSET(dirent64, d_reclen); -#endif - -CHECK_TYPE_SIZE(ifconf); -CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); -CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); - -CHECK_TYPE_SIZE(pollfd); -CHECK_SIZE_AND_OFFSET(pollfd, fd); -CHECK_SIZE_AND_OFFSET(pollfd, events); -CHECK_SIZE_AND_OFFSET(pollfd, revents); - -CHECK_TYPE_SIZE(nfds_t); - -CHECK_TYPE_SIZE(sigset_t); - -COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); -// Can't write checks for sa_handler and sa_sigaction due to them being -// preprocessor macros. -CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); -#if !defined(__s390x__) || __GLIBC_PREREQ (2, 20) -// On s390x glibc 2.19 and earlier sa_flags was unsigned long, and sa_resv -// didn't exist. -CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags); -#endif -#if SANITIZER_LINUX && (!SANITIZER_ANDROID || !SANITIZER_MIPS32) -CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer); -#endif - -#if SANITIZER_LINUX -CHECK_TYPE_SIZE(__sysctl_args); -CHECK_SIZE_AND_OFFSET(__sysctl_args, name); -CHECK_SIZE_AND_OFFSET(__sysctl_args, nlen); -CHECK_SIZE_AND_OFFSET(__sysctl_args, oldval); -CHECK_SIZE_AND_OFFSET(__sysctl_args, oldlenp); -CHECK_SIZE_AND_OFFSET(__sysctl_args, newval); -CHECK_SIZE_AND_OFFSET(__sysctl_args, newlen); - -CHECK_TYPE_SIZE(__kernel_uid_t); -CHECK_TYPE_SIZE(__kernel_gid_t); - -#if SANITIZER_USES_UID16_SYSCALLS -CHECK_TYPE_SIZE(__kernel_old_uid_t); -CHECK_TYPE_SIZE(__kernel_old_gid_t); -#endif - -CHECK_TYPE_SIZE(__kernel_off_t); -CHECK_TYPE_SIZE(__kernel_loff_t); -CHECK_TYPE_SIZE(__kernel_fd_set); -#endif - -#if !SANITIZER_ANDROID -CHECK_TYPE_SIZE(wordexp_t); -CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); -CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); -CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); -#endif - -CHECK_TYPE_SIZE(tm); -CHECK_SIZE_AND_OFFSET(tm, tm_sec); -CHECK_SIZE_AND_OFFSET(tm, tm_min); -CHECK_SIZE_AND_OFFSET(tm, tm_hour); -CHECK_SIZE_AND_OFFSET(tm, tm_mday); -CHECK_SIZE_AND_OFFSET(tm, tm_mon); -CHECK_SIZE_AND_OFFSET(tm, tm_year); -CHECK_SIZE_AND_OFFSET(tm, tm_wday); -CHECK_SIZE_AND_OFFSET(tm, tm_yday); -CHECK_SIZE_AND_OFFSET(tm, tm_isdst); -CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); -CHECK_SIZE_AND_OFFSET(tm, tm_zone); - -#if SANITIZER_LINUX -CHECK_TYPE_SIZE(mntent); -CHECK_SIZE_AND_OFFSET(mntent, mnt_fsname); -CHECK_SIZE_AND_OFFSET(mntent, mnt_dir); -CHECK_SIZE_AND_OFFSET(mntent, mnt_type); -CHECK_SIZE_AND_OFFSET(mntent, mnt_opts); -CHECK_SIZE_AND_OFFSET(mntent, mnt_freq); -CHECK_SIZE_AND_OFFSET(mntent, mnt_passno); -#endif - -CHECK_TYPE_SIZE(ether_addr); - -#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID -CHECK_TYPE_SIZE(ipc_perm); -# if SANITIZER_FREEBSD -CHECK_SIZE_AND_OFFSET(ipc_perm, key); -CHECK_SIZE_AND_OFFSET(ipc_perm, seq); -# else -CHECK_SIZE_AND_OFFSET(ipc_perm, __key); -CHECK_SIZE_AND_OFFSET(ipc_perm, __seq); -# endif -CHECK_SIZE_AND_OFFSET(ipc_perm, uid); -CHECK_SIZE_AND_OFFSET(ipc_perm, gid); -CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); -CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); -#if !defined(__aarch64__) || !SANITIZER_LINUX || __GLIBC_PREREQ (2, 21) -/* On aarch64 glibc 2.20 and earlier provided incorrect mode field. */ -CHECK_SIZE_AND_OFFSET(ipc_perm, mode); -#endif - -CHECK_TYPE_SIZE(shmid_ds); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); -#endif - -CHECK_TYPE_SIZE(clock_t); - -#if SANITIZER_LINUX -CHECK_TYPE_SIZE(clockid_t); -#endif - -#if !SANITIZER_ANDROID -CHECK_TYPE_SIZE(ifaddrs); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); -#if SANITIZER_LINUX || SANITIZER_FREEBSD -// Compare against the union, because we can't reach into the union in a -// compliant way. -#ifdef ifa_dstaddr -#undef ifa_dstaddr -#endif -# if SANITIZER_FREEBSD -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); -# else -COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)nullptr)->ifa_dstaddr) == - sizeof(((ifaddrs *)nullptr)->ifa_ifu)); -COMPILER_CHECK(offsetof(__sanitizer_ifaddrs, ifa_dstaddr) == - offsetof(ifaddrs, ifa_ifu)); -# endif // SANITIZER_FREEBSD -#else -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); -#endif // SANITIZER_LINUX -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); -#endif - -#if SANITIZER_LINUX -COMPILER_CHECK(sizeof(__sanitizer_struct_mallinfo) == sizeof(struct mallinfo)); -#endif - -#if !SANITIZER_ANDROID -CHECK_TYPE_SIZE(timeb); -CHECK_SIZE_AND_OFFSET(timeb, time); -CHECK_SIZE_AND_OFFSET(timeb, millitm); -CHECK_SIZE_AND_OFFSET(timeb, timezone); -CHECK_SIZE_AND_OFFSET(timeb, dstflag); -#endif - -CHECK_TYPE_SIZE(passwd); -CHECK_SIZE_AND_OFFSET(passwd, pw_name); -CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); -CHECK_SIZE_AND_OFFSET(passwd, pw_uid); -CHECK_SIZE_AND_OFFSET(passwd, pw_gid); -CHECK_SIZE_AND_OFFSET(passwd, pw_dir); -CHECK_SIZE_AND_OFFSET(passwd, pw_shell); - -#if !SANITIZER_ANDROID -CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); -#endif - -#if SANITIZER_MAC -CHECK_SIZE_AND_OFFSET(passwd, pw_change); -CHECK_SIZE_AND_OFFSET(passwd, pw_expire); -CHECK_SIZE_AND_OFFSET(passwd, pw_class); -#endif - - -CHECK_TYPE_SIZE(group); -CHECK_SIZE_AND_OFFSET(group, gr_name); -CHECK_SIZE_AND_OFFSET(group, gr_passwd); -CHECK_SIZE_AND_OFFSET(group, gr_gid); -CHECK_SIZE_AND_OFFSET(group, gr_mem); - -#if HAVE_RPC_XDR_H -CHECK_TYPE_SIZE(XDR); -CHECK_SIZE_AND_OFFSET(XDR, x_op); -CHECK_SIZE_AND_OFFSET(XDR, x_ops); -CHECK_SIZE_AND_OFFSET(XDR, x_public); -CHECK_SIZE_AND_OFFSET(XDR, x_private); -CHECK_SIZE_AND_OFFSET(XDR, x_base); -CHECK_SIZE_AND_OFFSET(XDR, x_handy); -COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE); -COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); -COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); -#endif - -#if SANITIZER_LINUX && !SANITIZER_ANDROID -COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE)); -CHECK_SIZE_AND_OFFSET(FILE, _flags); -CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr); -CHECK_SIZE_AND_OFFSET(FILE, _IO_read_end); -CHECK_SIZE_AND_OFFSET(FILE, _IO_read_base); -CHECK_SIZE_AND_OFFSET(FILE, _IO_write_ptr); -CHECK_SIZE_AND_OFFSET(FILE, _IO_write_end); -CHECK_SIZE_AND_OFFSET(FILE, _IO_write_base); -CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_base); -CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_end); -CHECK_SIZE_AND_OFFSET(FILE, _IO_save_base); -CHECK_SIZE_AND_OFFSET(FILE, _IO_backup_base); -CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end); -CHECK_SIZE_AND_OFFSET(FILE, _markers); -CHECK_SIZE_AND_OFFSET(FILE, _chain); -CHECK_SIZE_AND_OFFSET(FILE, _fileno); -#endif - -#if SANITIZER_LINUX && !SANITIZER_ANDROID -COMPILER_CHECK(sizeof(__sanitizer__obstack_chunk) <= sizeof(_obstack_chunk)); -CHECK_SIZE_AND_OFFSET(_obstack_chunk, limit); -CHECK_SIZE_AND_OFFSET(_obstack_chunk, prev); -CHECK_TYPE_SIZE(obstack); -CHECK_SIZE_AND_OFFSET(obstack, chunk_size); -CHECK_SIZE_AND_OFFSET(obstack, chunk); -CHECK_SIZE_AND_OFFSET(obstack, object_base); -CHECK_SIZE_AND_OFFSET(obstack, next_free); - -CHECK_TYPE_SIZE(cookie_io_functions_t); -CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, read); -CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, write); -CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, seek); -CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, close); -#endif - -#if SANITIZER_LINUX || SANITIZER_FREEBSD -CHECK_TYPE_SIZE(sem_t); -#endif - -#if SANITIZER_LINUX && defined(__arm__) -COMPILER_CHECK(ARM_VFPREGS_SIZE == ARM_VFPREGS_SIZE_ASAN); -#endif - -#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp b/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp new file mode 100644 index 000000000000..9852e6ba7879 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp @@ -0,0 +1,1276 @@ +//===-- sanitizer_platform_limits_posix.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific POSIX data structures. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_LINUX || SANITIZER_MAC +// Tests in this file assume that off_t-dependent data structures match the +// libc ABI. For example, struct dirent here is what readdir() function (as +// exported from libc) returns, and not the user-facing "dirent", which +// depends on _FILE_OFFSET_BITS setting. +// To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below. +#ifdef _FILE_OFFSET_BITS +#undef _FILE_OFFSET_BITS +#endif + +// Must go after undef _FILE_OFFSET_BITS. +#include "sanitizer_glibc_version.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !SANITIZER_MAC +#include +#endif + +#if !SANITIZER_IOS +#include +#endif + +#if !SANITIZER_ANDROID +#include +#include +#include +#include +#endif + +#if SANITIZER_LINUX +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#if SANITIZER_IOS +#undef IOC_DIRMASK +#endif + +#if SANITIZER_LINUX +# include +# include +# if defined(__mips64) || defined(__aarch64__) || defined(__arm__) +# include +# ifdef __arm__ +typedef struct user_fpregs elf_fpregset_t; +# define ARM_VFPREGS_SIZE_ASAN (32 * 8 /*fpregs*/ + 4 /*fpscr*/) +# if !defined(ARM_VFPREGS_SIZE) +# define ARM_VFPREGS_SIZE ARM_VFPREGS_SIZE_ASAN +# endif +# endif +# endif +# include +#endif + +#if !SANITIZER_ANDROID +#include +#include +#include +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +#include +#include +#include +#include +#include +#include +#include +#if HAVE_RPC_XDR_H +# include +#endif +#include +#include +#include +#include +#include +#include +#if defined(__mips64) +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID + +#if SANITIZER_ANDROID +#include +#include +#include +#include +#endif + +#if SANITIZER_LINUX +#include +#include +#include +#include +#endif // SANITIZER_LINUX + +#if SANITIZER_MAC +#include +#include +#include +#endif + +// Include these after system headers to avoid name clashes and ambiguities. +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform_limits_posix.h" + +namespace __sanitizer { + unsigned struct_utsname_sz = sizeof(struct utsname); + unsigned struct_stat_sz = sizeof(struct stat); +#if !SANITIZER_IOS + unsigned struct_stat64_sz = sizeof(struct stat64); +#endif // !SANITIZER_IOS + unsigned struct_rusage_sz = sizeof(struct rusage); + unsigned struct_tm_sz = sizeof(struct tm); + unsigned struct_passwd_sz = sizeof(struct passwd); + unsigned struct_group_sz = sizeof(struct group); + unsigned siginfo_t_sz = sizeof(siginfo_t); + unsigned struct_sigaction_sz = sizeof(struct sigaction); + unsigned struct_itimerval_sz = sizeof(struct itimerval); + unsigned pthread_t_sz = sizeof(pthread_t); + unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); + unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); + unsigned pid_t_sz = sizeof(pid_t); + unsigned timeval_sz = sizeof(timeval); + unsigned uid_t_sz = sizeof(uid_t); + unsigned gid_t_sz = sizeof(gid_t); + unsigned mbstate_t_sz = sizeof(mbstate_t); + unsigned sigset_t_sz = sizeof(sigset_t); + unsigned struct_timezone_sz = sizeof(struct timezone); + unsigned struct_tms_sz = sizeof(struct tms); + unsigned struct_sigevent_sz = sizeof(struct sigevent); + unsigned struct_sched_param_sz = sizeof(struct sched_param); + unsigned struct_regex_sz = sizeof(regex_t); + unsigned struct_regmatch_sz = sizeof(regmatch_t); + +#if SANITIZER_MAC && !SANITIZER_IOS + unsigned struct_statfs64_sz = sizeof(struct statfs64); +#endif // SANITIZER_MAC && !SANITIZER_IOS + +#if !SANITIZER_ANDROID + unsigned struct_fstab_sz = sizeof(struct fstab); + unsigned struct_statfs_sz = sizeof(struct statfs); + unsigned struct_sockaddr_sz = sizeof(struct sockaddr); + unsigned ucontext_t_sz = sizeof(ucontext_t); +#endif // !SANITIZER_ANDROID + +#if SANITIZER_LINUX + unsigned struct_epoll_event_sz = sizeof(struct epoll_event); + unsigned struct_sysinfo_sz = sizeof(struct sysinfo); + unsigned __user_cap_header_struct_sz = + sizeof(struct __user_cap_header_struct); + unsigned __user_cap_data_struct_sz = sizeof(struct __user_cap_data_struct); + unsigned struct_new_utsname_sz = sizeof(struct new_utsname); + unsigned struct_old_utsname_sz = sizeof(struct old_utsname); + unsigned struct_oldold_utsname_sz = sizeof(struct oldold_utsname); +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX + unsigned struct_rlimit_sz = sizeof(struct rlimit); + unsigned struct_timespec_sz = sizeof(struct timespec); + unsigned struct_utimbuf_sz = sizeof(struct utimbuf); + unsigned struct_itimerspec_sz = sizeof(struct itimerspec); +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + // Use pre-computed size of struct ustat to avoid which + // has been removed from glibc 2.28. +#if defined(__aarch64__) || defined(__s390x__) || defined (__mips64) \ + || defined(__powerpc64__) || defined(__arch64__) || defined(__sparcv9) \ + || defined(__x86_64__) +#define SIZEOF_STRUCT_USTAT 32 +#elif defined(__arm__) || defined(__i386__) || defined(__mips__) \ + || defined(__powerpc__) || defined(__s390__) || defined(__sparc__) +#define SIZEOF_STRUCT_USTAT 20 +#else +#error Unknown size of struct ustat +#endif + unsigned struct_ustat_sz = SIZEOF_STRUCT_USTAT; + unsigned struct_rlimit64_sz = sizeof(struct rlimit64); + unsigned struct_statvfs64_sz = sizeof(struct statvfs64); + unsigned struct_crypt_data_sz = sizeof(struct crypt_data); +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + unsigned struct_timex_sz = sizeof(struct timex); + unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); + unsigned struct_mq_attr_sz = sizeof(struct mq_attr); + unsigned struct_statvfs_sz = sizeof(struct statvfs); +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID + + const uptr sig_ign = (uptr)SIG_IGN; + const uptr sig_dfl = (uptr)SIG_DFL; + const uptr sig_err = (uptr)SIG_ERR; + const uptr sa_siginfo = (uptr)SA_SIGINFO; + +#if SANITIZER_LINUX + int e_tabsz = (int)E_TABSZ; +#endif + + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + unsigned struct_shminfo_sz = sizeof(struct shminfo); + unsigned struct_shm_info_sz = sizeof(struct shm_info); + int shmctl_ipc_stat = (int)IPC_STAT; + int shmctl_ipc_info = (int)IPC_INFO; + int shmctl_shm_info = (int)SHM_INFO; + int shmctl_shm_stat = (int)SHM_STAT; +#endif + +#if !SANITIZER_MAC && !SANITIZER_FREEBSD + unsigned struct_utmp_sz = sizeof(struct utmp); +#endif +#if !SANITIZER_ANDROID + unsigned struct_utmpx_sz = sizeof(struct utmpx); +#endif + + int map_fixed = MAP_FIXED; + + int af_inet = (int)AF_INET; + int af_inet6 = (int)AF_INET6; + + uptr __sanitizer_in_addr_sz(int af) { + if (af == AF_INET) + return sizeof(struct in_addr); + else if (af == AF_INET6) + return sizeof(struct in6_addr); + else + return 0; + } + +#if SANITIZER_LINUX +unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr)); +#elif SANITIZER_FREEBSD +unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + int glob_nomatch = GLOB_NOMATCH; + int glob_altdirfunc = GLOB_ALTDIRFUNC; +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ + defined(__s390__)) +#if defined(__mips64) || defined(__powerpc64__) || defined(__arm__) + unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs); + unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t); +#elif defined(__aarch64__) + unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs); + unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpsimd_state); +#elif defined(__s390__) + unsigned struct_user_regs_struct_sz = sizeof(struct _user_regs_struct); + unsigned struct_user_fpregs_struct_sz = sizeof(struct _user_fpregs_struct); +#else + unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct); + unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct); +#endif // __mips64 || __powerpc64__ || __aarch64__ +#if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \ + defined(__aarch64__) || defined(__arm__) || defined(__s390__) + unsigned struct_user_fpxregs_struct_sz = 0; +#else + unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct); +#endif // __x86_64 || __mips64 || __powerpc64__ || __aarch64__ || __arm__ +// || __s390__ +#ifdef __arm__ + unsigned struct_user_vfpregs_struct_sz = ARM_VFPREGS_SIZE; +#else + unsigned struct_user_vfpregs_struct_sz = 0; +#endif + + int ptrace_peektext = PTRACE_PEEKTEXT; + int ptrace_peekdata = PTRACE_PEEKDATA; + int ptrace_peekuser = PTRACE_PEEKUSER; +#if (defined(PTRACE_GETREGS) && defined(PTRACE_SETREGS)) || \ + (defined(PT_GETREGS) && defined(PT_SETREGS)) + int ptrace_getregs = PTRACE_GETREGS; + int ptrace_setregs = PTRACE_SETREGS; +#else + int ptrace_getregs = -1; + int ptrace_setregs = -1; +#endif +#if (defined(PTRACE_GETFPREGS) && defined(PTRACE_SETFPREGS)) || \ + (defined(PT_GETFPREGS) && defined(PT_SETFPREGS)) + int ptrace_getfpregs = PTRACE_GETFPREGS; + int ptrace_setfpregs = PTRACE_SETFPREGS; +#else + int ptrace_getfpregs = -1; + int ptrace_setfpregs = -1; +#endif +#if (defined(PTRACE_GETFPXREGS) && defined(PTRACE_SETFPXREGS)) || \ + (defined(PT_GETFPXREGS) && defined(PT_SETFPXREGS)) + int ptrace_getfpxregs = PTRACE_GETFPXREGS; + int ptrace_setfpxregs = PTRACE_SETFPXREGS; +#else + int ptrace_getfpxregs = -1; + int ptrace_setfpxregs = -1; +#endif // PTRACE_GETFPXREGS/PTRACE_SETFPXREGS +#if defined(PTRACE_GETVFPREGS) && defined(PTRACE_SETVFPREGS) + int ptrace_getvfpregs = PTRACE_GETVFPREGS; + int ptrace_setvfpregs = PTRACE_SETVFPREGS; +#else + int ptrace_getvfpregs = -1; + int ptrace_setvfpregs = -1; +#endif + int ptrace_geteventmsg = PTRACE_GETEVENTMSG; +#if (defined(PTRACE_GETSIGINFO) && defined(PTRACE_SETSIGINFO)) || \ + (defined(PT_GETSIGINFO) && defined(PT_SETSIGINFO)) + int ptrace_getsiginfo = PTRACE_GETSIGINFO; + int ptrace_setsiginfo = PTRACE_SETSIGINFO; +#else + int ptrace_getsiginfo = -1; + int ptrace_setsiginfo = -1; +#endif // PTRACE_GETSIGINFO/PTRACE_SETSIGINFO +#if defined(PTRACE_GETREGSET) && defined(PTRACE_SETREGSET) + int ptrace_getregset = PTRACE_GETREGSET; + int ptrace_setregset = PTRACE_SETREGSET; +#else + int ptrace_getregset = -1; + int ptrace_setregset = -1; +#endif // PTRACE_GETREGSET/PTRACE_SETREGSET +#endif + + unsigned path_max = PATH_MAX; + + // ioctl arguments + unsigned struct_ifreq_sz = sizeof(struct ifreq); + unsigned struct_termios_sz = sizeof(struct termios); + unsigned struct_winsize_sz = sizeof(struct winsize); + +#if SANITIZER_LINUX + unsigned struct_arpreq_sz = sizeof(struct arpreq); + unsigned struct_cdrom_msf_sz = sizeof(struct cdrom_msf); + unsigned struct_cdrom_multisession_sz = sizeof(struct cdrom_multisession); + unsigned struct_cdrom_read_audio_sz = sizeof(struct cdrom_read_audio); + unsigned struct_cdrom_subchnl_sz = sizeof(struct cdrom_subchnl); + unsigned struct_cdrom_ti_sz = sizeof(struct cdrom_ti); + unsigned struct_cdrom_tocentry_sz = sizeof(struct cdrom_tocentry); + unsigned struct_cdrom_tochdr_sz = sizeof(struct cdrom_tochdr); + unsigned struct_cdrom_volctrl_sz = sizeof(struct cdrom_volctrl); + unsigned struct_ff_effect_sz = sizeof(struct ff_effect); + unsigned struct_floppy_drive_params_sz = sizeof(struct floppy_drive_params); + unsigned struct_floppy_drive_struct_sz = sizeof(struct floppy_drive_struct); + unsigned struct_floppy_fdc_state_sz = sizeof(struct floppy_fdc_state); + unsigned struct_floppy_max_errors_sz = sizeof(struct floppy_max_errors); + unsigned struct_floppy_raw_cmd_sz = sizeof(struct floppy_raw_cmd); + unsigned struct_floppy_struct_sz = sizeof(struct floppy_struct); + unsigned struct_floppy_write_errors_sz = sizeof(struct floppy_write_errors); + unsigned struct_format_descr_sz = sizeof(struct format_descr); + unsigned struct_hd_driveid_sz = sizeof(struct hd_driveid); + unsigned struct_hd_geometry_sz = sizeof(struct hd_geometry); + unsigned struct_input_absinfo_sz = sizeof(struct input_absinfo); + unsigned struct_input_id_sz = sizeof(struct input_id); + unsigned struct_mtpos_sz = sizeof(struct mtpos); + unsigned struct_rtentry_sz = sizeof(struct rtentry); + unsigned struct_termio_sz = sizeof(struct termio); + unsigned struct_vt_consize_sz = sizeof(struct vt_consize); + unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes); + unsigned struct_vt_stat_sz = sizeof(struct vt_stat); +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX +#if SOUND_VERSION >= 0x040000 + unsigned struct_copr_buffer_sz = 0; + unsigned struct_copr_debug_buf_sz = 0; + unsigned struct_copr_msg_sz = 0; +#else + unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer); + unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf); + unsigned struct_copr_msg_sz = sizeof(struct copr_msg); +#endif + unsigned struct_midi_info_sz = sizeof(struct midi_info); + unsigned struct_mtget_sz = sizeof(struct mtget); + unsigned struct_mtop_sz = sizeof(struct mtop); + unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument); + unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec); + unsigned struct_synth_info_sz = sizeof(struct synth_info); + unsigned struct_vt_mode_sz = sizeof(struct vt_mode); +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct); + unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor); +#if EV_VERSION > (0x010000) + unsigned struct_input_keymap_entry_sz = sizeof(struct input_keymap_entry); +#else + unsigned struct_input_keymap_entry_sz = 0; +#endif + unsigned struct_ipx_config_data_sz = sizeof(struct ipx_config_data); + unsigned struct_kbdiacrs_sz = sizeof(struct kbdiacrs); + unsigned struct_kbentry_sz = sizeof(struct kbentry); + unsigned struct_kbkeycode_sz = sizeof(struct kbkeycode); + unsigned struct_kbsentry_sz = sizeof(struct kbsentry); + unsigned struct_mtconfiginfo_sz = sizeof(struct mtconfiginfo); + unsigned struct_nr_parms_struct_sz = sizeof(struct nr_parms_struct); + unsigned struct_scc_modem_sz = sizeof(struct scc_modem); + unsigned struct_scc_stat_sz = sizeof(struct scc_stat); + unsigned struct_serial_multiport_struct_sz + = sizeof(struct serial_multiport_struct); + unsigned struct_serial_struct_sz = sizeof(struct serial_struct); + unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25); + unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc); + unsigned struct_unimapinit_sz = sizeof(struct unimapinit); +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); + unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); +#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID + +#if !SANITIZER_ANDROID && !SANITIZER_MAC + unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); + unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); +#endif + + const unsigned long __sanitizer_bufsiz = BUFSIZ; + + const unsigned IOCTL_NOT_PRESENT = 0; + + unsigned IOCTL_FIOASYNC = FIOASYNC; + unsigned IOCTL_FIOCLEX = FIOCLEX; + unsigned IOCTL_FIOGETOWN = FIOGETOWN; + unsigned IOCTL_FIONBIO = FIONBIO; + unsigned IOCTL_FIONCLEX = FIONCLEX; + unsigned IOCTL_FIOSETOWN = FIOSETOWN; + unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; + unsigned IOCTL_SIOCATMARK = SIOCATMARK; + unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; + unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; + unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; + unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; + unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; + unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; + unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; + unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; + unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; + unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; + unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; + unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; + unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; + unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; + unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; + unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; + unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; + unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; + unsigned IOCTL_TIOCCONS = TIOCCONS; + unsigned IOCTL_TIOCEXCL = TIOCEXCL; + unsigned IOCTL_TIOCGETD = TIOCGETD; + unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; + unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; + unsigned IOCTL_TIOCMBIC = TIOCMBIC; + unsigned IOCTL_TIOCMBIS = TIOCMBIS; + unsigned IOCTL_TIOCMGET = TIOCMGET; + unsigned IOCTL_TIOCMSET = TIOCMSET; + unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; + unsigned IOCTL_TIOCNXCL = TIOCNXCL; + unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; + unsigned IOCTL_TIOCPKT = TIOCPKT; + unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; + unsigned IOCTL_TIOCSETD = TIOCSETD; + unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; + unsigned IOCTL_TIOCSTI = TIOCSTI; + unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; +#if SANITIZER_LINUX && !SANITIZER_ANDROID + unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; + unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; +#endif + +#if SANITIZER_LINUX + unsigned IOCTL_EVIOCGABS = EVIOCGABS(0); + unsigned IOCTL_EVIOCGBIT = EVIOCGBIT(0, 0); + unsigned IOCTL_EVIOCGEFFECTS = EVIOCGEFFECTS; + unsigned IOCTL_EVIOCGID = EVIOCGID; + unsigned IOCTL_EVIOCGKEY = EVIOCGKEY(0); + unsigned IOCTL_EVIOCGKEYCODE = EVIOCGKEYCODE; + unsigned IOCTL_EVIOCGLED = EVIOCGLED(0); + unsigned IOCTL_EVIOCGNAME = EVIOCGNAME(0); + unsigned IOCTL_EVIOCGPHYS = EVIOCGPHYS(0); + unsigned IOCTL_EVIOCGRAB = EVIOCGRAB; + unsigned IOCTL_EVIOCGREP = EVIOCGREP; + unsigned IOCTL_EVIOCGSND = EVIOCGSND(0); + unsigned IOCTL_EVIOCGSW = EVIOCGSW(0); + unsigned IOCTL_EVIOCGUNIQ = EVIOCGUNIQ(0); + unsigned IOCTL_EVIOCGVERSION = EVIOCGVERSION; + unsigned IOCTL_EVIOCRMFF = EVIOCRMFF; + unsigned IOCTL_EVIOCSABS = EVIOCSABS(0); + unsigned IOCTL_EVIOCSFF = EVIOCSFF; + unsigned IOCTL_EVIOCSKEYCODE = EVIOCSKEYCODE; + unsigned IOCTL_EVIOCSREP = EVIOCSREP; + unsigned IOCTL_BLKFLSBUF = BLKFLSBUF; + unsigned IOCTL_BLKGETSIZE = BLKGETSIZE; + unsigned IOCTL_BLKRAGET = BLKRAGET; + unsigned IOCTL_BLKRASET = BLKRASET; + unsigned IOCTL_BLKROGET = BLKROGET; + unsigned IOCTL_BLKROSET = BLKROSET; + unsigned IOCTL_BLKRRPART = BLKRRPART; + unsigned IOCTL_CDROMAUDIOBUFSIZ = CDROMAUDIOBUFSIZ; + unsigned IOCTL_CDROMEJECT = CDROMEJECT; + unsigned IOCTL_CDROMEJECT_SW = CDROMEJECT_SW; + unsigned IOCTL_CDROMMULTISESSION = CDROMMULTISESSION; + unsigned IOCTL_CDROMPAUSE = CDROMPAUSE; + unsigned IOCTL_CDROMPLAYMSF = CDROMPLAYMSF; + unsigned IOCTL_CDROMPLAYTRKIND = CDROMPLAYTRKIND; + unsigned IOCTL_CDROMREADAUDIO = CDROMREADAUDIO; + unsigned IOCTL_CDROMREADCOOKED = CDROMREADCOOKED; + unsigned IOCTL_CDROMREADMODE1 = CDROMREADMODE1; + unsigned IOCTL_CDROMREADMODE2 = CDROMREADMODE2; + unsigned IOCTL_CDROMREADRAW = CDROMREADRAW; + unsigned IOCTL_CDROMREADTOCENTRY = CDROMREADTOCENTRY; + unsigned IOCTL_CDROMREADTOCHDR = CDROMREADTOCHDR; + unsigned IOCTL_CDROMRESET = CDROMRESET; + unsigned IOCTL_CDROMRESUME = CDROMRESUME; + unsigned IOCTL_CDROMSEEK = CDROMSEEK; + unsigned IOCTL_CDROMSTART = CDROMSTART; + unsigned IOCTL_CDROMSTOP = CDROMSTOP; + unsigned IOCTL_CDROMSUBCHNL = CDROMSUBCHNL; + unsigned IOCTL_CDROMVOLCTRL = CDROMVOLCTRL; + unsigned IOCTL_CDROMVOLREAD = CDROMVOLREAD; + unsigned IOCTL_CDROM_GET_UPC = CDROM_GET_UPC; + unsigned IOCTL_FDCLRPRM = FDCLRPRM; + unsigned IOCTL_FDDEFPRM = FDDEFPRM; + unsigned IOCTL_FDFLUSH = FDFLUSH; + unsigned IOCTL_FDFMTBEG = FDFMTBEG; + unsigned IOCTL_FDFMTEND = FDFMTEND; + unsigned IOCTL_FDFMTTRK = FDFMTTRK; + unsigned IOCTL_FDGETDRVPRM = FDGETDRVPRM; + unsigned IOCTL_FDGETDRVSTAT = FDGETDRVSTAT; + unsigned IOCTL_FDGETDRVTYP = FDGETDRVTYP; + unsigned IOCTL_FDGETFDCSTAT = FDGETFDCSTAT; + unsigned IOCTL_FDGETMAXERRS = FDGETMAXERRS; + unsigned IOCTL_FDGETPRM = FDGETPRM; + unsigned IOCTL_FDMSGOFF = FDMSGOFF; + unsigned IOCTL_FDMSGON = FDMSGON; + unsigned IOCTL_FDPOLLDRVSTAT = FDPOLLDRVSTAT; + unsigned IOCTL_FDRAWCMD = FDRAWCMD; + unsigned IOCTL_FDRESET = FDRESET; + unsigned IOCTL_FDSETDRVPRM = FDSETDRVPRM; + unsigned IOCTL_FDSETEMSGTRESH = FDSETEMSGTRESH; + unsigned IOCTL_FDSETMAXERRS = FDSETMAXERRS; + unsigned IOCTL_FDSETPRM = FDSETPRM; + unsigned IOCTL_FDTWADDLE = FDTWADDLE; + unsigned IOCTL_FDWERRORCLR = FDWERRORCLR; + unsigned IOCTL_FDWERRORGET = FDWERRORGET; + unsigned IOCTL_HDIO_DRIVE_CMD = HDIO_DRIVE_CMD; + unsigned IOCTL_HDIO_GETGEO = HDIO_GETGEO; + unsigned IOCTL_HDIO_GET_32BIT = HDIO_GET_32BIT; + unsigned IOCTL_HDIO_GET_DMA = HDIO_GET_DMA; + unsigned IOCTL_HDIO_GET_IDENTITY = HDIO_GET_IDENTITY; + unsigned IOCTL_HDIO_GET_KEEPSETTINGS = HDIO_GET_KEEPSETTINGS; + unsigned IOCTL_HDIO_GET_MULTCOUNT = HDIO_GET_MULTCOUNT; + unsigned IOCTL_HDIO_GET_NOWERR = HDIO_GET_NOWERR; + unsigned IOCTL_HDIO_GET_UNMASKINTR = HDIO_GET_UNMASKINTR; + unsigned IOCTL_HDIO_SET_32BIT = HDIO_SET_32BIT; + unsigned IOCTL_HDIO_SET_DMA = HDIO_SET_DMA; + unsigned IOCTL_HDIO_SET_KEEPSETTINGS = HDIO_SET_KEEPSETTINGS; + unsigned IOCTL_HDIO_SET_MULTCOUNT = HDIO_SET_MULTCOUNT; + unsigned IOCTL_HDIO_SET_NOWERR = HDIO_SET_NOWERR; + unsigned IOCTL_HDIO_SET_UNMASKINTR = HDIO_SET_UNMASKINTR; + unsigned IOCTL_MTIOCPOS = MTIOCPOS; + unsigned IOCTL_PPPIOCGASYNCMAP = PPPIOCGASYNCMAP; + unsigned IOCTL_PPPIOCGDEBUG = PPPIOCGDEBUG; + unsigned IOCTL_PPPIOCGFLAGS = PPPIOCGFLAGS; + unsigned IOCTL_PPPIOCGUNIT = PPPIOCGUNIT; + unsigned IOCTL_PPPIOCGXASYNCMAP = PPPIOCGXASYNCMAP; + unsigned IOCTL_PPPIOCSASYNCMAP = PPPIOCSASYNCMAP; + unsigned IOCTL_PPPIOCSDEBUG = PPPIOCSDEBUG; + unsigned IOCTL_PPPIOCSFLAGS = PPPIOCSFLAGS; + unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID; + unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU; + unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP; + unsigned IOCTL_SIOCADDRT = SIOCADDRT; + unsigned IOCTL_SIOCDARP = SIOCDARP; + unsigned IOCTL_SIOCDELRT = SIOCDELRT; + unsigned IOCTL_SIOCDRARP = SIOCDRARP; + unsigned IOCTL_SIOCGARP = SIOCGARP; + unsigned IOCTL_SIOCGIFENCAP = SIOCGIFENCAP; + unsigned IOCTL_SIOCGIFHWADDR = SIOCGIFHWADDR; + unsigned IOCTL_SIOCGIFMAP = SIOCGIFMAP; + unsigned IOCTL_SIOCGIFMEM = SIOCGIFMEM; + unsigned IOCTL_SIOCGIFNAME = SIOCGIFNAME; + unsigned IOCTL_SIOCGIFSLAVE = SIOCGIFSLAVE; + unsigned IOCTL_SIOCGRARP = SIOCGRARP; + unsigned IOCTL_SIOCGSTAMP = SIOCGSTAMP; + unsigned IOCTL_SIOCSARP = SIOCSARP; + unsigned IOCTL_SIOCSIFENCAP = SIOCSIFENCAP; + unsigned IOCTL_SIOCSIFHWADDR = SIOCSIFHWADDR; + unsigned IOCTL_SIOCSIFLINK = SIOCSIFLINK; + unsigned IOCTL_SIOCSIFMAP = SIOCSIFMAP; + unsigned IOCTL_SIOCSIFMEM = SIOCSIFMEM; + unsigned IOCTL_SIOCSIFSLAVE = SIOCSIFSLAVE; + unsigned IOCTL_SIOCSRARP = SIOCSRARP; +# if SOUND_VERSION >= 0x040000 + unsigned IOCTL_SNDCTL_COPR_HALT = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_LOAD = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_RCODE = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_RCVMSG = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_RDATA = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_RESET = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_RUN = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_SENDMSG = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_WCODE = IOCTL_NOT_PRESENT; + unsigned IOCTL_SNDCTL_COPR_WDATA = IOCTL_NOT_PRESENT; + unsigned IOCTL_SOUND_PCM_READ_BITS = IOCTL_NOT_PRESENT; + unsigned IOCTL_SOUND_PCM_READ_CHANNELS = IOCTL_NOT_PRESENT; + unsigned IOCTL_SOUND_PCM_READ_FILTER = IOCTL_NOT_PRESENT; + unsigned IOCTL_SOUND_PCM_READ_RATE = IOCTL_NOT_PRESENT; + unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = IOCTL_NOT_PRESENT; + unsigned IOCTL_SOUND_PCM_WRITE_FILTER = IOCTL_NOT_PRESENT; +# else // SOUND_VERSION + unsigned IOCTL_SNDCTL_COPR_HALT = SNDCTL_COPR_HALT; + unsigned IOCTL_SNDCTL_COPR_LOAD = SNDCTL_COPR_LOAD; + unsigned IOCTL_SNDCTL_COPR_RCODE = SNDCTL_COPR_RCODE; + unsigned IOCTL_SNDCTL_COPR_RCVMSG = SNDCTL_COPR_RCVMSG; + unsigned IOCTL_SNDCTL_COPR_RDATA = SNDCTL_COPR_RDATA; + unsigned IOCTL_SNDCTL_COPR_RESET = SNDCTL_COPR_RESET; + unsigned IOCTL_SNDCTL_COPR_RUN = SNDCTL_COPR_RUN; + unsigned IOCTL_SNDCTL_COPR_SENDMSG = SNDCTL_COPR_SENDMSG; + unsigned IOCTL_SNDCTL_COPR_WCODE = SNDCTL_COPR_WCODE; + unsigned IOCTL_SNDCTL_COPR_WDATA = SNDCTL_COPR_WDATA; + unsigned IOCTL_SOUND_PCM_READ_BITS = SOUND_PCM_READ_BITS; + unsigned IOCTL_SOUND_PCM_READ_CHANNELS = SOUND_PCM_READ_CHANNELS; + unsigned IOCTL_SOUND_PCM_READ_FILTER = SOUND_PCM_READ_FILTER; + unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE; + unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = SOUND_PCM_WRITE_CHANNELS; + unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER; +#endif // SOUND_VERSION + unsigned IOCTL_TCFLSH = TCFLSH; + unsigned IOCTL_TCGETA = TCGETA; + unsigned IOCTL_TCGETS = TCGETS; + unsigned IOCTL_TCSBRK = TCSBRK; + unsigned IOCTL_TCSBRKP = TCSBRKP; + unsigned IOCTL_TCSETA = TCSETA; + unsigned IOCTL_TCSETAF = TCSETAF; + unsigned IOCTL_TCSETAW = TCSETAW; + unsigned IOCTL_TCSETS = TCSETS; + unsigned IOCTL_TCSETSF = TCSETSF; + unsigned IOCTL_TCSETSW = TCSETSW; + unsigned IOCTL_TCXONC = TCXONC; + unsigned IOCTL_TIOCGLCKTRMIOS = TIOCGLCKTRMIOS; + unsigned IOCTL_TIOCGSOFTCAR = TIOCGSOFTCAR; + unsigned IOCTL_TIOCINQ = TIOCINQ; + unsigned IOCTL_TIOCLINUX = TIOCLINUX; + unsigned IOCTL_TIOCSERCONFIG = TIOCSERCONFIG; + unsigned IOCTL_TIOCSERGETLSR = TIOCSERGETLSR; + unsigned IOCTL_TIOCSERGWILD = TIOCSERGWILD; + unsigned IOCTL_TIOCSERSWILD = TIOCSERSWILD; + unsigned IOCTL_TIOCSLCKTRMIOS = TIOCSLCKTRMIOS; + unsigned IOCTL_TIOCSSOFTCAR = TIOCSSOFTCAR; + unsigned IOCTL_VT_DISALLOCATE = VT_DISALLOCATE; + unsigned IOCTL_VT_GETSTATE = VT_GETSTATE; + unsigned IOCTL_VT_RESIZE = VT_RESIZE; + unsigned IOCTL_VT_RESIZEX = VT_RESIZEX; + unsigned IOCTL_VT_SENDSIG = VT_SENDSIG; + unsigned IOCTL_MTIOCGET = MTIOCGET; + unsigned IOCTL_MTIOCTOP = MTIOCTOP; + unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; + unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; + unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; + unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; + unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; + unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; + unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; + unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; + unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; + unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; + unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; + unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE; + unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR; + unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO; + unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME; + unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE; + unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT; + unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT; + unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS; + unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS; + unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND; + unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC; + unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE; + unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET; + unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES; + unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC; + unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI; + unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD; + unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO; + unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL; + unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE; + unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME; + unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT; + unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE; + unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START; + unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP; + unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO; + unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE; + unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM; + unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS; + unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS; + unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD; + unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK; + unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE; + unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN; + unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX; + unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE; + unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1; + unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2; + unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3; + unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD; + unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC; + unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE; + unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN; + unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM; + unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV; + unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK; + unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC; + unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER; + unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS; + unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH; + unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE; + unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME; + unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM; + unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS; + unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD; + unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE; + unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN; + unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX; + unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE; + unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1; + unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2; + unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3; + unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD; + unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC; + unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE; + unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN; + unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM; + unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV; + unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC; + unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER; + unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH; + unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE; + unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME; + unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; + unsigned IOCTL_VT_GETMODE = VT_GETMODE; + unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; + unsigned IOCTL_VT_RELDISP = VT_RELDISP; + unsigned IOCTL_VT_SETMODE = VT_SETMODE; + unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + unsigned IOCTL_CYGETDEFTHRESH = CYGETDEFTHRESH; + unsigned IOCTL_CYGETDEFTIMEOUT = CYGETDEFTIMEOUT; + unsigned IOCTL_CYGETMON = CYGETMON; + unsigned IOCTL_CYGETTHRESH = CYGETTHRESH; + unsigned IOCTL_CYGETTIMEOUT = CYGETTIMEOUT; + unsigned IOCTL_CYSETDEFTHRESH = CYSETDEFTHRESH; + unsigned IOCTL_CYSETDEFTIMEOUT = CYSETDEFTIMEOUT; + unsigned IOCTL_CYSETTHRESH = CYSETTHRESH; + unsigned IOCTL_CYSETTIMEOUT = CYSETTIMEOUT; + unsigned IOCTL_EQL_EMANCIPATE = EQL_EMANCIPATE; + unsigned IOCTL_EQL_ENSLAVE = EQL_ENSLAVE; + unsigned IOCTL_EQL_GETMASTRCFG = EQL_GETMASTRCFG; + unsigned IOCTL_EQL_GETSLAVECFG = EQL_GETSLAVECFG; + unsigned IOCTL_EQL_SETMASTRCFG = EQL_SETMASTRCFG; + unsigned IOCTL_EQL_SETSLAVECFG = EQL_SETSLAVECFG; +#if EV_VERSION > (0x010000) + unsigned IOCTL_EVIOCGKEYCODE_V2 = EVIOCGKEYCODE_V2; + unsigned IOCTL_EVIOCGPROP = EVIOCGPROP(0); + unsigned IOCTL_EVIOCSKEYCODE_V2 = EVIOCSKEYCODE_V2; +#else + unsigned IOCTL_EVIOCGKEYCODE_V2 = IOCTL_NOT_PRESENT; + unsigned IOCTL_EVIOCGPROP = IOCTL_NOT_PRESENT; + unsigned IOCTL_EVIOCSKEYCODE_V2 = IOCTL_NOT_PRESENT; +#endif + unsigned IOCTL_FS_IOC_GETFLAGS = FS_IOC_GETFLAGS; + unsigned IOCTL_FS_IOC_GETVERSION = FS_IOC_GETVERSION; + unsigned IOCTL_FS_IOC_SETFLAGS = FS_IOC_SETFLAGS; + unsigned IOCTL_FS_IOC_SETVERSION = FS_IOC_SETVERSION; + unsigned IOCTL_GIO_CMAP = GIO_CMAP; + unsigned IOCTL_GIO_FONT = GIO_FONT; + unsigned IOCTL_GIO_UNIMAP = GIO_UNIMAP; + unsigned IOCTL_GIO_UNISCRNMAP = GIO_UNISCRNMAP; + unsigned IOCTL_KDADDIO = KDADDIO; + unsigned IOCTL_KDDELIO = KDDELIO; + unsigned IOCTL_KDGETKEYCODE = KDGETKEYCODE; + unsigned IOCTL_KDGKBDIACR = KDGKBDIACR; + unsigned IOCTL_KDGKBENT = KDGKBENT; + unsigned IOCTL_KDGKBLED = KDGKBLED; + unsigned IOCTL_KDGKBMETA = KDGKBMETA; + unsigned IOCTL_KDGKBSENT = KDGKBSENT; + unsigned IOCTL_KDMAPDISP = KDMAPDISP; + unsigned IOCTL_KDSETKEYCODE = KDSETKEYCODE; + unsigned IOCTL_KDSIGACCEPT = KDSIGACCEPT; + unsigned IOCTL_KDSKBDIACR = KDSKBDIACR; + unsigned IOCTL_KDSKBENT = KDSKBENT; + unsigned IOCTL_KDSKBLED = KDSKBLED; + unsigned IOCTL_KDSKBMETA = KDSKBMETA; + unsigned IOCTL_KDSKBSENT = KDSKBSENT; + unsigned IOCTL_KDUNMAPDISP = KDUNMAPDISP; + unsigned IOCTL_LPABORT = LPABORT; + unsigned IOCTL_LPABORTOPEN = LPABORTOPEN; + unsigned IOCTL_LPCAREFUL = LPCAREFUL; + unsigned IOCTL_LPCHAR = LPCHAR; + unsigned IOCTL_LPGETIRQ = LPGETIRQ; + unsigned IOCTL_LPGETSTATUS = LPGETSTATUS; + unsigned IOCTL_LPRESET = LPRESET; + unsigned IOCTL_LPSETIRQ = LPSETIRQ; + unsigned IOCTL_LPTIME = LPTIME; + unsigned IOCTL_LPWAIT = LPWAIT; + unsigned IOCTL_MTIOCGETCONFIG = MTIOCGETCONFIG; + unsigned IOCTL_MTIOCSETCONFIG = MTIOCSETCONFIG; + unsigned IOCTL_PIO_CMAP = PIO_CMAP; + unsigned IOCTL_PIO_FONT = PIO_FONT; + unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP; + unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR; + unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP; + unsigned IOCTL_SCSI_IOCTL_GET_IDLUN = SCSI_IOCTL_GET_IDLUN; + unsigned IOCTL_SCSI_IOCTL_PROBE_HOST = SCSI_IOCTL_PROBE_HOST; + unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE = SCSI_IOCTL_TAGGED_DISABLE; + unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE = SCSI_IOCTL_TAGGED_ENABLE; + unsigned IOCTL_SIOCAIPXITFCRT = SIOCAIPXITFCRT; + unsigned IOCTL_SIOCAIPXPRISLT = SIOCAIPXPRISLT; + unsigned IOCTL_SIOCAX25ADDUID = SIOCAX25ADDUID; + unsigned IOCTL_SIOCAX25DELUID = SIOCAX25DELUID; + unsigned IOCTL_SIOCAX25GETPARMS = SIOCAX25GETPARMS; + unsigned IOCTL_SIOCAX25GETUID = SIOCAX25GETUID; + unsigned IOCTL_SIOCAX25NOUID = SIOCAX25NOUID; + unsigned IOCTL_SIOCAX25SETPARMS = SIOCAX25SETPARMS; + unsigned IOCTL_SIOCDEVPLIP = SIOCDEVPLIP; + unsigned IOCTL_SIOCIPXCFGDATA = SIOCIPXCFGDATA; + unsigned IOCTL_SIOCNRDECOBS = SIOCNRDECOBS; + unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS; + unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL; + unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS; + unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL; + unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI; + unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI; + unsigned IOCTL_TIOCSSERIAL = TIOCSSERIAL; +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP; + unsigned IOCTL_KDDISABIO = KDDISABIO; + unsigned IOCTL_KDENABIO = KDENABIO; + unsigned IOCTL_KDGETLED = KDGETLED; + unsigned IOCTL_KDGETMODE = KDGETMODE; + unsigned IOCTL_KDGKBMODE = KDGKBMODE; + unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; + unsigned IOCTL_KDMKTONE = KDMKTONE; + unsigned IOCTL_KDSETLED = KDSETLED; + unsigned IOCTL_KDSETMODE = KDSETMODE; + unsigned IOCTL_KDSKBMODE = KDSKBMODE; + unsigned IOCTL_KIOCSOUND = KIOCSOUND; + unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP; + unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; + unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE; +#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID + + const int si_SEGV_MAPERR = SEGV_MAPERR; + const int si_SEGV_ACCERR = SEGV_ACCERR; +} // namespace __sanitizer + +using namespace __sanitizer; + +COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); + +COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); +CHECK_TYPE_SIZE(pthread_key_t); + +#if SANITIZER_LINUX +// FIXME: We define those on Linux and Mac, but only check on Linux. +COMPILER_CHECK(IOC_NRBITS == _IOC_NRBITS); +COMPILER_CHECK(IOC_TYPEBITS == _IOC_TYPEBITS); +COMPILER_CHECK(IOC_SIZEBITS == _IOC_SIZEBITS); +COMPILER_CHECK(IOC_DIRBITS == _IOC_DIRBITS); +COMPILER_CHECK(IOC_NRMASK == _IOC_NRMASK); +COMPILER_CHECK(IOC_TYPEMASK == _IOC_TYPEMASK); +COMPILER_CHECK(IOC_SIZEMASK == _IOC_SIZEMASK); +COMPILER_CHECK(IOC_DIRMASK == _IOC_DIRMASK); +COMPILER_CHECK(IOC_NRSHIFT == _IOC_NRSHIFT); +COMPILER_CHECK(IOC_TYPESHIFT == _IOC_TYPESHIFT); +COMPILER_CHECK(IOC_SIZESHIFT == _IOC_SIZESHIFT); +COMPILER_CHECK(IOC_DIRSHIFT == _IOC_DIRSHIFT); +COMPILER_CHECK(IOC_NONE == _IOC_NONE); +COMPILER_CHECK(IOC_WRITE == _IOC_WRITE); +COMPILER_CHECK(IOC_READ == _IOC_READ); +COMPILER_CHECK(EVIOC_ABS_MAX == ABS_MAX); +COMPILER_CHECK(EVIOC_EV_MAX == EV_MAX); +COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678)); +COMPILER_CHECK(IOC_DIR(0x12345678) == _IOC_DIR(0x12345678)); +COMPILER_CHECK(IOC_NR(0x12345678) == _IOC_NR(0x12345678)); +COMPILER_CHECK(IOC_TYPE(0x12345678) == _IOC_TYPE(0x12345678)); +#endif // SANITIZER_LINUX + +#if SANITIZER_LINUX || SANITIZER_FREEBSD +// There are more undocumented fields in dl_phdr_info that we are not interested +// in. +COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); +#endif // SANITIZER_LINUX || SANITIZER_FREEBSD + +#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID +CHECK_TYPE_SIZE(glob_t); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); +CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); +CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); +CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); +CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); +CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); +#endif + +CHECK_TYPE_SIZE(addrinfo); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); + +CHECK_TYPE_SIZE(hostent); +CHECK_SIZE_AND_OFFSET(hostent, h_name); +CHECK_SIZE_AND_OFFSET(hostent, h_aliases); +CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); +CHECK_SIZE_AND_OFFSET(hostent, h_length); +CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); + +CHECK_TYPE_SIZE(iovec); +CHECK_SIZE_AND_OFFSET(iovec, iov_base); +CHECK_SIZE_AND_OFFSET(iovec, iov_len); + +CHECK_TYPE_SIZE(msghdr); +CHECK_SIZE_AND_OFFSET(msghdr, msg_name); +CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_control); +CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); + +CHECK_TYPE_SIZE(cmsghdr); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); + +#if SANITIZER_LINUX && (__ANDROID_API__ >= 21 || __GLIBC_PREREQ (2, 14)) +CHECK_TYPE_SIZE(mmsghdr); +CHECK_SIZE_AND_OFFSET(mmsghdr, msg_hdr); +CHECK_SIZE_AND_OFFSET(mmsghdr, msg_len); +#endif + +COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); +CHECK_SIZE_AND_OFFSET(dirent, d_ino); +#if SANITIZER_MAC +CHECK_SIZE_AND_OFFSET(dirent, d_seekoff); +#elif SANITIZER_FREEBSD +// There is no 'd_off' field on FreeBSD. +#else +CHECK_SIZE_AND_OFFSET(dirent, d_off); +#endif +CHECK_SIZE_AND_OFFSET(dirent, d_reclen); + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64)); +CHECK_SIZE_AND_OFFSET(dirent64, d_ino); +CHECK_SIZE_AND_OFFSET(dirent64, d_off); +CHECK_SIZE_AND_OFFSET(dirent64, d_reclen); +#endif + +CHECK_TYPE_SIZE(ifconf); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); + +CHECK_TYPE_SIZE(pollfd); +CHECK_SIZE_AND_OFFSET(pollfd, fd); +CHECK_SIZE_AND_OFFSET(pollfd, events); +CHECK_SIZE_AND_OFFSET(pollfd, revents); + +CHECK_TYPE_SIZE(nfds_t); + +CHECK_TYPE_SIZE(sigset_t); + +COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); +// Can't write checks for sa_handler and sa_sigaction due to them being +// preprocessor macros. +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); +#if !defined(__s390x__) || __GLIBC_PREREQ (2, 20) +// On s390x glibc 2.19 and earlier sa_flags was unsigned long, and sa_resv +// didn't exist. +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags); +#endif +#if SANITIZER_LINUX && (!SANITIZER_ANDROID || !SANITIZER_MIPS32) +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer); +#endif + +#if SANITIZER_LINUX +CHECK_TYPE_SIZE(__sysctl_args); +CHECK_SIZE_AND_OFFSET(__sysctl_args, name); +CHECK_SIZE_AND_OFFSET(__sysctl_args, nlen); +CHECK_SIZE_AND_OFFSET(__sysctl_args, oldval); +CHECK_SIZE_AND_OFFSET(__sysctl_args, oldlenp); +CHECK_SIZE_AND_OFFSET(__sysctl_args, newval); +CHECK_SIZE_AND_OFFSET(__sysctl_args, newlen); + +CHECK_TYPE_SIZE(__kernel_uid_t); +CHECK_TYPE_SIZE(__kernel_gid_t); + +#if SANITIZER_USES_UID16_SYSCALLS +CHECK_TYPE_SIZE(__kernel_old_uid_t); +CHECK_TYPE_SIZE(__kernel_old_gid_t); +#endif + +CHECK_TYPE_SIZE(__kernel_off_t); +CHECK_TYPE_SIZE(__kernel_loff_t); +CHECK_TYPE_SIZE(__kernel_fd_set); +#endif + +#if !SANITIZER_ANDROID +CHECK_TYPE_SIZE(wordexp_t); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); +#endif + +CHECK_TYPE_SIZE(tm); +CHECK_SIZE_AND_OFFSET(tm, tm_sec); +CHECK_SIZE_AND_OFFSET(tm, tm_min); +CHECK_SIZE_AND_OFFSET(tm, tm_hour); +CHECK_SIZE_AND_OFFSET(tm, tm_mday); +CHECK_SIZE_AND_OFFSET(tm, tm_mon); +CHECK_SIZE_AND_OFFSET(tm, tm_year); +CHECK_SIZE_AND_OFFSET(tm, tm_wday); +CHECK_SIZE_AND_OFFSET(tm, tm_yday); +CHECK_SIZE_AND_OFFSET(tm, tm_isdst); +CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); +CHECK_SIZE_AND_OFFSET(tm, tm_zone); + +#if SANITIZER_LINUX +CHECK_TYPE_SIZE(mntent); +CHECK_SIZE_AND_OFFSET(mntent, mnt_fsname); +CHECK_SIZE_AND_OFFSET(mntent, mnt_dir); +CHECK_SIZE_AND_OFFSET(mntent, mnt_type); +CHECK_SIZE_AND_OFFSET(mntent, mnt_opts); +CHECK_SIZE_AND_OFFSET(mntent, mnt_freq); +CHECK_SIZE_AND_OFFSET(mntent, mnt_passno); +#endif + +CHECK_TYPE_SIZE(ether_addr); + +#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID +CHECK_TYPE_SIZE(ipc_perm); +# if SANITIZER_FREEBSD +CHECK_SIZE_AND_OFFSET(ipc_perm, key); +CHECK_SIZE_AND_OFFSET(ipc_perm, seq); +# else +CHECK_SIZE_AND_OFFSET(ipc_perm, __key); +CHECK_SIZE_AND_OFFSET(ipc_perm, __seq); +# endif +CHECK_SIZE_AND_OFFSET(ipc_perm, uid); +CHECK_SIZE_AND_OFFSET(ipc_perm, gid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); +#if (!defined(__aarch64__) || !SANITIZER_LINUX || __GLIBC_PREREQ (2, 21)) && \ + !defined(__arm__) +/* On aarch64 glibc 2.20 and earlier provided incorrect mode field. */ +/* On Arm newer glibc provide a different mode field, it's hard to detect + so just disable the check. */ +CHECK_SIZE_AND_OFFSET(ipc_perm, mode); +#endif + +CHECK_TYPE_SIZE(shmid_ds); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); +#endif + +CHECK_TYPE_SIZE(clock_t); + +#if SANITIZER_LINUX +CHECK_TYPE_SIZE(clockid_t); +#endif + +#if !SANITIZER_ANDROID +CHECK_TYPE_SIZE(ifaddrs); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); +#if SANITIZER_LINUX || SANITIZER_FREEBSD +// Compare against the union, because we can't reach into the union in a +// compliant way. +#ifdef ifa_dstaddr +#undef ifa_dstaddr +#endif +# if SANITIZER_FREEBSD +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); +# else +COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)nullptr)->ifa_dstaddr) == + sizeof(((ifaddrs *)nullptr)->ifa_ifu)); +COMPILER_CHECK(offsetof(__sanitizer_ifaddrs, ifa_dstaddr) == + offsetof(ifaddrs, ifa_ifu)); +# endif // SANITIZER_FREEBSD +#else +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); +#endif // SANITIZER_LINUX +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); +#endif + +#if SANITIZER_LINUX +COMPILER_CHECK(sizeof(__sanitizer_struct_mallinfo) == sizeof(struct mallinfo)); +#endif + +#if !SANITIZER_ANDROID +CHECK_TYPE_SIZE(timeb); +CHECK_SIZE_AND_OFFSET(timeb, time); +CHECK_SIZE_AND_OFFSET(timeb, millitm); +CHECK_SIZE_AND_OFFSET(timeb, timezone); +CHECK_SIZE_AND_OFFSET(timeb, dstflag); +#endif + +CHECK_TYPE_SIZE(passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_name); +CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_uid); +CHECK_SIZE_AND_OFFSET(passwd, pw_gid); +CHECK_SIZE_AND_OFFSET(passwd, pw_dir); +CHECK_SIZE_AND_OFFSET(passwd, pw_shell); + +#if !SANITIZER_ANDROID +CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); +#endif + +#if SANITIZER_MAC +CHECK_SIZE_AND_OFFSET(passwd, pw_change); +CHECK_SIZE_AND_OFFSET(passwd, pw_expire); +CHECK_SIZE_AND_OFFSET(passwd, pw_class); +#endif + + +CHECK_TYPE_SIZE(group); +CHECK_SIZE_AND_OFFSET(group, gr_name); +CHECK_SIZE_AND_OFFSET(group, gr_passwd); +CHECK_SIZE_AND_OFFSET(group, gr_gid); +CHECK_SIZE_AND_OFFSET(group, gr_mem); + +#if HAVE_RPC_XDR_H +CHECK_TYPE_SIZE(XDR); +CHECK_SIZE_AND_OFFSET(XDR, x_op); +CHECK_SIZE_AND_OFFSET(XDR, x_ops); +CHECK_SIZE_AND_OFFSET(XDR, x_public); +CHECK_SIZE_AND_OFFSET(XDR, x_private); +CHECK_SIZE_AND_OFFSET(XDR, x_base); +CHECK_SIZE_AND_OFFSET(XDR, x_handy); +COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE); +COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); +COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE)); +CHECK_SIZE_AND_OFFSET(FILE, _flags); +CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr); +CHECK_SIZE_AND_OFFSET(FILE, _IO_read_end); +CHECK_SIZE_AND_OFFSET(FILE, _IO_read_base); +CHECK_SIZE_AND_OFFSET(FILE, _IO_write_ptr); +CHECK_SIZE_AND_OFFSET(FILE, _IO_write_end); +CHECK_SIZE_AND_OFFSET(FILE, _IO_write_base); +CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_base); +CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_end); +CHECK_SIZE_AND_OFFSET(FILE, _IO_save_base); +CHECK_SIZE_AND_OFFSET(FILE, _IO_backup_base); +CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end); +CHECK_SIZE_AND_OFFSET(FILE, _markers); +CHECK_SIZE_AND_OFFSET(FILE, _chain); +CHECK_SIZE_AND_OFFSET(FILE, _fileno); +#endif + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +COMPILER_CHECK(sizeof(__sanitizer__obstack_chunk) <= sizeof(_obstack_chunk)); +CHECK_SIZE_AND_OFFSET(_obstack_chunk, limit); +CHECK_SIZE_AND_OFFSET(_obstack_chunk, prev); +CHECK_TYPE_SIZE(obstack); +CHECK_SIZE_AND_OFFSET(obstack, chunk_size); +CHECK_SIZE_AND_OFFSET(obstack, chunk); +CHECK_SIZE_AND_OFFSET(obstack, object_base); +CHECK_SIZE_AND_OFFSET(obstack, next_free); + +CHECK_TYPE_SIZE(cookie_io_functions_t); +CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, read); +CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, write); +CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, seek); +CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, close); +#endif + +#if SANITIZER_LINUX || SANITIZER_FREEBSD +CHECK_TYPE_SIZE(sem_t); +#endif + +#if SANITIZER_LINUX && defined(__arm__) +COMPILER_CHECK(ARM_VFPREGS_SIZE == ARM_VFPREGS_SIZE_ASAN); +#endif + +#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h index f1a4fd7d3709..db2c4f07b3ae 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -19,844 +19,846 @@ #include "sanitizer_internal_defs.h" #include "sanitizer_platform.h" -# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) ((link_map*)(handle)) - -#ifndef __GLIBC_PREREQ -#define __GLIBC_PREREQ(x, y) 0 +#if defined(__sparc__) +// FIXME: This can't be included from tsan which does not support sparc yet. +#include "sanitizer_glibc_version.h" #endif +# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) ((link_map*)(handle)) + namespace __sanitizer { - extern unsigned struct_utsname_sz; - extern unsigned struct_stat_sz; +extern unsigned struct_utsname_sz; +extern unsigned struct_stat_sz; #if !SANITIZER_IOS - extern unsigned struct_stat64_sz; -#endif - extern unsigned struct_rusage_sz; - extern unsigned siginfo_t_sz; - extern unsigned struct_itimerval_sz; - extern unsigned pthread_t_sz; - extern unsigned pthread_mutex_t_sz; - extern unsigned pthread_cond_t_sz; - extern unsigned pid_t_sz; - extern unsigned timeval_sz; - extern unsigned uid_t_sz; - extern unsigned gid_t_sz; - extern unsigned mbstate_t_sz; - extern unsigned struct_timezone_sz; - extern unsigned struct_tms_sz; - extern unsigned struct_itimerspec_sz; - extern unsigned struct_sigevent_sz; - extern unsigned struct_sched_param_sz; - extern unsigned struct_statfs64_sz; - extern unsigned struct_regex_sz; - extern unsigned struct_regmatch_sz; +extern unsigned struct_stat64_sz; +#endif +extern unsigned struct_rusage_sz; +extern unsigned siginfo_t_sz; +extern unsigned struct_itimerval_sz; +extern unsigned pthread_t_sz; +extern unsigned pthread_mutex_t_sz; +extern unsigned pthread_cond_t_sz; +extern unsigned pid_t_sz; +extern unsigned timeval_sz; +extern unsigned uid_t_sz; +extern unsigned gid_t_sz; +extern unsigned mbstate_t_sz; +extern unsigned struct_timezone_sz; +extern unsigned struct_tms_sz; +extern unsigned struct_itimerspec_sz; +extern unsigned struct_sigevent_sz; +extern unsigned struct_sched_param_sz; +extern unsigned struct_statfs64_sz; +extern unsigned struct_regex_sz; +extern unsigned struct_regmatch_sz; #if !SANITIZER_ANDROID - extern unsigned struct_fstab_sz; - extern unsigned struct_statfs_sz; - extern unsigned struct_sockaddr_sz; - extern unsigned ucontext_t_sz; +extern unsigned struct_fstab_sz; +extern unsigned struct_statfs_sz; +extern unsigned struct_sockaddr_sz; +extern unsigned ucontext_t_sz; #endif // !SANITIZER_ANDROID #if SANITIZER_LINUX #if defined(__x86_64__) - const unsigned struct_kernel_stat_sz = 144; - const unsigned struct_kernel_stat64_sz = 0; +const unsigned struct_kernel_stat_sz = 144; +const unsigned struct_kernel_stat64_sz = 0; #elif defined(__i386__) - const unsigned struct_kernel_stat_sz = 64; - const unsigned struct_kernel_stat64_sz = 96; +const unsigned struct_kernel_stat_sz = 64; +const unsigned struct_kernel_stat64_sz = 96; #elif defined(__arm__) - const unsigned struct_kernel_stat_sz = 64; - const unsigned struct_kernel_stat64_sz = 104; +const unsigned struct_kernel_stat_sz = 64; +const unsigned struct_kernel_stat64_sz = 104; #elif defined(__aarch64__) - const unsigned struct_kernel_stat_sz = 128; - const unsigned struct_kernel_stat64_sz = 104; +const unsigned struct_kernel_stat_sz = 128; +const unsigned struct_kernel_stat64_sz = 104; #elif defined(__powerpc__) && !defined(__powerpc64__) - const unsigned struct_kernel_stat_sz = 72; - const unsigned struct_kernel_stat64_sz = 104; +const unsigned struct_kernel_stat_sz = 72; +const unsigned struct_kernel_stat64_sz = 104; #elif defined(__powerpc64__) - const unsigned struct_kernel_stat_sz = 144; - const unsigned struct_kernel_stat64_sz = 104; +const unsigned struct_kernel_stat_sz = 144; +const unsigned struct_kernel_stat64_sz = 104; #elif defined(__mips__) - const unsigned struct_kernel_stat_sz = - SANITIZER_ANDROID ? FIRST_32_SECOND_64(104, 128) : - FIRST_32_SECOND_64(160, 216); - const unsigned struct_kernel_stat64_sz = 104; +const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID + ? FIRST_32_SECOND_64(104, 128) + : FIRST_32_SECOND_64(160, 216); +const unsigned struct_kernel_stat64_sz = 104; #elif defined(__s390__) && !defined(__s390x__) - const unsigned struct_kernel_stat_sz = 64; - const unsigned struct_kernel_stat64_sz = 104; +const unsigned struct_kernel_stat_sz = 64; +const unsigned struct_kernel_stat64_sz = 104; #elif defined(__s390x__) - const unsigned struct_kernel_stat_sz = 144; - const unsigned struct_kernel_stat64_sz = 0; +const unsigned struct_kernel_stat_sz = 144; +const unsigned struct_kernel_stat64_sz = 0; #elif defined(__sparc__) && defined(__arch64__) - const unsigned struct___old_kernel_stat_sz = 0; - const unsigned struct_kernel_stat_sz = 104; - const unsigned struct_kernel_stat64_sz = 144; +const unsigned struct___old_kernel_stat_sz = 0; +const unsigned struct_kernel_stat_sz = 104; +const unsigned struct_kernel_stat64_sz = 144; #elif defined(__sparc__) && !defined(__arch64__) - const unsigned struct___old_kernel_stat_sz = 0; - const unsigned struct_kernel_stat_sz = 64; - const unsigned struct_kernel_stat64_sz = 104; -#endif - struct __sanitizer_perf_event_attr { - unsigned type; - unsigned size; - // More fields that vary with the kernel version. - }; +const unsigned struct___old_kernel_stat_sz = 0; +const unsigned struct_kernel_stat_sz = 64; +const unsigned struct_kernel_stat64_sz = 104; +#endif +struct __sanitizer_perf_event_attr { + unsigned type; + unsigned size; + // More fields that vary with the kernel version. +}; - extern unsigned struct_epoll_event_sz; - extern unsigned struct_sysinfo_sz; - extern unsigned __user_cap_header_struct_sz; - extern unsigned __user_cap_data_struct_sz; - extern unsigned struct_new_utsname_sz; - extern unsigned struct_old_utsname_sz; - extern unsigned struct_oldold_utsname_sz; +extern unsigned struct_epoll_event_sz; +extern unsigned struct_sysinfo_sz; +extern unsigned __user_cap_header_struct_sz; +extern unsigned __user_cap_data_struct_sz; +extern unsigned struct_new_utsname_sz; +extern unsigned struct_old_utsname_sz; +extern unsigned struct_oldold_utsname_sz; - const unsigned struct_kexec_segment_sz = 4 * sizeof(unsigned long); +const unsigned struct_kexec_segment_sz = 4 * sizeof(unsigned long); #endif // SANITIZER_LINUX #if SANITIZER_LINUX #if defined(__powerpc64__) || defined(__s390__) - const unsigned struct___old_kernel_stat_sz = 0; +const unsigned struct___old_kernel_stat_sz = 0; #elif !defined(__sparc__) - const unsigned struct___old_kernel_stat_sz = 32; -#endif - - extern unsigned struct_rlimit_sz; - extern unsigned struct_utimbuf_sz; - extern unsigned struct_timespec_sz; - - struct __sanitizer_iocb { - u64 aio_data; - u32 aio_key_or_aio_reserved1; // Simply crazy. - u32 aio_reserved1_or_aio_key; // Luckily, we don't need these. - u16 aio_lio_opcode; - s16 aio_reqprio; - u32 aio_fildes; - u64 aio_buf; - u64 aio_nbytes; - s64 aio_offset; - u64 aio_reserved2; - u64 aio_reserved3; - }; +const unsigned struct___old_kernel_stat_sz = 32; +#endif - struct __sanitizer_io_event { - u64 data; - u64 obj; - u64 res; - u64 res2; - }; +extern unsigned struct_rlimit_sz; +extern unsigned struct_utimbuf_sz; +extern unsigned struct_timespec_sz; + +struct __sanitizer_iocb { + u64 aio_data; + u32 aio_key_or_aio_reserved1; // Simply crazy. + u32 aio_reserved1_or_aio_key; // Luckily, we don't need these. + u16 aio_lio_opcode; + s16 aio_reqprio; + u32 aio_fildes; + u64 aio_buf; + u64 aio_nbytes; + s64 aio_offset; + u64 aio_reserved2; + u64 aio_reserved3; +}; - const unsigned iocb_cmd_pread = 0; - const unsigned iocb_cmd_pwrite = 1; - const unsigned iocb_cmd_preadv = 7; - const unsigned iocb_cmd_pwritev = 8; - - struct __sanitizer___sysctl_args { - int *name; - int nlen; - void *oldval; - uptr *oldlenp; - void *newval; - uptr newlen; - unsigned long ___unused[4]; - }; +struct __sanitizer_io_event { + u64 data; + u64 obj; + u64 res; + u64 res2; +}; - const unsigned old_sigset_t_sz = sizeof(unsigned long); +const unsigned iocb_cmd_pread = 0; +const unsigned iocb_cmd_pwrite = 1; +const unsigned iocb_cmd_preadv = 7; +const unsigned iocb_cmd_pwritev = 8; + +struct __sanitizer___sysctl_args { + int *name; + int nlen; + void *oldval; + uptr *oldlenp; + void *newval; + uptr newlen; + unsigned long ___unused[4]; +}; - struct __sanitizer_sem_t { +const unsigned old_sigset_t_sz = sizeof(unsigned long); + +struct __sanitizer_sem_t { #if SANITIZER_ANDROID && defined(_LP64) - int data[4]; + int data[4]; #elif SANITIZER_ANDROID && !defined(_LP64) - int data; + int data; #elif SANITIZER_LINUX - uptr data[4]; + uptr data[4]; #endif - }; +}; #endif // SANITIZER_LINUX #if SANITIZER_ANDROID - struct __sanitizer_struct_mallinfo { - uptr v[10]; - }; +struct __sanitizer_struct_mallinfo { + uptr v[10]; +}; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID - struct __sanitizer_struct_mallinfo { - int v[10]; - }; +struct __sanitizer_struct_mallinfo { + int v[10]; +}; - extern unsigned struct_ustat_sz; - extern unsigned struct_rlimit64_sz; - extern unsigned struct_statvfs64_sz; +extern unsigned struct_ustat_sz; +extern unsigned struct_rlimit64_sz; +extern unsigned struct_statvfs64_sz; - struct __sanitizer_ipc_perm { - int __key; - int uid; - int gid; - int cuid; - int cgid; +struct __sanitizer_ipc_perm { + int __key; + int uid; + int gid; + int cuid; + int cgid; #ifdef __powerpc__ - unsigned mode; - unsigned __seq; - u64 __unused1; - u64 __unused2; + unsigned mode; + unsigned __seq; + u64 __unused1; + u64 __unused2; #elif defined(__sparc__) #if defined(__arch64__) - unsigned mode; - unsigned short __pad1; + unsigned mode; + unsigned short __pad1; #else - unsigned short __pad1; - unsigned short mode; - unsigned short __pad2; + unsigned short __pad1; + unsigned short mode; + unsigned short __pad2; #endif - unsigned short __seq; - unsigned long long __unused1; - unsigned long long __unused2; + unsigned short __seq; + unsigned long long __unused1; + unsigned long long __unused2; #elif defined(__mips__) || defined(__aarch64__) || defined(__s390x__) - unsigned int mode; - unsigned short __seq; - unsigned short __pad1; - unsigned long __unused1; - unsigned long __unused2; + unsigned int mode; + unsigned short __seq; + unsigned short __pad1; + unsigned long __unused1; + unsigned long __unused2; #else - unsigned short mode; - unsigned short __pad1; - unsigned short __seq; - unsigned short __pad2; + unsigned short mode; + unsigned short __pad1; + unsigned short __seq; + unsigned short __pad2; #if defined(__x86_64__) && !defined(_LP64) - u64 __unused1; - u64 __unused2; + u64 __unused1; + u64 __unused2; #else - unsigned long __unused1; - unsigned long __unused2; + unsigned long __unused1; + unsigned long __unused2; #endif #endif - }; +}; - struct __sanitizer_shmid_ds { - __sanitizer_ipc_perm shm_perm; - #if defined(__sparc__) - #if !defined(__arch64__) - u32 __pad1; - #endif - long shm_atime; - #if !defined(__arch64__) - u32 __pad2; - #endif - long shm_dtime; - #if !defined(__arch64__) - u32 __pad3; - #endif - long shm_ctime; - uptr shm_segsz; - int shm_cpid; - int shm_lpid; - unsigned long shm_nattch; - unsigned long __glibc_reserved1; - unsigned long __glibc_reserved2; - #else - #ifndef __powerpc__ - uptr shm_segsz; - #elif !defined(__powerpc64__) - uptr __unused0; - #endif - #if defined(__x86_64__) && !defined(_LP64) - u64 shm_atime; - u64 shm_dtime; - u64 shm_ctime; - #else - uptr shm_atime; - #if !defined(_LP64) && !defined(__mips__) - uptr __unused1; - #endif - uptr shm_dtime; - #if !defined(_LP64) && !defined(__mips__) - uptr __unused2; - #endif - uptr shm_ctime; - #if !defined(_LP64) && !defined(__mips__) - uptr __unused3; - #endif - #endif - #ifdef __powerpc__ - uptr shm_segsz; - #endif - int shm_cpid; - int shm_lpid; - #if defined(__x86_64__) && !defined(_LP64) - u64 shm_nattch; - u64 __unused4; - u64 __unused5; - #else - uptr shm_nattch; - uptr __unused4; - uptr __unused5; - #endif +struct __sanitizer_shmid_ds { + __sanitizer_ipc_perm shm_perm; +#if defined(__sparc__) +#if !defined(__arch64__) + u32 __pad1; #endif - }; + long shm_atime; +#if !defined(__arch64__) + u32 __pad2; +#endif + long shm_dtime; +#if !defined(__arch64__) + u32 __pad3; +#endif + long shm_ctime; + uptr shm_segsz; + int shm_cpid; + int shm_lpid; + unsigned long shm_nattch; + unsigned long __glibc_reserved1; + unsigned long __glibc_reserved2; +#else +#ifndef __powerpc__ + uptr shm_segsz; +#elif !defined(__powerpc64__) + uptr __unused0; +#endif +#if defined(__x86_64__) && !defined(_LP64) + u64 shm_atime; + u64 shm_dtime; + u64 shm_ctime; +#else + uptr shm_atime; +#if !defined(_LP64) && !defined(__mips__) + uptr __unused1; +#endif + uptr shm_dtime; +#if !defined(_LP64) && !defined(__mips__) + uptr __unused2; +#endif + uptr shm_ctime; +#if !defined(_LP64) && !defined(__mips__) + uptr __unused3; +#endif +#endif +#ifdef __powerpc__ + uptr shm_segsz; +#endif + int shm_cpid; + int shm_lpid; +#if defined(__x86_64__) && !defined(_LP64) + u64 shm_nattch; + u64 __unused4; + u64 __unused5; +#else + uptr shm_nattch; + uptr __unused4; + uptr __unused5; +#endif +#endif +}; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID - extern unsigned struct_msqid_ds_sz; - extern unsigned struct_mq_attr_sz; - extern unsigned struct_timex_sz; - extern unsigned struct_statvfs_sz; +extern unsigned struct_msqid_ds_sz; +extern unsigned struct_mq_attr_sz; +extern unsigned struct_timex_sz; +extern unsigned struct_statvfs_sz; +extern unsigned struct_crypt_data_sz; #endif // SANITIZER_LINUX && !SANITIZER_ANDROID - struct __sanitizer_iovec { - void *iov_base; - uptr iov_len; - }; +struct __sanitizer_iovec { + void *iov_base; + uptr iov_len; +}; #if !SANITIZER_ANDROID - struct __sanitizer_ifaddrs { - struct __sanitizer_ifaddrs *ifa_next; - char *ifa_name; - unsigned int ifa_flags; - void *ifa_addr; // (struct sockaddr *) - void *ifa_netmask; // (struct sockaddr *) - // This is a union on Linux. +struct __sanitizer_ifaddrs { + struct __sanitizer_ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + void *ifa_addr; // (struct sockaddr *) + void *ifa_netmask; // (struct sockaddr *) + // This is a union on Linux. # ifdef ifa_dstaddr # undef ifa_dstaddr # endif - void *ifa_dstaddr; // (struct sockaddr *) - void *ifa_data; - }; + void *ifa_dstaddr; // (struct sockaddr *) + void *ifa_data; +}; #endif // !SANITIZER_ANDROID #if SANITIZER_MAC - typedef unsigned long __sanitizer_pthread_key_t; +typedef unsigned long __sanitizer_pthread_key_t; #else - typedef unsigned __sanitizer_pthread_key_t; +typedef unsigned __sanitizer_pthread_key_t; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID - struct __sanitizer_XDR { - int x_op; - void *x_ops; - uptr x_public; - uptr x_private; - uptr x_base; - unsigned x_handy; - }; +struct __sanitizer_XDR { + int x_op; + void *x_ops; + uptr x_public; + uptr x_private; + uptr x_base; + unsigned x_handy; +}; - const int __sanitizer_XDR_ENCODE = 0; - const int __sanitizer_XDR_DECODE = 1; - const int __sanitizer_XDR_FREE = 2; +const int __sanitizer_XDR_ENCODE = 0; +const int __sanitizer_XDR_DECODE = 1; +const int __sanitizer_XDR_FREE = 2; #endif - struct __sanitizer_passwd { - char *pw_name; - char *pw_passwd; - int pw_uid; - int pw_gid; +struct __sanitizer_passwd { + char *pw_name; + char *pw_passwd; + int pw_uid; + int pw_gid; #if SANITIZER_MAC - long pw_change; - char *pw_class; + long pw_change; + char *pw_class; #endif #if !(SANITIZER_ANDROID && (SANITIZER_WORDSIZE == 32)) - char *pw_gecos; + char *pw_gecos; #endif - char *pw_dir; - char *pw_shell; + char *pw_dir; + char *pw_shell; #if SANITIZER_MAC - long pw_expire; + long pw_expire; #endif - }; +}; - struct __sanitizer_group { - char *gr_name; - char *gr_passwd; - int gr_gid; - char **gr_mem; - }; +struct __sanitizer_group { + char *gr_name; + char *gr_passwd; + int gr_gid; + char **gr_mem; +}; #if defined(__x86_64__) && !defined(_LP64) - typedef long long __sanitizer_time_t; +typedef long long __sanitizer_time_t; #else - typedef long __sanitizer_time_t; +typedef long __sanitizer_time_t; #endif - typedef long __sanitizer_suseconds_t; +typedef long __sanitizer_suseconds_t; - struct __sanitizer_timeval { - __sanitizer_time_t tv_sec; - __sanitizer_suseconds_t tv_usec; - }; +struct __sanitizer_timeval { + __sanitizer_time_t tv_sec; + __sanitizer_suseconds_t tv_usec; +}; - struct __sanitizer_itimerval { - struct __sanitizer_timeval it_interval; - struct __sanitizer_timeval it_value; - }; +struct __sanitizer_itimerval { + struct __sanitizer_timeval it_interval; + struct __sanitizer_timeval it_value; +}; - struct __sanitizer_timeb { - __sanitizer_time_t time; - unsigned short millitm; - short timezone; - short dstflag; - }; +struct __sanitizer_timeb { + __sanitizer_time_t time; + unsigned short millitm; + short timezone; + short dstflag; +}; - struct __sanitizer_ether_addr { - u8 octet[6]; - }; +struct __sanitizer_ether_addr { + u8 octet[6]; +}; - struct __sanitizer_tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; - long int tm_gmtoff; - const char *tm_zone; - }; +struct __sanitizer_tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long int tm_gmtoff; + const char *tm_zone; +}; #if SANITIZER_LINUX - struct __sanitizer_mntent { - char *mnt_fsname; - char *mnt_dir; - char *mnt_type; - char *mnt_opts; - int mnt_freq; - int mnt_passno; - }; +struct __sanitizer_mntent { + char *mnt_fsname; + char *mnt_dir; + char *mnt_type; + char *mnt_opts; + int mnt_freq; + int mnt_passno; +}; - struct __sanitizer_file_handle { - unsigned int handle_bytes; - int handle_type; - unsigned char f_handle[1]; // variable sized - }; +struct __sanitizer_file_handle { + unsigned int handle_bytes; + int handle_type; + unsigned char f_handle[1]; // variable sized +}; #endif #if SANITIZER_MAC - struct __sanitizer_msghdr { - void *msg_name; - unsigned msg_namelen; - struct __sanitizer_iovec *msg_iov; - unsigned msg_iovlen; - void *msg_control; - unsigned msg_controllen; - int msg_flags; - }; - struct __sanitizer_cmsghdr { - unsigned cmsg_len; - int cmsg_level; - int cmsg_type; - }; +struct __sanitizer_msghdr { + void *msg_name; + unsigned msg_namelen; + struct __sanitizer_iovec *msg_iov; + unsigned msg_iovlen; + void *msg_control; + unsigned msg_controllen; + int msg_flags; +}; +struct __sanitizer_cmsghdr { + unsigned cmsg_len; + int cmsg_level; + int cmsg_type; +}; #else - struct __sanitizer_msghdr { - void *msg_name; - unsigned msg_namelen; - struct __sanitizer_iovec *msg_iov; - uptr msg_iovlen; - void *msg_control; - uptr msg_controllen; - int msg_flags; - }; - struct __sanitizer_cmsghdr { - uptr cmsg_len; - int cmsg_level; - int cmsg_type; - }; +struct __sanitizer_msghdr { + void *msg_name; + unsigned msg_namelen; + struct __sanitizer_iovec *msg_iov; + uptr msg_iovlen; + void *msg_control; + uptr msg_controllen; + int msg_flags; +}; +struct __sanitizer_cmsghdr { + uptr cmsg_len; + int cmsg_level; + int cmsg_type; +}; #endif #if SANITIZER_LINUX - struct __sanitizer_mmsghdr { - __sanitizer_msghdr msg_hdr; - unsigned int msg_len; - }; +struct __sanitizer_mmsghdr { + __sanitizer_msghdr msg_hdr; + unsigned int msg_len; +}; #endif #if SANITIZER_MAC - struct __sanitizer_dirent { - unsigned long long d_ino; - unsigned long long d_seekoff; - unsigned short d_reclen; - // more fields that we don't care about - }; +struct __sanitizer_dirent { + unsigned long long d_ino; + unsigned long long d_seekoff; + unsigned short d_reclen; + // more fields that we don't care about +}; #elif SANITIZER_ANDROID || defined(__x86_64__) - struct __sanitizer_dirent { - unsigned long long d_ino; - unsigned long long d_off; - unsigned short d_reclen; - // more fields that we don't care about - }; +struct __sanitizer_dirent { + unsigned long long d_ino; + unsigned long long d_off; + unsigned short d_reclen; + // more fields that we don't care about +}; #else - struct __sanitizer_dirent { - uptr d_ino; - uptr d_off; - unsigned short d_reclen; - // more fields that we don't care about - }; +struct __sanitizer_dirent { + uptr d_ino; + uptr d_off; + unsigned short d_reclen; + // more fields that we don't care about +}; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID - struct __sanitizer_dirent64 { - unsigned long long d_ino; - unsigned long long d_off; - unsigned short d_reclen; - // more fields that we don't care about - }; +struct __sanitizer_dirent64 { + unsigned long long d_ino; + unsigned long long d_off; + unsigned short d_reclen; + // more fields that we don't care about +}; #endif #if defined(__x86_64__) && !defined(_LP64) - typedef long long __sanitizer_clock_t; +typedef long long __sanitizer_clock_t; #else - typedef long __sanitizer_clock_t; +typedef long __sanitizer_clock_t; #endif #if SANITIZER_LINUX - typedef int __sanitizer_clockid_t; +typedef int __sanitizer_clockid_t; #endif #if SANITIZER_LINUX -#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__)\ - || defined(__mips__) - typedef unsigned __sanitizer___kernel_uid_t; - typedef unsigned __sanitizer___kernel_gid_t; +#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__) || \ + defined(__mips__) +typedef unsigned __sanitizer___kernel_uid_t; +typedef unsigned __sanitizer___kernel_gid_t; #else - typedef unsigned short __sanitizer___kernel_uid_t; - typedef unsigned short __sanitizer___kernel_gid_t; +typedef unsigned short __sanitizer___kernel_uid_t; +typedef unsigned short __sanitizer___kernel_gid_t; #endif #if defined(__x86_64__) && !defined(_LP64) - typedef long long __sanitizer___kernel_off_t; +typedef long long __sanitizer___kernel_off_t; #else - typedef long __sanitizer___kernel_off_t; +typedef long __sanitizer___kernel_off_t; #endif #if defined(__powerpc__) || defined(__mips__) - typedef unsigned int __sanitizer___kernel_old_uid_t; - typedef unsigned int __sanitizer___kernel_old_gid_t; +typedef unsigned int __sanitizer___kernel_old_uid_t; +typedef unsigned int __sanitizer___kernel_old_gid_t; #else - typedef unsigned short __sanitizer___kernel_old_uid_t; - typedef unsigned short __sanitizer___kernel_old_gid_t; +typedef unsigned short __sanitizer___kernel_old_uid_t; +typedef unsigned short __sanitizer___kernel_old_gid_t; #endif - typedef long long __sanitizer___kernel_loff_t; - typedef struct { - unsigned long fds_bits[1024 / (8 * sizeof(long))]; - } __sanitizer___kernel_fd_set; +typedef long long __sanitizer___kernel_loff_t; +typedef struct { + unsigned long fds_bits[1024 / (8 * sizeof(long))]; +} __sanitizer___kernel_fd_set; #endif - // This thing depends on the platform. We are only interested in the upper - // limit. Verified with a compiler assert in .cc. - const int pthread_attr_t_max_sz = 128; - union __sanitizer_pthread_attr_t { - char size[pthread_attr_t_max_sz]; // NOLINT - void *align; - }; +// This thing depends on the platform. We are only interested in the upper +// limit. Verified with a compiler assert in .cpp. +union __sanitizer_pthread_attr_t { + char size[128]; + void *align; +}; #if SANITIZER_ANDROID # if SANITIZER_MIPS - typedef unsigned long __sanitizer_sigset_t[16/sizeof(unsigned long)]; +typedef unsigned long __sanitizer_sigset_t[16 / sizeof(unsigned long)]; # else - typedef unsigned long __sanitizer_sigset_t; +typedef unsigned long __sanitizer_sigset_t; # endif #elif SANITIZER_MAC - typedef unsigned __sanitizer_sigset_t; +typedef unsigned __sanitizer_sigset_t; #elif SANITIZER_LINUX - struct __sanitizer_sigset_t { - // The size is determined by looking at sizeof of real sigset_t on linux. - uptr val[128 / sizeof(uptr)]; - }; +struct __sanitizer_sigset_t { + // The size is determined by looking at sizeof of real sigset_t on linux. + uptr val[128 / sizeof(uptr)]; +}; #endif - struct __sanitizer_siginfo { - // The size is determined by looking at sizeof of real siginfo_t on linux. - u64 opaque[128 / sizeof(u64)]; - }; +struct __sanitizer_siginfo { + // The size is determined by looking at sizeof of real siginfo_t on linux. + u64 opaque[128 / sizeof(u64)]; +}; - using __sanitizer_sighandler_ptr = void (*)(int sig); - using __sanitizer_sigactionhandler_ptr = - void (*)(int sig, __sanitizer_siginfo *siginfo, void *uctx); +using __sanitizer_sighandler_ptr = void (*)(int sig); +using __sanitizer_sigactionhandler_ptr = void (*)(int sig, + __sanitizer_siginfo *siginfo, + void *uctx); - // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. +// Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. #if SANITIZER_ANDROID && (SANITIZER_WORDSIZE == 64) - struct __sanitizer_sigaction { - unsigned sa_flags; - union { - __sanitizer_sigactionhandler_ptr sigaction; - __sanitizer_sighandler_ptr handler; - }; - __sanitizer_sigset_t sa_mask; - void (*sa_restorer)(); +struct __sanitizer_sigaction { + unsigned sa_flags; + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; }; + __sanitizer_sigset_t sa_mask; + void (*sa_restorer)(); +}; #elif SANITIZER_ANDROID && SANITIZER_MIPS32 // check this before WORDSIZE == 32 - struct __sanitizer_sigaction { - unsigned sa_flags; - union { - __sanitizer_sigactionhandler_ptr sigaction; - __sanitizer_sighandler_ptr handler; - }; - __sanitizer_sigset_t sa_mask; +struct __sanitizer_sigaction { + unsigned sa_flags; + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; }; + __sanitizer_sigset_t sa_mask; +}; #elif SANITIZER_ANDROID && (SANITIZER_WORDSIZE == 32) - struct __sanitizer_sigaction { - union { - __sanitizer_sigactionhandler_ptr sigaction; - __sanitizer_sighandler_ptr handler; - }; - __sanitizer_sigset_t sa_mask; - uptr sa_flags; - void (*sa_restorer)(); +struct __sanitizer_sigaction { + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; }; + __sanitizer_sigset_t sa_mask; + uptr sa_flags; + void (*sa_restorer)(); +}; #else // !SANITIZER_ANDROID - struct __sanitizer_sigaction { +struct __sanitizer_sigaction { #if defined(__mips__) && !SANITIZER_FREEBSD - unsigned int sa_flags; + unsigned int sa_flags; #endif - union { - __sanitizer_sigactionhandler_ptr sigaction; - __sanitizer_sighandler_ptr handler; - }; + union { + __sanitizer_sigactionhandler_ptr sigaction; + __sanitizer_sighandler_ptr handler; + }; #if SANITIZER_FREEBSD - int sa_flags; - __sanitizer_sigset_t sa_mask; + int sa_flags; + __sanitizer_sigset_t sa_mask; #else #if defined(__s390x__) - int sa_resv; + int sa_resv; #else - __sanitizer_sigset_t sa_mask; + __sanitizer_sigset_t sa_mask; #endif #ifndef __mips__ #if defined(__sparc__) #if __GLIBC_PREREQ (2, 20) - // On sparc glibc 2.19 and earlier sa_flags was unsigned long. + // On sparc glibc 2.19 and earlier sa_flags was unsigned long. #if defined(__arch64__) - // To maintain ABI compatibility on sparc64 when switching to an int, - // __glibc_reserved0 was added. - int __glibc_reserved0; + // To maintain ABI compatibility on sparc64 when switching to an int, + // __glibc_reserved0 was added. + int __glibc_reserved0; #endif - int sa_flags; + int sa_flags; #else - unsigned long sa_flags; + unsigned long sa_flags; #endif #else - int sa_flags; + int sa_flags; #endif #endif #endif #if SANITIZER_LINUX - void (*sa_restorer)(); + void (*sa_restorer)(); #endif #if defined(__mips__) && (SANITIZER_WORDSIZE == 32) - int sa_resv[1]; + int sa_resv[1]; #endif #if defined(__s390x__) - __sanitizer_sigset_t sa_mask; + __sanitizer_sigset_t sa_mask; #endif - }; +}; #endif // !SANITIZER_ANDROID #if defined(__mips__) - struct __sanitizer_kernel_sigset_t { - uptr sig[2]; - }; +struct __sanitizer_kernel_sigset_t { + uptr sig[2]; +}; #else - struct __sanitizer_kernel_sigset_t { - u8 sig[8]; - }; +struct __sanitizer_kernel_sigset_t { + u8 sig[8]; +}; #endif - // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. +// Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. #if SANITIZER_MIPS - struct __sanitizer_kernel_sigaction_t { - unsigned int sa_flags; - union { - void (*handler)(int signo); - void (*sigaction)(int signo, __sanitizer_siginfo *info, void *ctx); - }; - __sanitizer_kernel_sigset_t sa_mask; - void (*sa_restorer)(void); +struct __sanitizer_kernel_sigaction_t { + unsigned int sa_flags; + union { + void (*handler)(int signo); + void (*sigaction)(int signo, __sanitizer_siginfo *info, void *ctx); }; + __sanitizer_kernel_sigset_t sa_mask; + void (*sa_restorer)(void); +}; #else - struct __sanitizer_kernel_sigaction_t { - union { - void (*handler)(int signo); - void (*sigaction)(int signo, __sanitizer_siginfo *info, void *ctx); - }; - unsigned long sa_flags; - void (*sa_restorer)(void); - __sanitizer_kernel_sigset_t sa_mask; +struct __sanitizer_kernel_sigaction_t { + union { + void (*handler)(int signo); + void (*sigaction)(int signo, __sanitizer_siginfo *info, void *ctx); }; + unsigned long sa_flags; + void (*sa_restorer)(void); + __sanitizer_kernel_sigset_t sa_mask; +}; #endif - extern const uptr sig_ign; - extern const uptr sig_dfl; - extern const uptr sig_err; - extern const uptr sa_siginfo; +extern const uptr sig_ign; +extern const uptr sig_dfl; +extern const uptr sig_err; +extern const uptr sa_siginfo; #if SANITIZER_LINUX - extern int e_tabsz; +extern int e_tabsz; #endif - extern int af_inet; - extern int af_inet6; - uptr __sanitizer_in_addr_sz(int af); +extern int af_inet; +extern int af_inet6; +uptr __sanitizer_in_addr_sz(int af); #if SANITIZER_LINUX - struct __sanitizer_dl_phdr_info { - uptr dlpi_addr; - const char *dlpi_name; - const void *dlpi_phdr; - short dlpi_phnum; - }; +struct __sanitizer_dl_phdr_info { + uptr dlpi_addr; + const char *dlpi_name; + const void *dlpi_phdr; + short dlpi_phnum; +}; - extern unsigned struct_ElfW_Phdr_sz; +extern unsigned struct_ElfW_Phdr_sz; #endif - struct __sanitizer_addrinfo { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; +struct __sanitizer_addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; #if SANITIZER_ANDROID || SANITIZER_MAC - unsigned ai_addrlen; - char *ai_canonname; - void *ai_addr; + unsigned ai_addrlen; + char *ai_canonname; + void *ai_addr; #else // LINUX - unsigned ai_addrlen; - void *ai_addr; - char *ai_canonname; + unsigned ai_addrlen; + void *ai_addr; + char *ai_canonname; #endif - struct __sanitizer_addrinfo *ai_next; - }; + struct __sanitizer_addrinfo *ai_next; +}; - struct __sanitizer_hostent { - char *h_name; - char **h_aliases; - int h_addrtype; - int h_length; - char **h_addr_list; - }; +struct __sanitizer_hostent { + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; +}; - struct __sanitizer_pollfd { - int fd; - short events; - short revents; - }; +struct __sanitizer_pollfd { + int fd; + short events; + short revents; +}; #if SANITIZER_ANDROID || SANITIZER_MAC - typedef unsigned __sanitizer_nfds_t; +typedef unsigned __sanitizer_nfds_t; #else - typedef unsigned long __sanitizer_nfds_t; +typedef unsigned long __sanitizer_nfds_t; #endif #if !SANITIZER_ANDROID # if SANITIZER_LINUX - struct __sanitizer_glob_t { - uptr gl_pathc; - char **gl_pathv; - uptr gl_offs; - int gl_flags; - - void (*gl_closedir)(void *dirp); - void *(*gl_readdir)(void *dirp); - void *(*gl_opendir)(const char *); - int (*gl_lstat)(const char *, void *); - int (*gl_stat)(const char *, void *); - }; +struct __sanitizer_glob_t { + uptr gl_pathc; + char **gl_pathv; + uptr gl_offs; + int gl_flags; + + void (*gl_closedir)(void *dirp); + void *(*gl_readdir)(void *dirp); + void *(*gl_opendir)(const char *); + int (*gl_lstat)(const char *, void *); + int (*gl_stat)(const char *, void *); +}; # endif // SANITIZER_LINUX # if SANITIZER_LINUX - extern int glob_nomatch; - extern int glob_altdirfunc; +extern int glob_nomatch; +extern int glob_altdirfunc; # endif #endif // !SANITIZER_ANDROID - extern unsigned path_max; +extern unsigned path_max; - struct __sanitizer_wordexp_t { - uptr we_wordc; - char **we_wordv; - uptr we_offs; - }; +struct __sanitizer_wordexp_t { + uptr we_wordc; + char **we_wordv; + uptr we_offs; +}; #if SANITIZER_LINUX && !SANITIZER_ANDROID - struct __sanitizer_FILE { - int _flags; - char *_IO_read_ptr; - char *_IO_read_end; - char *_IO_read_base; - char *_IO_write_base; - char *_IO_write_ptr; - char *_IO_write_end; - char *_IO_buf_base; - char *_IO_buf_end; - char *_IO_save_base; - char *_IO_backup_base; - char *_IO_save_end; - void *_markers; - __sanitizer_FILE *_chain; - int _fileno; - }; +struct __sanitizer_FILE { + int _flags; + char *_IO_read_ptr; + char *_IO_read_end; + char *_IO_read_base; + char *_IO_write_base; + char *_IO_write_ptr; + char *_IO_write_end; + char *_IO_buf_base; + char *_IO_buf_end; + char *_IO_save_base; + char *_IO_backup_base; + char *_IO_save_end; + void *_markers; + __sanitizer_FILE *_chain; + int _fileno; +}; # define SANITIZER_HAS_STRUCT_FILE 1 #else - typedef void __sanitizer_FILE; +typedef void __sanitizer_FILE; # define SANITIZER_HAS_STRUCT_FILE 0 #endif -#if SANITIZER_LINUX && !SANITIZER_ANDROID && \ - (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ - defined(__s390__)) - extern unsigned struct_user_regs_struct_sz; - extern unsigned struct_user_fpregs_struct_sz; - extern unsigned struct_user_fpxregs_struct_sz; - extern unsigned struct_user_vfpregs_struct_sz; - - extern int ptrace_peektext; - extern int ptrace_peekdata; - extern int ptrace_peekuser; - extern int ptrace_getregs; - extern int ptrace_setregs; - extern int ptrace_getfpregs; - extern int ptrace_setfpregs; - extern int ptrace_getfpxregs; - extern int ptrace_setfpxregs; - extern int ptrace_getvfpregs; - extern int ptrace_setvfpregs; - extern int ptrace_getsiginfo; - extern int ptrace_setsiginfo; - extern int ptrace_getregset; - extern int ptrace_setregset; - extern int ptrace_geteventmsg; +#if SANITIZER_LINUX && !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ + defined(__s390__)) +extern unsigned struct_user_regs_struct_sz; +extern unsigned struct_user_fpregs_struct_sz; +extern unsigned struct_user_fpxregs_struct_sz; +extern unsigned struct_user_vfpregs_struct_sz; + +extern int ptrace_peektext; +extern int ptrace_peekdata; +extern int ptrace_peekuser; +extern int ptrace_getregs; +extern int ptrace_setregs; +extern int ptrace_getfpregs; +extern int ptrace_setfpregs; +extern int ptrace_getfpxregs; +extern int ptrace_setfpxregs; +extern int ptrace_getvfpregs; +extern int ptrace_setvfpregs; +extern int ptrace_getsiginfo; +extern int ptrace_setsiginfo; +extern int ptrace_getregset; +extern int ptrace_setregset; +extern int ptrace_geteventmsg; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID - extern unsigned struct_shminfo_sz; - extern unsigned struct_shm_info_sz; - extern int shmctl_ipc_stat; - extern int shmctl_ipc_info; - extern int shmctl_shm_info; - extern int shmctl_shm_stat; +extern unsigned struct_shminfo_sz; +extern unsigned struct_shm_info_sz; +extern int shmctl_ipc_stat; +extern int shmctl_ipc_info; +extern int shmctl_shm_info; +extern int shmctl_shm_stat; #endif #if !SANITIZER_MAC && !SANITIZER_FREEBSD - extern unsigned struct_utmp_sz; +extern unsigned struct_utmp_sz; #endif #if !SANITIZER_ANDROID - extern unsigned struct_utmpx_sz; +extern unsigned struct_utmpx_sz; #endif - extern int map_fixed; +extern int map_fixed; - // ioctl arguments - struct __sanitizer_ifconf { - int ifc_len; - union { - void *ifcu_req; - } ifc_ifcu; +// ioctl arguments +struct __sanitizer_ifconf { + int ifc_len; + union { + void *ifcu_req; + } ifc_ifcu; #if SANITIZER_MAC - } __attribute__((packed)); +} __attribute__((packed)); #else - }; +}; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID @@ -932,519 +934,519 @@ struct __sanitizer_cookie_io_functions_t { #define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) #endif - extern unsigned struct_ifreq_sz; - extern unsigned struct_termios_sz; - extern unsigned struct_winsize_sz; +extern unsigned struct_ifreq_sz; +extern unsigned struct_termios_sz; +extern unsigned struct_winsize_sz; #if SANITIZER_LINUX - extern unsigned struct_arpreq_sz; - extern unsigned struct_cdrom_msf_sz; - extern unsigned struct_cdrom_multisession_sz; - extern unsigned struct_cdrom_read_audio_sz; - extern unsigned struct_cdrom_subchnl_sz; - extern unsigned struct_cdrom_ti_sz; - extern unsigned struct_cdrom_tocentry_sz; - extern unsigned struct_cdrom_tochdr_sz; - extern unsigned struct_cdrom_volctrl_sz; - extern unsigned struct_ff_effect_sz; - extern unsigned struct_floppy_drive_params_sz; - extern unsigned struct_floppy_drive_struct_sz; - extern unsigned struct_floppy_fdc_state_sz; - extern unsigned struct_floppy_max_errors_sz; - extern unsigned struct_floppy_raw_cmd_sz; - extern unsigned struct_floppy_struct_sz; - extern unsigned struct_floppy_write_errors_sz; - extern unsigned struct_format_descr_sz; - extern unsigned struct_hd_driveid_sz; - extern unsigned struct_hd_geometry_sz; - extern unsigned struct_input_absinfo_sz; - extern unsigned struct_input_id_sz; - extern unsigned struct_mtpos_sz; - extern unsigned struct_termio_sz; - extern unsigned struct_vt_consize_sz; - extern unsigned struct_vt_sizes_sz; - extern unsigned struct_vt_stat_sz; +extern unsigned struct_arpreq_sz; +extern unsigned struct_cdrom_msf_sz; +extern unsigned struct_cdrom_multisession_sz; +extern unsigned struct_cdrom_read_audio_sz; +extern unsigned struct_cdrom_subchnl_sz; +extern unsigned struct_cdrom_ti_sz; +extern unsigned struct_cdrom_tocentry_sz; +extern unsigned struct_cdrom_tochdr_sz; +extern unsigned struct_cdrom_volctrl_sz; +extern unsigned struct_ff_effect_sz; +extern unsigned struct_floppy_drive_params_sz; +extern unsigned struct_floppy_drive_struct_sz; +extern unsigned struct_floppy_fdc_state_sz; +extern unsigned struct_floppy_max_errors_sz; +extern unsigned struct_floppy_raw_cmd_sz; +extern unsigned struct_floppy_struct_sz; +extern unsigned struct_floppy_write_errors_sz; +extern unsigned struct_format_descr_sz; +extern unsigned struct_hd_driveid_sz; +extern unsigned struct_hd_geometry_sz; +extern unsigned struct_input_absinfo_sz; +extern unsigned struct_input_id_sz; +extern unsigned struct_mtpos_sz; +extern unsigned struct_termio_sz; +extern unsigned struct_vt_consize_sz; +extern unsigned struct_vt_sizes_sz; +extern unsigned struct_vt_stat_sz; #endif // SANITIZER_LINUX #if SANITIZER_LINUX - extern unsigned struct_copr_buffer_sz; - extern unsigned struct_copr_debug_buf_sz; - extern unsigned struct_copr_msg_sz; - extern unsigned struct_midi_info_sz; - extern unsigned struct_mtget_sz; - extern unsigned struct_mtop_sz; - extern unsigned struct_rtentry_sz; - extern unsigned struct_sbi_instrument_sz; - extern unsigned struct_seq_event_rec_sz; - extern unsigned struct_synth_info_sz; - extern unsigned struct_vt_mode_sz; +extern unsigned struct_copr_buffer_sz; +extern unsigned struct_copr_debug_buf_sz; +extern unsigned struct_copr_msg_sz; +extern unsigned struct_midi_info_sz; +extern unsigned struct_mtget_sz; +extern unsigned struct_mtop_sz; +extern unsigned struct_rtentry_sz; +extern unsigned struct_sbi_instrument_sz; +extern unsigned struct_seq_event_rec_sz; +extern unsigned struct_synth_info_sz; +extern unsigned struct_vt_mode_sz; #endif // SANITIZER_LINUX #if SANITIZER_LINUX && !SANITIZER_ANDROID - extern unsigned struct_ax25_parms_struct_sz; - extern unsigned struct_cyclades_monitor_sz; - extern unsigned struct_input_keymap_entry_sz; - extern unsigned struct_ipx_config_data_sz; - extern unsigned struct_kbdiacrs_sz; - extern unsigned struct_kbentry_sz; - extern unsigned struct_kbkeycode_sz; - extern unsigned struct_kbsentry_sz; - extern unsigned struct_mtconfiginfo_sz; - extern unsigned struct_nr_parms_struct_sz; - extern unsigned struct_scc_modem_sz; - extern unsigned struct_scc_stat_sz; - extern unsigned struct_serial_multiport_struct_sz; - extern unsigned struct_serial_struct_sz; - extern unsigned struct_sockaddr_ax25_sz; - extern unsigned struct_unimapdesc_sz; - extern unsigned struct_unimapinit_sz; +extern unsigned struct_ax25_parms_struct_sz; +extern unsigned struct_cyclades_monitor_sz; +extern unsigned struct_input_keymap_entry_sz; +extern unsigned struct_ipx_config_data_sz; +extern unsigned struct_kbdiacrs_sz; +extern unsigned struct_kbentry_sz; +extern unsigned struct_kbkeycode_sz; +extern unsigned struct_kbsentry_sz; +extern unsigned struct_mtconfiginfo_sz; +extern unsigned struct_nr_parms_struct_sz; +extern unsigned struct_scc_modem_sz; +extern unsigned struct_scc_stat_sz; +extern unsigned struct_serial_multiport_struct_sz; +extern unsigned struct_serial_struct_sz; +extern unsigned struct_sockaddr_ax25_sz; +extern unsigned struct_unimapdesc_sz; +extern unsigned struct_unimapinit_sz; #endif // SANITIZER_LINUX && !SANITIZER_ANDROID - extern const unsigned long __sanitizer_bufsiz; +extern const unsigned long __sanitizer_bufsiz; #if SANITIZER_LINUX && !SANITIZER_ANDROID - extern unsigned struct_audio_buf_info_sz; - extern unsigned struct_ppp_stats_sz; +extern unsigned struct_audio_buf_info_sz; +extern unsigned struct_ppp_stats_sz; #endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID #if !SANITIZER_ANDROID && !SANITIZER_MAC - extern unsigned struct_sioc_sg_req_sz; - extern unsigned struct_sioc_vif_req_sz; -#endif - - // ioctl request identifiers - - // A special value to mark ioctls that are not present on the target platform, - // when it can not be determined without including any system headers. - extern const unsigned IOCTL_NOT_PRESENT; - - extern unsigned IOCTL_FIOASYNC; - extern unsigned IOCTL_FIOCLEX; - extern unsigned IOCTL_FIOGETOWN; - extern unsigned IOCTL_FIONBIO; - extern unsigned IOCTL_FIONCLEX; - extern unsigned IOCTL_FIOSETOWN; - extern unsigned IOCTL_SIOCADDMULTI; - extern unsigned IOCTL_SIOCATMARK; - extern unsigned IOCTL_SIOCDELMULTI; - extern unsigned IOCTL_SIOCGIFADDR; - extern unsigned IOCTL_SIOCGIFBRDADDR; - extern unsigned IOCTL_SIOCGIFCONF; - extern unsigned IOCTL_SIOCGIFDSTADDR; - extern unsigned IOCTL_SIOCGIFFLAGS; - extern unsigned IOCTL_SIOCGIFMETRIC; - extern unsigned IOCTL_SIOCGIFMTU; - extern unsigned IOCTL_SIOCGIFNETMASK; - extern unsigned IOCTL_SIOCGPGRP; - extern unsigned IOCTL_SIOCSIFADDR; - extern unsigned IOCTL_SIOCSIFBRDADDR; - extern unsigned IOCTL_SIOCSIFDSTADDR; - extern unsigned IOCTL_SIOCSIFFLAGS; - extern unsigned IOCTL_SIOCSIFMETRIC; - extern unsigned IOCTL_SIOCSIFMTU; - extern unsigned IOCTL_SIOCSIFNETMASK; - extern unsigned IOCTL_SIOCSPGRP; - extern unsigned IOCTL_TIOCCONS; - extern unsigned IOCTL_TIOCEXCL; - extern unsigned IOCTL_TIOCGETD; - extern unsigned IOCTL_TIOCGPGRP; - extern unsigned IOCTL_TIOCGWINSZ; - extern unsigned IOCTL_TIOCMBIC; - extern unsigned IOCTL_TIOCMBIS; - extern unsigned IOCTL_TIOCMGET; - extern unsigned IOCTL_TIOCMSET; - extern unsigned IOCTL_TIOCNOTTY; - extern unsigned IOCTL_TIOCNXCL; - extern unsigned IOCTL_TIOCOUTQ; - extern unsigned IOCTL_TIOCPKT; - extern unsigned IOCTL_TIOCSCTTY; - extern unsigned IOCTL_TIOCSETD; - extern unsigned IOCTL_TIOCSPGRP; - extern unsigned IOCTL_TIOCSTI; - extern unsigned IOCTL_TIOCSWINSZ; +extern unsigned struct_sioc_sg_req_sz; +extern unsigned struct_sioc_vif_req_sz; +#endif + +// ioctl request identifiers + +// A special value to mark ioctls that are not present on the target platform, +// when it can not be determined without including any system headers. +extern const unsigned IOCTL_NOT_PRESENT; + +extern unsigned IOCTL_FIOASYNC; +extern unsigned IOCTL_FIOCLEX; +extern unsigned IOCTL_FIOGETOWN; +extern unsigned IOCTL_FIONBIO; +extern unsigned IOCTL_FIONCLEX; +extern unsigned IOCTL_FIOSETOWN; +extern unsigned IOCTL_SIOCADDMULTI; +extern unsigned IOCTL_SIOCATMARK; +extern unsigned IOCTL_SIOCDELMULTI; +extern unsigned IOCTL_SIOCGIFADDR; +extern unsigned IOCTL_SIOCGIFBRDADDR; +extern unsigned IOCTL_SIOCGIFCONF; +extern unsigned IOCTL_SIOCGIFDSTADDR; +extern unsigned IOCTL_SIOCGIFFLAGS; +extern unsigned IOCTL_SIOCGIFMETRIC; +extern unsigned IOCTL_SIOCGIFMTU; +extern unsigned IOCTL_SIOCGIFNETMASK; +extern unsigned IOCTL_SIOCGPGRP; +extern unsigned IOCTL_SIOCSIFADDR; +extern unsigned IOCTL_SIOCSIFBRDADDR; +extern unsigned IOCTL_SIOCSIFDSTADDR; +extern unsigned IOCTL_SIOCSIFFLAGS; +extern unsigned IOCTL_SIOCSIFMETRIC; +extern unsigned IOCTL_SIOCSIFMTU; +extern unsigned IOCTL_SIOCSIFNETMASK; +extern unsigned IOCTL_SIOCSPGRP; +extern unsigned IOCTL_TIOCCONS; +extern unsigned IOCTL_TIOCEXCL; +extern unsigned IOCTL_TIOCGETD; +extern unsigned IOCTL_TIOCGPGRP; +extern unsigned IOCTL_TIOCGWINSZ; +extern unsigned IOCTL_TIOCMBIC; +extern unsigned IOCTL_TIOCMBIS; +extern unsigned IOCTL_TIOCMGET; +extern unsigned IOCTL_TIOCMSET; +extern unsigned IOCTL_TIOCNOTTY; +extern unsigned IOCTL_TIOCNXCL; +extern unsigned IOCTL_TIOCOUTQ; +extern unsigned IOCTL_TIOCPKT; +extern unsigned IOCTL_TIOCSCTTY; +extern unsigned IOCTL_TIOCSETD; +extern unsigned IOCTL_TIOCSPGRP; +extern unsigned IOCTL_TIOCSTI; +extern unsigned IOCTL_TIOCSWINSZ; #if SANITIZER_LINUX && !SANITIZER_ANDROID - extern unsigned IOCTL_SIOCGETSGCNT; - extern unsigned IOCTL_SIOCGETVIFCNT; +extern unsigned IOCTL_SIOCGETSGCNT; +extern unsigned IOCTL_SIOCGETVIFCNT; #endif #if SANITIZER_LINUX - extern unsigned IOCTL_EVIOCGABS; - extern unsigned IOCTL_EVIOCGBIT; - extern unsigned IOCTL_EVIOCGEFFECTS; - extern unsigned IOCTL_EVIOCGID; - extern unsigned IOCTL_EVIOCGKEY; - extern unsigned IOCTL_EVIOCGKEYCODE; - extern unsigned IOCTL_EVIOCGLED; - extern unsigned IOCTL_EVIOCGNAME; - extern unsigned IOCTL_EVIOCGPHYS; - extern unsigned IOCTL_EVIOCGRAB; - extern unsigned IOCTL_EVIOCGREP; - extern unsigned IOCTL_EVIOCGSND; - extern unsigned IOCTL_EVIOCGSW; - extern unsigned IOCTL_EVIOCGUNIQ; - extern unsigned IOCTL_EVIOCGVERSION; - extern unsigned IOCTL_EVIOCRMFF; - extern unsigned IOCTL_EVIOCSABS; - extern unsigned IOCTL_EVIOCSFF; - extern unsigned IOCTL_EVIOCSKEYCODE; - extern unsigned IOCTL_EVIOCSREP; - extern unsigned IOCTL_BLKFLSBUF; - extern unsigned IOCTL_BLKGETSIZE; - extern unsigned IOCTL_BLKRAGET; - extern unsigned IOCTL_BLKRASET; - extern unsigned IOCTL_BLKROGET; - extern unsigned IOCTL_BLKROSET; - extern unsigned IOCTL_BLKRRPART; - extern unsigned IOCTL_CDROMAUDIOBUFSIZ; - extern unsigned IOCTL_CDROMEJECT; - extern unsigned IOCTL_CDROMEJECT_SW; - extern unsigned IOCTL_CDROMMULTISESSION; - extern unsigned IOCTL_CDROMPAUSE; - extern unsigned IOCTL_CDROMPLAYMSF; - extern unsigned IOCTL_CDROMPLAYTRKIND; - extern unsigned IOCTL_CDROMREADAUDIO; - extern unsigned IOCTL_CDROMREADCOOKED; - extern unsigned IOCTL_CDROMREADMODE1; - extern unsigned IOCTL_CDROMREADMODE2; - extern unsigned IOCTL_CDROMREADRAW; - extern unsigned IOCTL_CDROMREADTOCENTRY; - extern unsigned IOCTL_CDROMREADTOCHDR; - extern unsigned IOCTL_CDROMRESET; - extern unsigned IOCTL_CDROMRESUME; - extern unsigned IOCTL_CDROMSEEK; - extern unsigned IOCTL_CDROMSTART; - extern unsigned IOCTL_CDROMSTOP; - extern unsigned IOCTL_CDROMSUBCHNL; - extern unsigned IOCTL_CDROMVOLCTRL; - extern unsigned IOCTL_CDROMVOLREAD; - extern unsigned IOCTL_CDROM_GET_UPC; - extern unsigned IOCTL_FDCLRPRM; - extern unsigned IOCTL_FDDEFPRM; - extern unsigned IOCTL_FDFLUSH; - extern unsigned IOCTL_FDFMTBEG; - extern unsigned IOCTL_FDFMTEND; - extern unsigned IOCTL_FDFMTTRK; - extern unsigned IOCTL_FDGETDRVPRM; - extern unsigned IOCTL_FDGETDRVSTAT; - extern unsigned IOCTL_FDGETDRVTYP; - extern unsigned IOCTL_FDGETFDCSTAT; - extern unsigned IOCTL_FDGETMAXERRS; - extern unsigned IOCTL_FDGETPRM; - extern unsigned IOCTL_FDMSGOFF; - extern unsigned IOCTL_FDMSGON; - extern unsigned IOCTL_FDPOLLDRVSTAT; - extern unsigned IOCTL_FDRAWCMD; - extern unsigned IOCTL_FDRESET; - extern unsigned IOCTL_FDSETDRVPRM; - extern unsigned IOCTL_FDSETEMSGTRESH; - extern unsigned IOCTL_FDSETMAXERRS; - extern unsigned IOCTL_FDSETPRM; - extern unsigned IOCTL_FDTWADDLE; - extern unsigned IOCTL_FDWERRORCLR; - extern unsigned IOCTL_FDWERRORGET; - extern unsigned IOCTL_HDIO_DRIVE_CMD; - extern unsigned IOCTL_HDIO_GETGEO; - extern unsigned IOCTL_HDIO_GET_32BIT; - extern unsigned IOCTL_HDIO_GET_DMA; - extern unsigned IOCTL_HDIO_GET_IDENTITY; - extern unsigned IOCTL_HDIO_GET_KEEPSETTINGS; - extern unsigned IOCTL_HDIO_GET_MULTCOUNT; - extern unsigned IOCTL_HDIO_GET_NOWERR; - extern unsigned IOCTL_HDIO_GET_UNMASKINTR; - extern unsigned IOCTL_HDIO_SET_32BIT; - extern unsigned IOCTL_HDIO_SET_DMA; - extern unsigned IOCTL_HDIO_SET_KEEPSETTINGS; - extern unsigned IOCTL_HDIO_SET_MULTCOUNT; - extern unsigned IOCTL_HDIO_SET_NOWERR; - extern unsigned IOCTL_HDIO_SET_UNMASKINTR; - extern unsigned IOCTL_MTIOCPOS; - extern unsigned IOCTL_PPPIOCGASYNCMAP; - extern unsigned IOCTL_PPPIOCGDEBUG; - extern unsigned IOCTL_PPPIOCGFLAGS; - extern unsigned IOCTL_PPPIOCGUNIT; - extern unsigned IOCTL_PPPIOCGXASYNCMAP; - extern unsigned IOCTL_PPPIOCSASYNCMAP; - extern unsigned IOCTL_PPPIOCSDEBUG; - extern unsigned IOCTL_PPPIOCSFLAGS; - extern unsigned IOCTL_PPPIOCSMAXCID; - extern unsigned IOCTL_PPPIOCSMRU; - extern unsigned IOCTL_PPPIOCSXASYNCMAP; - extern unsigned IOCTL_SIOCDARP; - extern unsigned IOCTL_SIOCDRARP; - extern unsigned IOCTL_SIOCGARP; - extern unsigned IOCTL_SIOCGIFENCAP; - extern unsigned IOCTL_SIOCGIFHWADDR; - extern unsigned IOCTL_SIOCGIFMAP; - extern unsigned IOCTL_SIOCGIFMEM; - extern unsigned IOCTL_SIOCGIFNAME; - extern unsigned IOCTL_SIOCGIFSLAVE; - extern unsigned IOCTL_SIOCGRARP; - extern unsigned IOCTL_SIOCGSTAMP; - extern unsigned IOCTL_SIOCSARP; - extern unsigned IOCTL_SIOCSIFENCAP; - extern unsigned IOCTL_SIOCSIFHWADDR; - extern unsigned IOCTL_SIOCSIFLINK; - extern unsigned IOCTL_SIOCSIFMAP; - extern unsigned IOCTL_SIOCSIFMEM; - extern unsigned IOCTL_SIOCSIFSLAVE; - extern unsigned IOCTL_SIOCSRARP; - extern unsigned IOCTL_SNDCTL_COPR_HALT; - extern unsigned IOCTL_SNDCTL_COPR_LOAD; - extern unsigned IOCTL_SNDCTL_COPR_RCODE; - extern unsigned IOCTL_SNDCTL_COPR_RCVMSG; - extern unsigned IOCTL_SNDCTL_COPR_RDATA; - extern unsigned IOCTL_SNDCTL_COPR_RESET; - extern unsigned IOCTL_SNDCTL_COPR_RUN; - extern unsigned IOCTL_SNDCTL_COPR_SENDMSG; - extern unsigned IOCTL_SNDCTL_COPR_WCODE; - extern unsigned IOCTL_SNDCTL_COPR_WDATA; - extern unsigned IOCTL_TCFLSH; - extern unsigned IOCTL_TCGETA; - extern unsigned IOCTL_TCGETS; - extern unsigned IOCTL_TCSBRK; - extern unsigned IOCTL_TCSBRKP; - extern unsigned IOCTL_TCSETA; - extern unsigned IOCTL_TCSETAF; - extern unsigned IOCTL_TCSETAW; - extern unsigned IOCTL_TCSETS; - extern unsigned IOCTL_TCSETSF; - extern unsigned IOCTL_TCSETSW; - extern unsigned IOCTL_TCXONC; - extern unsigned IOCTL_TIOCGLCKTRMIOS; - extern unsigned IOCTL_TIOCGSOFTCAR; - extern unsigned IOCTL_TIOCINQ; - extern unsigned IOCTL_TIOCLINUX; - extern unsigned IOCTL_TIOCSERCONFIG; - extern unsigned IOCTL_TIOCSERGETLSR; - extern unsigned IOCTL_TIOCSERGWILD; - extern unsigned IOCTL_TIOCSERSWILD; - extern unsigned IOCTL_TIOCSLCKTRMIOS; - extern unsigned IOCTL_TIOCSSOFTCAR; - extern unsigned IOCTL_VT_DISALLOCATE; - extern unsigned IOCTL_VT_GETSTATE; - extern unsigned IOCTL_VT_RESIZE; - extern unsigned IOCTL_VT_RESIZEX; - extern unsigned IOCTL_VT_SENDSIG; - extern unsigned IOCTL_MTIOCGET; - extern unsigned IOCTL_MTIOCTOP; - extern unsigned IOCTL_SIOCADDRT; - extern unsigned IOCTL_SIOCDELRT; - extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; - extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; - extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; - extern unsigned IOCTL_SNDCTL_DSP_POST; - extern unsigned IOCTL_SNDCTL_DSP_RESET; - extern unsigned IOCTL_SNDCTL_DSP_SETFMT; - extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; - extern unsigned IOCTL_SNDCTL_DSP_SPEED; - extern unsigned IOCTL_SNDCTL_DSP_STEREO; - extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; - extern unsigned IOCTL_SNDCTL_DSP_SYNC; - extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE; - extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR; - extern unsigned IOCTL_SNDCTL_MIDI_INFO; - extern unsigned IOCTL_SNDCTL_MIDI_PRETIME; - extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE; - extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT; - extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT; - extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS; - extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS; - extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND; - extern unsigned IOCTL_SNDCTL_SEQ_PANIC; - extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE; - extern unsigned IOCTL_SNDCTL_SEQ_RESET; - extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES; - extern unsigned IOCTL_SNDCTL_SEQ_SYNC; - extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI; - extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD; - extern unsigned IOCTL_SNDCTL_SYNTH_INFO; - extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL; - extern unsigned IOCTL_SNDCTL_TMR_CONTINUE; - extern unsigned IOCTL_SNDCTL_TMR_METRONOME; - extern unsigned IOCTL_SNDCTL_TMR_SELECT; - extern unsigned IOCTL_SNDCTL_TMR_SOURCE; - extern unsigned IOCTL_SNDCTL_TMR_START; - extern unsigned IOCTL_SNDCTL_TMR_STOP; - extern unsigned IOCTL_SNDCTL_TMR_TEMPO; - extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE; - extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM; - extern unsigned IOCTL_SOUND_MIXER_READ_BASS; - extern unsigned IOCTL_SOUND_MIXER_READ_CAPS; - extern unsigned IOCTL_SOUND_MIXER_READ_CD; - extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK; - extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE; - extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN; - extern unsigned IOCTL_SOUND_MIXER_READ_IMIX; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE1; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE2; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE3; - extern unsigned IOCTL_SOUND_MIXER_READ_LINE; - extern unsigned IOCTL_SOUND_MIXER_READ_LOUD; - extern unsigned IOCTL_SOUND_MIXER_READ_MIC; - extern unsigned IOCTL_SOUND_MIXER_READ_MUTE; - extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN; - extern unsigned IOCTL_SOUND_MIXER_READ_PCM; - extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV; - extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK; - extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC; - extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER; - extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS; - extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH; - extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE; - extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME; - extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM; - extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS; - extern unsigned IOCTL_SOUND_MIXER_WRITE_CD; - extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN; - extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD; - extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC; - extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN; - extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM; - extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV; - extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC; - extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER; - extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH; - extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE; - extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME; - extern unsigned IOCTL_SOUND_PCM_READ_BITS; - extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; - extern unsigned IOCTL_SOUND_PCM_READ_FILTER; - extern unsigned IOCTL_SOUND_PCM_READ_RATE; - extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS; - extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; - extern unsigned IOCTL_VT_ACTIVATE; - extern unsigned IOCTL_VT_GETMODE; - extern unsigned IOCTL_VT_OPENQRY; - extern unsigned IOCTL_VT_RELDISP; - extern unsigned IOCTL_VT_SETMODE; - extern unsigned IOCTL_VT_WAITACTIVE; +extern unsigned IOCTL_EVIOCGABS; +extern unsigned IOCTL_EVIOCGBIT; +extern unsigned IOCTL_EVIOCGEFFECTS; +extern unsigned IOCTL_EVIOCGID; +extern unsigned IOCTL_EVIOCGKEY; +extern unsigned IOCTL_EVIOCGKEYCODE; +extern unsigned IOCTL_EVIOCGLED; +extern unsigned IOCTL_EVIOCGNAME; +extern unsigned IOCTL_EVIOCGPHYS; +extern unsigned IOCTL_EVIOCGRAB; +extern unsigned IOCTL_EVIOCGREP; +extern unsigned IOCTL_EVIOCGSND; +extern unsigned IOCTL_EVIOCGSW; +extern unsigned IOCTL_EVIOCGUNIQ; +extern unsigned IOCTL_EVIOCGVERSION; +extern unsigned IOCTL_EVIOCRMFF; +extern unsigned IOCTL_EVIOCSABS; +extern unsigned IOCTL_EVIOCSFF; +extern unsigned IOCTL_EVIOCSKEYCODE; +extern unsigned IOCTL_EVIOCSREP; +extern unsigned IOCTL_BLKFLSBUF; +extern unsigned IOCTL_BLKGETSIZE; +extern unsigned IOCTL_BLKRAGET; +extern unsigned IOCTL_BLKRASET; +extern unsigned IOCTL_BLKROGET; +extern unsigned IOCTL_BLKROSET; +extern unsigned IOCTL_BLKRRPART; +extern unsigned IOCTL_CDROMAUDIOBUFSIZ; +extern unsigned IOCTL_CDROMEJECT; +extern unsigned IOCTL_CDROMEJECT_SW; +extern unsigned IOCTL_CDROMMULTISESSION; +extern unsigned IOCTL_CDROMPAUSE; +extern unsigned IOCTL_CDROMPLAYMSF; +extern unsigned IOCTL_CDROMPLAYTRKIND; +extern unsigned IOCTL_CDROMREADAUDIO; +extern unsigned IOCTL_CDROMREADCOOKED; +extern unsigned IOCTL_CDROMREADMODE1; +extern unsigned IOCTL_CDROMREADMODE2; +extern unsigned IOCTL_CDROMREADRAW; +extern unsigned IOCTL_CDROMREADTOCENTRY; +extern unsigned IOCTL_CDROMREADTOCHDR; +extern unsigned IOCTL_CDROMRESET; +extern unsigned IOCTL_CDROMRESUME; +extern unsigned IOCTL_CDROMSEEK; +extern unsigned IOCTL_CDROMSTART; +extern unsigned IOCTL_CDROMSTOP; +extern unsigned IOCTL_CDROMSUBCHNL; +extern unsigned IOCTL_CDROMVOLCTRL; +extern unsigned IOCTL_CDROMVOLREAD; +extern unsigned IOCTL_CDROM_GET_UPC; +extern unsigned IOCTL_FDCLRPRM; +extern unsigned IOCTL_FDDEFPRM; +extern unsigned IOCTL_FDFLUSH; +extern unsigned IOCTL_FDFMTBEG; +extern unsigned IOCTL_FDFMTEND; +extern unsigned IOCTL_FDFMTTRK; +extern unsigned IOCTL_FDGETDRVPRM; +extern unsigned IOCTL_FDGETDRVSTAT; +extern unsigned IOCTL_FDGETDRVTYP; +extern unsigned IOCTL_FDGETFDCSTAT; +extern unsigned IOCTL_FDGETMAXERRS; +extern unsigned IOCTL_FDGETPRM; +extern unsigned IOCTL_FDMSGOFF; +extern unsigned IOCTL_FDMSGON; +extern unsigned IOCTL_FDPOLLDRVSTAT; +extern unsigned IOCTL_FDRAWCMD; +extern unsigned IOCTL_FDRESET; +extern unsigned IOCTL_FDSETDRVPRM; +extern unsigned IOCTL_FDSETEMSGTRESH; +extern unsigned IOCTL_FDSETMAXERRS; +extern unsigned IOCTL_FDSETPRM; +extern unsigned IOCTL_FDTWADDLE; +extern unsigned IOCTL_FDWERRORCLR; +extern unsigned IOCTL_FDWERRORGET; +extern unsigned IOCTL_HDIO_DRIVE_CMD; +extern unsigned IOCTL_HDIO_GETGEO; +extern unsigned IOCTL_HDIO_GET_32BIT; +extern unsigned IOCTL_HDIO_GET_DMA; +extern unsigned IOCTL_HDIO_GET_IDENTITY; +extern unsigned IOCTL_HDIO_GET_KEEPSETTINGS; +extern unsigned IOCTL_HDIO_GET_MULTCOUNT; +extern unsigned IOCTL_HDIO_GET_NOWERR; +extern unsigned IOCTL_HDIO_GET_UNMASKINTR; +extern unsigned IOCTL_HDIO_SET_32BIT; +extern unsigned IOCTL_HDIO_SET_DMA; +extern unsigned IOCTL_HDIO_SET_KEEPSETTINGS; +extern unsigned IOCTL_HDIO_SET_MULTCOUNT; +extern unsigned IOCTL_HDIO_SET_NOWERR; +extern unsigned IOCTL_HDIO_SET_UNMASKINTR; +extern unsigned IOCTL_MTIOCPOS; +extern unsigned IOCTL_PPPIOCGASYNCMAP; +extern unsigned IOCTL_PPPIOCGDEBUG; +extern unsigned IOCTL_PPPIOCGFLAGS; +extern unsigned IOCTL_PPPIOCGUNIT; +extern unsigned IOCTL_PPPIOCGXASYNCMAP; +extern unsigned IOCTL_PPPIOCSASYNCMAP; +extern unsigned IOCTL_PPPIOCSDEBUG; +extern unsigned IOCTL_PPPIOCSFLAGS; +extern unsigned IOCTL_PPPIOCSMAXCID; +extern unsigned IOCTL_PPPIOCSMRU; +extern unsigned IOCTL_PPPIOCSXASYNCMAP; +extern unsigned IOCTL_SIOCDARP; +extern unsigned IOCTL_SIOCDRARP; +extern unsigned IOCTL_SIOCGARP; +extern unsigned IOCTL_SIOCGIFENCAP; +extern unsigned IOCTL_SIOCGIFHWADDR; +extern unsigned IOCTL_SIOCGIFMAP; +extern unsigned IOCTL_SIOCGIFMEM; +extern unsigned IOCTL_SIOCGIFNAME; +extern unsigned IOCTL_SIOCGIFSLAVE; +extern unsigned IOCTL_SIOCGRARP; +extern unsigned IOCTL_SIOCGSTAMP; +extern unsigned IOCTL_SIOCSARP; +extern unsigned IOCTL_SIOCSIFENCAP; +extern unsigned IOCTL_SIOCSIFHWADDR; +extern unsigned IOCTL_SIOCSIFLINK; +extern unsigned IOCTL_SIOCSIFMAP; +extern unsigned IOCTL_SIOCSIFMEM; +extern unsigned IOCTL_SIOCSIFSLAVE; +extern unsigned IOCTL_SIOCSRARP; +extern unsigned IOCTL_SNDCTL_COPR_HALT; +extern unsigned IOCTL_SNDCTL_COPR_LOAD; +extern unsigned IOCTL_SNDCTL_COPR_RCODE; +extern unsigned IOCTL_SNDCTL_COPR_RCVMSG; +extern unsigned IOCTL_SNDCTL_COPR_RDATA; +extern unsigned IOCTL_SNDCTL_COPR_RESET; +extern unsigned IOCTL_SNDCTL_COPR_RUN; +extern unsigned IOCTL_SNDCTL_COPR_SENDMSG; +extern unsigned IOCTL_SNDCTL_COPR_WCODE; +extern unsigned IOCTL_SNDCTL_COPR_WDATA; +extern unsigned IOCTL_TCFLSH; +extern unsigned IOCTL_TCGETA; +extern unsigned IOCTL_TCGETS; +extern unsigned IOCTL_TCSBRK; +extern unsigned IOCTL_TCSBRKP; +extern unsigned IOCTL_TCSETA; +extern unsigned IOCTL_TCSETAF; +extern unsigned IOCTL_TCSETAW; +extern unsigned IOCTL_TCSETS; +extern unsigned IOCTL_TCSETSF; +extern unsigned IOCTL_TCSETSW; +extern unsigned IOCTL_TCXONC; +extern unsigned IOCTL_TIOCGLCKTRMIOS; +extern unsigned IOCTL_TIOCGSOFTCAR; +extern unsigned IOCTL_TIOCINQ; +extern unsigned IOCTL_TIOCLINUX; +extern unsigned IOCTL_TIOCSERCONFIG; +extern unsigned IOCTL_TIOCSERGETLSR; +extern unsigned IOCTL_TIOCSERGWILD; +extern unsigned IOCTL_TIOCSERSWILD; +extern unsigned IOCTL_TIOCSLCKTRMIOS; +extern unsigned IOCTL_TIOCSSOFTCAR; +extern unsigned IOCTL_VT_DISALLOCATE; +extern unsigned IOCTL_VT_GETSTATE; +extern unsigned IOCTL_VT_RESIZE; +extern unsigned IOCTL_VT_RESIZEX; +extern unsigned IOCTL_VT_SENDSIG; +extern unsigned IOCTL_MTIOCGET; +extern unsigned IOCTL_MTIOCTOP; +extern unsigned IOCTL_SIOCADDRT; +extern unsigned IOCTL_SIOCDELRT; +extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; +extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; +extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; +extern unsigned IOCTL_SNDCTL_DSP_POST; +extern unsigned IOCTL_SNDCTL_DSP_RESET; +extern unsigned IOCTL_SNDCTL_DSP_SETFMT; +extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; +extern unsigned IOCTL_SNDCTL_DSP_SPEED; +extern unsigned IOCTL_SNDCTL_DSP_STEREO; +extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; +extern unsigned IOCTL_SNDCTL_DSP_SYNC; +extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE; +extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR; +extern unsigned IOCTL_SNDCTL_MIDI_INFO; +extern unsigned IOCTL_SNDCTL_MIDI_PRETIME; +extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE; +extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT; +extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT; +extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS; +extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS; +extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND; +extern unsigned IOCTL_SNDCTL_SEQ_PANIC; +extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE; +extern unsigned IOCTL_SNDCTL_SEQ_RESET; +extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES; +extern unsigned IOCTL_SNDCTL_SEQ_SYNC; +extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI; +extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD; +extern unsigned IOCTL_SNDCTL_SYNTH_INFO; +extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL; +extern unsigned IOCTL_SNDCTL_TMR_CONTINUE; +extern unsigned IOCTL_SNDCTL_TMR_METRONOME; +extern unsigned IOCTL_SNDCTL_TMR_SELECT; +extern unsigned IOCTL_SNDCTL_TMR_SOURCE; +extern unsigned IOCTL_SNDCTL_TMR_START; +extern unsigned IOCTL_SNDCTL_TMR_STOP; +extern unsigned IOCTL_SNDCTL_TMR_TEMPO; +extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE; +extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM; +extern unsigned IOCTL_SOUND_MIXER_READ_BASS; +extern unsigned IOCTL_SOUND_MIXER_READ_CAPS; +extern unsigned IOCTL_SOUND_MIXER_READ_CD; +extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK; +extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE; +extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN; +extern unsigned IOCTL_SOUND_MIXER_READ_IMIX; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE1; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE2; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE3; +extern unsigned IOCTL_SOUND_MIXER_READ_LINE; +extern unsigned IOCTL_SOUND_MIXER_READ_LOUD; +extern unsigned IOCTL_SOUND_MIXER_READ_MIC; +extern unsigned IOCTL_SOUND_MIXER_READ_MUTE; +extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN; +extern unsigned IOCTL_SOUND_MIXER_READ_PCM; +extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV; +extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK; +extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC; +extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER; +extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS; +extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH; +extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE; +extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME; +extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM; +extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS; +extern unsigned IOCTL_SOUND_MIXER_WRITE_CD; +extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN; +extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD; +extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC; +extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN; +extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM; +extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV; +extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC; +extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER; +extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH; +extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE; +extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME; +extern unsigned IOCTL_SOUND_PCM_READ_BITS; +extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_READ_FILTER; +extern unsigned IOCTL_SOUND_PCM_READ_RATE; +extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS; +extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; +extern unsigned IOCTL_VT_ACTIVATE; +extern unsigned IOCTL_VT_GETMODE; +extern unsigned IOCTL_VT_OPENQRY; +extern unsigned IOCTL_VT_RELDISP; +extern unsigned IOCTL_VT_SETMODE; +extern unsigned IOCTL_VT_WAITACTIVE; #endif // SANITIZER_LINUX #if SANITIZER_LINUX && !SANITIZER_ANDROID - extern unsigned IOCTL_CYGETDEFTHRESH; - extern unsigned IOCTL_CYGETDEFTIMEOUT; - extern unsigned IOCTL_CYGETMON; - extern unsigned IOCTL_CYGETTHRESH; - extern unsigned IOCTL_CYGETTIMEOUT; - extern unsigned IOCTL_CYSETDEFTHRESH; - extern unsigned IOCTL_CYSETDEFTIMEOUT; - extern unsigned IOCTL_CYSETTHRESH; - extern unsigned IOCTL_CYSETTIMEOUT; - extern unsigned IOCTL_EQL_EMANCIPATE; - extern unsigned IOCTL_EQL_ENSLAVE; - extern unsigned IOCTL_EQL_GETMASTRCFG; - extern unsigned IOCTL_EQL_GETSLAVECFG; - extern unsigned IOCTL_EQL_SETMASTRCFG; - extern unsigned IOCTL_EQL_SETSLAVECFG; - extern unsigned IOCTL_EVIOCGKEYCODE_V2; - extern unsigned IOCTL_EVIOCGPROP; - extern unsigned IOCTL_EVIOCSKEYCODE_V2; - extern unsigned IOCTL_FS_IOC_GETFLAGS; - extern unsigned IOCTL_FS_IOC_GETVERSION; - extern unsigned IOCTL_FS_IOC_SETFLAGS; - extern unsigned IOCTL_FS_IOC_SETVERSION; - extern unsigned IOCTL_GIO_CMAP; - extern unsigned IOCTL_GIO_FONT; - extern unsigned IOCTL_GIO_UNIMAP; - extern unsigned IOCTL_GIO_UNISCRNMAP; - extern unsigned IOCTL_KDADDIO; - extern unsigned IOCTL_KDDELIO; - extern unsigned IOCTL_KDGETKEYCODE; - extern unsigned IOCTL_KDGKBDIACR; - extern unsigned IOCTL_KDGKBENT; - extern unsigned IOCTL_KDGKBLED; - extern unsigned IOCTL_KDGKBMETA; - extern unsigned IOCTL_KDGKBSENT; - extern unsigned IOCTL_KDMAPDISP; - extern unsigned IOCTL_KDSETKEYCODE; - extern unsigned IOCTL_KDSIGACCEPT; - extern unsigned IOCTL_KDSKBDIACR; - extern unsigned IOCTL_KDSKBENT; - extern unsigned IOCTL_KDSKBLED; - extern unsigned IOCTL_KDSKBMETA; - extern unsigned IOCTL_KDSKBSENT; - extern unsigned IOCTL_KDUNMAPDISP; - extern unsigned IOCTL_LPABORT; - extern unsigned IOCTL_LPABORTOPEN; - extern unsigned IOCTL_LPCAREFUL; - extern unsigned IOCTL_LPCHAR; - extern unsigned IOCTL_LPGETIRQ; - extern unsigned IOCTL_LPGETSTATUS; - extern unsigned IOCTL_LPRESET; - extern unsigned IOCTL_LPSETIRQ; - extern unsigned IOCTL_LPTIME; - extern unsigned IOCTL_LPWAIT; - extern unsigned IOCTL_MTIOCGETCONFIG; - extern unsigned IOCTL_MTIOCSETCONFIG; - extern unsigned IOCTL_PIO_CMAP; - extern unsigned IOCTL_PIO_FONT; - extern unsigned IOCTL_PIO_UNIMAP; - extern unsigned IOCTL_PIO_UNIMAPCLR; - extern unsigned IOCTL_PIO_UNISCRNMAP; - extern unsigned IOCTL_SCSI_IOCTL_GET_IDLUN; - extern unsigned IOCTL_SCSI_IOCTL_PROBE_HOST; - extern unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE; - extern unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE; - extern unsigned IOCTL_SIOCAIPXITFCRT; - extern unsigned IOCTL_SIOCAIPXPRISLT; - extern unsigned IOCTL_SIOCAX25ADDUID; - extern unsigned IOCTL_SIOCAX25DELUID; - extern unsigned IOCTL_SIOCAX25GETPARMS; - extern unsigned IOCTL_SIOCAX25GETUID; - extern unsigned IOCTL_SIOCAX25NOUID; - extern unsigned IOCTL_SIOCAX25SETPARMS; - extern unsigned IOCTL_SIOCDEVPLIP; - extern unsigned IOCTL_SIOCIPXCFGDATA; - extern unsigned IOCTL_SIOCNRDECOBS; - extern unsigned IOCTL_SIOCNRGETPARMS; - extern unsigned IOCTL_SIOCNRRTCTL; - extern unsigned IOCTL_SIOCNRSETPARMS; - extern unsigned IOCTL_SNDCTL_DSP_GETISPACE; - extern unsigned IOCTL_SNDCTL_DSP_GETOSPACE; - extern unsigned IOCTL_TIOCGSERIAL; - extern unsigned IOCTL_TIOCSERGETMULTI; - extern unsigned IOCTL_TIOCSERSETMULTI; - extern unsigned IOCTL_TIOCSSERIAL; - extern unsigned IOCTL_GIO_SCRNMAP; - extern unsigned IOCTL_KDDISABIO; - extern unsigned IOCTL_KDENABIO; - extern unsigned IOCTL_KDGETLED; - extern unsigned IOCTL_KDGETMODE; - extern unsigned IOCTL_KDGKBMODE; - extern unsigned IOCTL_KDGKBTYPE; - extern unsigned IOCTL_KDMKTONE; - extern unsigned IOCTL_KDSETLED; - extern unsigned IOCTL_KDSETMODE; - extern unsigned IOCTL_KDSKBMODE; - extern unsigned IOCTL_KIOCSOUND; - extern unsigned IOCTL_PIO_SCRNMAP; -#endif - - extern const int si_SEGV_MAPERR; - extern const int si_SEGV_ACCERR; +extern unsigned IOCTL_CYGETDEFTHRESH; +extern unsigned IOCTL_CYGETDEFTIMEOUT; +extern unsigned IOCTL_CYGETMON; +extern unsigned IOCTL_CYGETTHRESH; +extern unsigned IOCTL_CYGETTIMEOUT; +extern unsigned IOCTL_CYSETDEFTHRESH; +extern unsigned IOCTL_CYSETDEFTIMEOUT; +extern unsigned IOCTL_CYSETTHRESH; +extern unsigned IOCTL_CYSETTIMEOUT; +extern unsigned IOCTL_EQL_EMANCIPATE; +extern unsigned IOCTL_EQL_ENSLAVE; +extern unsigned IOCTL_EQL_GETMASTRCFG; +extern unsigned IOCTL_EQL_GETSLAVECFG; +extern unsigned IOCTL_EQL_SETMASTRCFG; +extern unsigned IOCTL_EQL_SETSLAVECFG; +extern unsigned IOCTL_EVIOCGKEYCODE_V2; +extern unsigned IOCTL_EVIOCGPROP; +extern unsigned IOCTL_EVIOCSKEYCODE_V2; +extern unsigned IOCTL_FS_IOC_GETFLAGS; +extern unsigned IOCTL_FS_IOC_GETVERSION; +extern unsigned IOCTL_FS_IOC_SETFLAGS; +extern unsigned IOCTL_FS_IOC_SETVERSION; +extern unsigned IOCTL_GIO_CMAP; +extern unsigned IOCTL_GIO_FONT; +extern unsigned IOCTL_GIO_UNIMAP; +extern unsigned IOCTL_GIO_UNISCRNMAP; +extern unsigned IOCTL_KDADDIO; +extern unsigned IOCTL_KDDELIO; +extern unsigned IOCTL_KDGETKEYCODE; +extern unsigned IOCTL_KDGKBDIACR; +extern unsigned IOCTL_KDGKBENT; +extern unsigned IOCTL_KDGKBLED; +extern unsigned IOCTL_KDGKBMETA; +extern unsigned IOCTL_KDGKBSENT; +extern unsigned IOCTL_KDMAPDISP; +extern unsigned IOCTL_KDSETKEYCODE; +extern unsigned IOCTL_KDSIGACCEPT; +extern unsigned IOCTL_KDSKBDIACR; +extern unsigned IOCTL_KDSKBENT; +extern unsigned IOCTL_KDSKBLED; +extern unsigned IOCTL_KDSKBMETA; +extern unsigned IOCTL_KDSKBSENT; +extern unsigned IOCTL_KDUNMAPDISP; +extern unsigned IOCTL_LPABORT; +extern unsigned IOCTL_LPABORTOPEN; +extern unsigned IOCTL_LPCAREFUL; +extern unsigned IOCTL_LPCHAR; +extern unsigned IOCTL_LPGETIRQ; +extern unsigned IOCTL_LPGETSTATUS; +extern unsigned IOCTL_LPRESET; +extern unsigned IOCTL_LPSETIRQ; +extern unsigned IOCTL_LPTIME; +extern unsigned IOCTL_LPWAIT; +extern unsigned IOCTL_MTIOCGETCONFIG; +extern unsigned IOCTL_MTIOCSETCONFIG; +extern unsigned IOCTL_PIO_CMAP; +extern unsigned IOCTL_PIO_FONT; +extern unsigned IOCTL_PIO_UNIMAP; +extern unsigned IOCTL_PIO_UNIMAPCLR; +extern unsigned IOCTL_PIO_UNISCRNMAP; +extern unsigned IOCTL_SCSI_IOCTL_GET_IDLUN; +extern unsigned IOCTL_SCSI_IOCTL_PROBE_HOST; +extern unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE; +extern unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE; +extern unsigned IOCTL_SIOCAIPXITFCRT; +extern unsigned IOCTL_SIOCAIPXPRISLT; +extern unsigned IOCTL_SIOCAX25ADDUID; +extern unsigned IOCTL_SIOCAX25DELUID; +extern unsigned IOCTL_SIOCAX25GETPARMS; +extern unsigned IOCTL_SIOCAX25GETUID; +extern unsigned IOCTL_SIOCAX25NOUID; +extern unsigned IOCTL_SIOCAX25SETPARMS; +extern unsigned IOCTL_SIOCDEVPLIP; +extern unsigned IOCTL_SIOCIPXCFGDATA; +extern unsigned IOCTL_SIOCNRDECOBS; +extern unsigned IOCTL_SIOCNRGETPARMS; +extern unsigned IOCTL_SIOCNRRTCTL; +extern unsigned IOCTL_SIOCNRSETPARMS; +extern unsigned IOCTL_SNDCTL_DSP_GETISPACE; +extern unsigned IOCTL_SNDCTL_DSP_GETOSPACE; +extern unsigned IOCTL_TIOCGSERIAL; +extern unsigned IOCTL_TIOCSERGETMULTI; +extern unsigned IOCTL_TIOCSERSETMULTI; +extern unsigned IOCTL_TIOCSSERIAL; +extern unsigned IOCTL_GIO_SCRNMAP; +extern unsigned IOCTL_KDDISABIO; +extern unsigned IOCTL_KDENABIO; +extern unsigned IOCTL_KDGETLED; +extern unsigned IOCTL_KDGETMODE; +extern unsigned IOCTL_KDGKBMODE; +extern unsigned IOCTL_KDGKBTYPE; +extern unsigned IOCTL_KDMKTONE; +extern unsigned IOCTL_KDSETLED; +extern unsigned IOCTL_KDSETMODE; +extern unsigned IOCTL_KDSKBMODE; +extern unsigned IOCTL_KIOCSOUND; +extern unsigned IOCTL_PIO_SCRNMAP; +#endif + +extern const int si_SEGV_MAPERR; +extern const int si_SEGV_ACCERR; } // namespace __sanitizer #define CHECK_TYPE_SIZE(TYPE) \ COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) -#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ - COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *) NULL)->MEMBER) == \ - sizeof(((CLASS *) NULL)->MEMBER)); \ - COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ +#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ offsetof(CLASS, MEMBER)) // For sigaction, which is a function and struct at the same time, // and thus requires explicit "struct" in sizeof() expression. -#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ - COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *) NULL)->MEMBER) == \ - sizeof(((struct CLASS *) NULL)->MEMBER)); \ - COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ +#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((struct CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ offsetof(struct CLASS, MEMBER)) #define SIGACTION_SYMNAME sigaction diff --git a/lib/sanitizer_common/sanitizer_platform_limits_solaris.cc b/lib/sanitizer_common/sanitizer_platform_limits_solaris.cc deleted file mode 100644 index 3503eb2eab34..000000000000 --- a/lib/sanitizer_common/sanitizer_platform_limits_solaris.cc +++ /dev/null @@ -1,365 +0,0 @@ -//===-- sanitizer_platform_limits_solaris.cc ------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of Sanitizer common code. -// -// Sizes and layouts of platform-specific Solaris data structures. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_SOLARIS -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Include these after system headers to avoid name clashes and ambiguities. -#include "sanitizer_internal_defs.h" -#include "sanitizer_platform_limits_solaris.h" - -namespace __sanitizer { - unsigned struct_utsname_sz = sizeof(struct utsname); - unsigned struct_stat_sz = sizeof(struct stat); - unsigned struct_stat64_sz = sizeof(struct stat64); - unsigned struct_rusage_sz = sizeof(struct rusage); - unsigned struct_tm_sz = sizeof(struct tm); - unsigned struct_passwd_sz = sizeof(struct passwd); - unsigned struct_group_sz = sizeof(struct group); - unsigned siginfo_t_sz = sizeof(siginfo_t); - unsigned struct_sigaction_sz = sizeof(struct sigaction); - unsigned struct_itimerval_sz = sizeof(struct itimerval); - unsigned pthread_t_sz = sizeof(pthread_t); - unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); - unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); - unsigned pid_t_sz = sizeof(pid_t); - unsigned timeval_sz = sizeof(timeval); - unsigned uid_t_sz = sizeof(uid_t); - unsigned gid_t_sz = sizeof(gid_t); - unsigned mbstate_t_sz = sizeof(mbstate_t); - unsigned sigset_t_sz = sizeof(sigset_t); - unsigned struct_timezone_sz = sizeof(struct timezone); - unsigned struct_tms_sz = sizeof(struct tms); - unsigned struct_sigevent_sz = sizeof(struct sigevent); - unsigned struct_sched_param_sz = sizeof(struct sched_param); - unsigned struct_statfs_sz = sizeof(struct statfs); - unsigned struct_sockaddr_sz = sizeof(struct sockaddr); - unsigned ucontext_t_sz = sizeof(ucontext_t); - unsigned struct_timespec_sz = sizeof(struct timespec); -#if SANITIZER_SOLARIS32 - unsigned struct_statvfs64_sz = sizeof(struct statvfs64); -#endif - unsigned struct_statvfs_sz = sizeof(struct statvfs); - - const uptr sig_ign = (uptr)SIG_IGN; - const uptr sig_dfl = (uptr)SIG_DFL; - const uptr sig_err = (uptr)SIG_ERR; - const uptr sa_siginfo = (uptr)SA_SIGINFO; - - int shmctl_ipc_stat = (int)IPC_STAT; - - unsigned struct_utmp_sz = sizeof(struct utmp); - unsigned struct_utmpx_sz = sizeof(struct utmpx); - - int map_fixed = MAP_FIXED; - - int af_inet = (int)AF_INET; - int af_inet6 = (int)AF_INET6; - - uptr __sanitizer_in_addr_sz(int af) { - if (af == AF_INET) - return sizeof(struct in_addr); - else if (af == AF_INET6) - return sizeof(struct in6_addr); - else - return 0; - } - - unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr)); - - int glob_nomatch = GLOB_NOMATCH; - - unsigned path_max = PATH_MAX; - - // ioctl arguments - unsigned struct_ifreq_sz = sizeof(struct ifreq); - unsigned struct_termios_sz = sizeof(struct termios); - unsigned struct_winsize_sz = sizeof(struct winsize); - - unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); - unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); - - const unsigned IOCTL_NOT_PRESENT = 0; - - unsigned IOCTL_FIOASYNC = FIOASYNC; - unsigned IOCTL_FIOCLEX = FIOCLEX; - unsigned IOCTL_FIOGETOWN = FIOGETOWN; - unsigned IOCTL_FIONBIO = FIONBIO; - unsigned IOCTL_FIONCLEX = FIONCLEX; - unsigned IOCTL_FIOSETOWN = FIOSETOWN; - unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; - unsigned IOCTL_SIOCATMARK = SIOCATMARK; - unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; - unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; - unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; - unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; - unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; - unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; - unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; - unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; - unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; - unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; - unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; - unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; - unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; - unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; - unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; - unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; - unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; - unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; - unsigned IOCTL_TIOCEXCL = TIOCEXCL; - unsigned IOCTL_TIOCGETD = TIOCGETD; - unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; - unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; - unsigned IOCTL_TIOCMBIC = TIOCMBIC; - unsigned IOCTL_TIOCMBIS = TIOCMBIS; - unsigned IOCTL_TIOCMGET = TIOCMGET; - unsigned IOCTL_TIOCMSET = TIOCMSET; - unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; - unsigned IOCTL_TIOCNXCL = TIOCNXCL; - unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; - unsigned IOCTL_TIOCPKT = TIOCPKT; - unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; - unsigned IOCTL_TIOCSETD = TIOCSETD; - unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; - unsigned IOCTL_TIOCSTI = TIOCSTI; - unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; - - unsigned IOCTL_MTIOCGET = MTIOCGET; - unsigned IOCTL_MTIOCTOP = MTIOCTOP; - - const int si_SEGV_MAPERR = SEGV_MAPERR; - const int si_SEGV_ACCERR = SEGV_ACCERR; -} // namespace __sanitizer - -using namespace __sanitizer; - -COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); - -COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); -CHECK_TYPE_SIZE(pthread_key_t); - -// There are more undocumented fields in dl_phdr_info that we are not interested -// in. -COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); - -CHECK_TYPE_SIZE(glob_t); -CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); -CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); -CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); - -CHECK_TYPE_SIZE(addrinfo); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); - -CHECK_TYPE_SIZE(hostent); -CHECK_SIZE_AND_OFFSET(hostent, h_name); -CHECK_SIZE_AND_OFFSET(hostent, h_aliases); -CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); -CHECK_SIZE_AND_OFFSET(hostent, h_length); -CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); - -CHECK_TYPE_SIZE(iovec); -CHECK_SIZE_AND_OFFSET(iovec, iov_base); -CHECK_SIZE_AND_OFFSET(iovec, iov_len); - -CHECK_TYPE_SIZE(msghdr); -CHECK_SIZE_AND_OFFSET(msghdr, msg_name); -CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); -CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_control); -CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); - -CHECK_TYPE_SIZE(cmsghdr); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); - -COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); -CHECK_SIZE_AND_OFFSET(dirent, d_ino); -CHECK_SIZE_AND_OFFSET(dirent, d_off); -CHECK_SIZE_AND_OFFSET(dirent, d_reclen); - -#if SANITIZER_SOLARIS32 -COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64)); -CHECK_SIZE_AND_OFFSET(dirent64, d_ino); -CHECK_SIZE_AND_OFFSET(dirent64, d_off); -CHECK_SIZE_AND_OFFSET(dirent64, d_reclen); -#endif - -CHECK_TYPE_SIZE(ifconf); -CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); -CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); - -CHECK_TYPE_SIZE(pollfd); -CHECK_SIZE_AND_OFFSET(pollfd, fd); -CHECK_SIZE_AND_OFFSET(pollfd, events); -CHECK_SIZE_AND_OFFSET(pollfd, revents); - -CHECK_TYPE_SIZE(nfds_t); - -CHECK_TYPE_SIZE(sigset_t); - -COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); -// Can't write checks for sa_handler and sa_sigaction due to them being -// preprocessor macros. -CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); -CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags); - -CHECK_TYPE_SIZE(wordexp_t); -CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); -CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); -CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); - -CHECK_TYPE_SIZE(tm); -CHECK_SIZE_AND_OFFSET(tm, tm_sec); -CHECK_SIZE_AND_OFFSET(tm, tm_min); -CHECK_SIZE_AND_OFFSET(tm, tm_hour); -CHECK_SIZE_AND_OFFSET(tm, tm_mday); -CHECK_SIZE_AND_OFFSET(tm, tm_mon); -CHECK_SIZE_AND_OFFSET(tm, tm_year); -CHECK_SIZE_AND_OFFSET(tm, tm_wday); -CHECK_SIZE_AND_OFFSET(tm, tm_yday); -CHECK_SIZE_AND_OFFSET(tm, tm_isdst); - -CHECK_TYPE_SIZE(ether_addr); - -CHECK_TYPE_SIZE(ipc_perm); -CHECK_SIZE_AND_OFFSET(ipc_perm, key); -CHECK_SIZE_AND_OFFSET(ipc_perm, seq); -CHECK_SIZE_AND_OFFSET(ipc_perm, uid); -CHECK_SIZE_AND_OFFSET(ipc_perm, gid); -CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); -CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); -CHECK_SIZE_AND_OFFSET(ipc_perm, mode); - -CHECK_TYPE_SIZE(shmid_ds); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); - -CHECK_TYPE_SIZE(clock_t); - -CHECK_TYPE_SIZE(ifaddrs); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); -// Compare against the union, because we can't reach into the union in a -// compliant way. -#ifdef ifa_dstaddr -#undef ifa_dstaddr -#endif -COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)nullptr)->ifa_dstaddr) == - sizeof(((ifaddrs *)nullptr)->ifa_ifu)); -COMPILER_CHECK(offsetof(__sanitizer_ifaddrs, ifa_dstaddr) == - offsetof(ifaddrs, ifa_ifu)); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); - -CHECK_TYPE_SIZE(timeb); -CHECK_SIZE_AND_OFFSET(timeb, time); -CHECK_SIZE_AND_OFFSET(timeb, millitm); -CHECK_SIZE_AND_OFFSET(timeb, timezone); -CHECK_SIZE_AND_OFFSET(timeb, dstflag); - -CHECK_TYPE_SIZE(passwd); -CHECK_SIZE_AND_OFFSET(passwd, pw_name); -CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); -CHECK_SIZE_AND_OFFSET(passwd, pw_uid); -CHECK_SIZE_AND_OFFSET(passwd, pw_gid); -CHECK_SIZE_AND_OFFSET(passwd, pw_dir); -CHECK_SIZE_AND_OFFSET(passwd, pw_shell); - -CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); - -CHECK_TYPE_SIZE(group); -CHECK_SIZE_AND_OFFSET(group, gr_name); -CHECK_SIZE_AND_OFFSET(group, gr_passwd); -CHECK_SIZE_AND_OFFSET(group, gr_gid); -CHECK_SIZE_AND_OFFSET(group, gr_mem); - -CHECK_TYPE_SIZE(XDR); -CHECK_SIZE_AND_OFFSET(XDR, x_op); -CHECK_SIZE_AND_OFFSET(XDR, x_ops); -CHECK_SIZE_AND_OFFSET(XDR, x_public); -CHECK_SIZE_AND_OFFSET(XDR, x_private); -CHECK_SIZE_AND_OFFSET(XDR, x_base); -CHECK_SIZE_AND_OFFSET(XDR, x_handy); -COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE); -COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); -COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); - -CHECK_TYPE_SIZE(sem_t); - -#endif // SANITIZER_SOLARIS diff --git a/lib/sanitizer_common/sanitizer_platform_limits_solaris.cpp b/lib/sanitizer_common/sanitizer_platform_limits_solaris.cpp new file mode 100644 index 000000000000..9717d98ebf1a --- /dev/null +++ b/lib/sanitizer_common/sanitizer_platform_limits_solaris.cpp @@ -0,0 +1,365 @@ +//===-- sanitizer_platform_limits_solaris.cpp -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer common code. +// +// Sizes and layouts of platform-specific Solaris data structures. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_SOLARIS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Include these after system headers to avoid name clashes and ambiguities. +#include "sanitizer_internal_defs.h" +#include "sanitizer_platform_limits_solaris.h" + +namespace __sanitizer { + unsigned struct_utsname_sz = sizeof(struct utsname); + unsigned struct_stat_sz = sizeof(struct stat); + unsigned struct_stat64_sz = sizeof(struct stat64); + unsigned struct_rusage_sz = sizeof(struct rusage); + unsigned struct_tm_sz = sizeof(struct tm); + unsigned struct_passwd_sz = sizeof(struct passwd); + unsigned struct_group_sz = sizeof(struct group); + unsigned siginfo_t_sz = sizeof(siginfo_t); + unsigned struct_sigaction_sz = sizeof(struct sigaction); + unsigned struct_itimerval_sz = sizeof(struct itimerval); + unsigned pthread_t_sz = sizeof(pthread_t); + unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); + unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); + unsigned pid_t_sz = sizeof(pid_t); + unsigned timeval_sz = sizeof(timeval); + unsigned uid_t_sz = sizeof(uid_t); + unsigned gid_t_sz = sizeof(gid_t); + unsigned mbstate_t_sz = sizeof(mbstate_t); + unsigned sigset_t_sz = sizeof(sigset_t); + unsigned struct_timezone_sz = sizeof(struct timezone); + unsigned struct_tms_sz = sizeof(struct tms); + unsigned struct_sigevent_sz = sizeof(struct sigevent); + unsigned struct_sched_param_sz = sizeof(struct sched_param); + unsigned struct_statfs_sz = sizeof(struct statfs); + unsigned struct_sockaddr_sz = sizeof(struct sockaddr); + unsigned ucontext_t_sz = sizeof(ucontext_t); + unsigned struct_timespec_sz = sizeof(struct timespec); +#if SANITIZER_SOLARIS32 + unsigned struct_statvfs64_sz = sizeof(struct statvfs64); +#endif + unsigned struct_statvfs_sz = sizeof(struct statvfs); + + const uptr sig_ign = (uptr)SIG_IGN; + const uptr sig_dfl = (uptr)SIG_DFL; + const uptr sig_err = (uptr)SIG_ERR; + const uptr sa_siginfo = (uptr)SA_SIGINFO; + + int shmctl_ipc_stat = (int)IPC_STAT; + + unsigned struct_utmp_sz = sizeof(struct utmp); + unsigned struct_utmpx_sz = sizeof(struct utmpx); + + int map_fixed = MAP_FIXED; + + int af_inet = (int)AF_INET; + int af_inet6 = (int)AF_INET6; + + uptr __sanitizer_in_addr_sz(int af) { + if (af == AF_INET) + return sizeof(struct in_addr); + else if (af == AF_INET6) + return sizeof(struct in6_addr); + else + return 0; + } + + unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr)); + + int glob_nomatch = GLOB_NOMATCH; + + unsigned path_max = PATH_MAX; + + // ioctl arguments + unsigned struct_ifreq_sz = sizeof(struct ifreq); + unsigned struct_termios_sz = sizeof(struct termios); + unsigned struct_winsize_sz = sizeof(struct winsize); + + unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); + unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); + + const unsigned IOCTL_NOT_PRESENT = 0; + + unsigned IOCTL_FIOASYNC = FIOASYNC; + unsigned IOCTL_FIOCLEX = FIOCLEX; + unsigned IOCTL_FIOGETOWN = FIOGETOWN; + unsigned IOCTL_FIONBIO = FIONBIO; + unsigned IOCTL_FIONCLEX = FIONCLEX; + unsigned IOCTL_FIOSETOWN = FIOSETOWN; + unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; + unsigned IOCTL_SIOCATMARK = SIOCATMARK; + unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; + unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; + unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; + unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; + unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; + unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; + unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; + unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; + unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; + unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; + unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; + unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; + unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; + unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; + unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; + unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; + unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; + unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; + unsigned IOCTL_TIOCEXCL = TIOCEXCL; + unsigned IOCTL_TIOCGETD = TIOCGETD; + unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; + unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; + unsigned IOCTL_TIOCMBIC = TIOCMBIC; + unsigned IOCTL_TIOCMBIS = TIOCMBIS; + unsigned IOCTL_TIOCMGET = TIOCMGET; + unsigned IOCTL_TIOCMSET = TIOCMSET; + unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; + unsigned IOCTL_TIOCNXCL = TIOCNXCL; + unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; + unsigned IOCTL_TIOCPKT = TIOCPKT; + unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; + unsigned IOCTL_TIOCSETD = TIOCSETD; + unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; + unsigned IOCTL_TIOCSTI = TIOCSTI; + unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; + + unsigned IOCTL_MTIOCGET = MTIOCGET; + unsigned IOCTL_MTIOCTOP = MTIOCTOP; + + const int si_SEGV_MAPERR = SEGV_MAPERR; + const int si_SEGV_ACCERR = SEGV_ACCERR; +} // namespace __sanitizer + +using namespace __sanitizer; + +COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); + +COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); +CHECK_TYPE_SIZE(pthread_key_t); + +// There are more undocumented fields in dl_phdr_info that we are not interested +// in. +COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); +CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); + +CHECK_TYPE_SIZE(glob_t); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); +CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); +CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); + +CHECK_TYPE_SIZE(addrinfo); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); +CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); + +CHECK_TYPE_SIZE(hostent); +CHECK_SIZE_AND_OFFSET(hostent, h_name); +CHECK_SIZE_AND_OFFSET(hostent, h_aliases); +CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); +CHECK_SIZE_AND_OFFSET(hostent, h_length); +CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); + +CHECK_TYPE_SIZE(iovec); +CHECK_SIZE_AND_OFFSET(iovec, iov_base); +CHECK_SIZE_AND_OFFSET(iovec, iov_len); + +CHECK_TYPE_SIZE(msghdr); +CHECK_SIZE_AND_OFFSET(msghdr, msg_name); +CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); +CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_control); +CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); +CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); + +CHECK_TYPE_SIZE(cmsghdr); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); +CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); + +COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); +CHECK_SIZE_AND_OFFSET(dirent, d_ino); +CHECK_SIZE_AND_OFFSET(dirent, d_off); +CHECK_SIZE_AND_OFFSET(dirent, d_reclen); + +#if SANITIZER_SOLARIS32 +COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64)); +CHECK_SIZE_AND_OFFSET(dirent64, d_ino); +CHECK_SIZE_AND_OFFSET(dirent64, d_off); +CHECK_SIZE_AND_OFFSET(dirent64, d_reclen); +#endif + +CHECK_TYPE_SIZE(ifconf); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); +CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); + +CHECK_TYPE_SIZE(pollfd); +CHECK_SIZE_AND_OFFSET(pollfd, fd); +CHECK_SIZE_AND_OFFSET(pollfd, events); +CHECK_SIZE_AND_OFFSET(pollfd, revents); + +CHECK_TYPE_SIZE(nfds_t); + +CHECK_TYPE_SIZE(sigset_t); + +COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); +// Can't write checks for sa_handler and sa_sigaction due to them being +// preprocessor macros. +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); +CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags); + +CHECK_TYPE_SIZE(wordexp_t); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); +CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); + +CHECK_TYPE_SIZE(tm); +CHECK_SIZE_AND_OFFSET(tm, tm_sec); +CHECK_SIZE_AND_OFFSET(tm, tm_min); +CHECK_SIZE_AND_OFFSET(tm, tm_hour); +CHECK_SIZE_AND_OFFSET(tm, tm_mday); +CHECK_SIZE_AND_OFFSET(tm, tm_mon); +CHECK_SIZE_AND_OFFSET(tm, tm_year); +CHECK_SIZE_AND_OFFSET(tm, tm_wday); +CHECK_SIZE_AND_OFFSET(tm, tm_yday); +CHECK_SIZE_AND_OFFSET(tm, tm_isdst); + +CHECK_TYPE_SIZE(ether_addr); + +CHECK_TYPE_SIZE(ipc_perm); +CHECK_SIZE_AND_OFFSET(ipc_perm, key); +CHECK_SIZE_AND_OFFSET(ipc_perm, seq); +CHECK_SIZE_AND_OFFSET(ipc_perm, uid); +CHECK_SIZE_AND_OFFSET(ipc_perm, gid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); +CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); +CHECK_SIZE_AND_OFFSET(ipc_perm, mode); + +CHECK_TYPE_SIZE(shmid_ds); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); +CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); + +CHECK_TYPE_SIZE(clock_t); + +CHECK_TYPE_SIZE(ifaddrs); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); +// Compare against the union, because we can't reach into the union in a +// compliant way. +#ifdef ifa_dstaddr +#undef ifa_dstaddr +#endif +COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)nullptr)->ifa_dstaddr) == + sizeof(((ifaddrs *)nullptr)->ifa_ifu)); +COMPILER_CHECK(offsetof(__sanitizer_ifaddrs, ifa_dstaddr) == + offsetof(ifaddrs, ifa_ifu)); +CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); + +CHECK_TYPE_SIZE(timeb); +CHECK_SIZE_AND_OFFSET(timeb, time); +CHECK_SIZE_AND_OFFSET(timeb, millitm); +CHECK_SIZE_AND_OFFSET(timeb, timezone); +CHECK_SIZE_AND_OFFSET(timeb, dstflag); + +CHECK_TYPE_SIZE(passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_name); +CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); +CHECK_SIZE_AND_OFFSET(passwd, pw_uid); +CHECK_SIZE_AND_OFFSET(passwd, pw_gid); +CHECK_SIZE_AND_OFFSET(passwd, pw_dir); +CHECK_SIZE_AND_OFFSET(passwd, pw_shell); + +CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); + +CHECK_TYPE_SIZE(group); +CHECK_SIZE_AND_OFFSET(group, gr_name); +CHECK_SIZE_AND_OFFSET(group, gr_passwd); +CHECK_SIZE_AND_OFFSET(group, gr_gid); +CHECK_SIZE_AND_OFFSET(group, gr_mem); + +CHECK_TYPE_SIZE(XDR); +CHECK_SIZE_AND_OFFSET(XDR, x_op); +CHECK_SIZE_AND_OFFSET(XDR, x_ops); +CHECK_SIZE_AND_OFFSET(XDR, x_public); +CHECK_SIZE_AND_OFFSET(XDR, x_private); +CHECK_SIZE_AND_OFFSET(XDR, x_base); +CHECK_SIZE_AND_OFFSET(XDR, x_handy); +COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE); +COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); +COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); + +CHECK_TYPE_SIZE(sem_t); + +#endif // SANITIZER_SOLARIS diff --git a/lib/sanitizer_common/sanitizer_platform_limits_solaris.h b/lib/sanitizer_common/sanitizer_platform_limits_solaris.h index eb5c5855b378..77ae6e6a44db 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_solaris.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_solaris.h @@ -68,7 +68,7 @@ struct __sanitizer_ipc_perm { #if !defined(_LP64) int pad[4]; #endif - }; +}; struct __sanitizer_shmid_ds { __sanitizer_ipc_perm shm_perm; @@ -236,10 +236,9 @@ typedef long __sanitizer_clock_t; typedef int __sanitizer_clockid_t; // This thing depends on the platform. We are only interested in the upper -// limit. Verified with a compiler assert in .cc. -const int pthread_attr_t_max_sz = 128; +// limit. Verified with a compiler assert in .cpp. union __sanitizer_pthread_attr_t { - char size[pthread_attr_t_max_sz]; // NOLINT + char size[128]; void *align; }; diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc deleted file mode 100644 index bf7127443c41..000000000000 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ /dev/null @@ -1,388 +0,0 @@ -//===-- sanitizer_posix.cc ------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries and implements POSIX-specific functions from -// sanitizer_posix.h. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_POSIX - -#include "sanitizer_common.h" -#include "sanitizer_file.h" -#include "sanitizer_flags.h" -#include "sanitizer_libc.h" -#include "sanitizer_posix.h" -#include "sanitizer_procmaps.h" - -#include -#include -#include -#include - -#if SANITIZER_FREEBSD -// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before -// that, it was never implemented. So just define it to zero. -#undef MAP_NORESERVE -#define MAP_NORESERVE 0 -#endif - -namespace __sanitizer { - -// ------------- sanitizer_common.h -uptr GetMmapGranularity() { - return GetPageSize(); -} - -void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { - size = RoundUpTo(size, GetPageSizeCached()); - uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, mem_type); - int reserrno; - if (UNLIKELY(internal_iserror(res, &reserrno))) - ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report); - IncreaseTotalMmap(size); - return (void *)res; -} - -void UnmapOrDie(void *addr, uptr size) { - if (!addr || !size) return; - uptr res = internal_munmap(addr, size); - if (UNLIKELY(internal_iserror(res))) { - Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", - SanitizerToolName, size, size, addr); - CHECK("unable to unmap" && 0); - } - DecreaseTotalMmap(size); -} - -void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { - size = RoundUpTo(size, GetPageSizeCached()); - uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, mem_type); - int reserrno; - if (UNLIKELY(internal_iserror(res, &reserrno))) { - if (reserrno == ENOMEM) - return nullptr; - ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); - } - IncreaseTotalMmap(size); - return (void *)res; -} - -// We want to map a chunk of address space aligned to 'alignment'. -// We do it by mapping a bit more and then unmapping redundant pieces. -// We probably can do it with fewer syscalls in some OS-dependent way. -void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, - const char *mem_type) { - CHECK(IsPowerOfTwo(size)); - CHECK(IsPowerOfTwo(alignment)); - uptr map_size = size + alignment; - uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type); - if (UNLIKELY(!map_res)) - return nullptr; - uptr map_end = map_res + map_size; - uptr res = map_res; - if (!IsAligned(res, alignment)) { - res = (map_res + alignment - 1) & ~(alignment - 1); - UnmapOrDie((void*)map_res, res - map_res); - } - uptr end = res + size; - if (end != map_end) - UnmapOrDie((void*)end, map_end - end); - return (void*)res; -} - -void *MmapNoReserveOrDie(uptr size, const char *mem_type) { - size = RoundUpTo(size, GetPageSizeCached()); - uptr p = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, mem_type); - int reserrno; - if (UNLIKELY(internal_iserror(p, &reserrno))) - ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno); - IncreaseTotalMmap(size); - return (void *)p; -} - -static void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem, - const char *name) { - size = RoundUpTo(size, GetPageSizeCached()); - fixed_addr = RoundDownTo(fixed_addr, GetPageSizeCached()); - uptr p = MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, name); - int reserrno; - if (UNLIKELY(internal_iserror(p, &reserrno))) { - if (tolerate_enomem && reserrno == ENOMEM) - return nullptr; - char mem_type[40]; - internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", - fixed_addr); - ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); - } - IncreaseTotalMmap(size); - return (void *)p; -} - -void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) { - return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/, name); -} - -void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) { - return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/, name); -} - -bool MprotectNoAccess(uptr addr, uptr size) { - return 0 == internal_mprotect((void*)addr, size, PROT_NONE); -} - -bool MprotectReadOnly(uptr addr, uptr size) { - return 0 == internal_mprotect((void *)addr, size, PROT_READ); -} - -#if !SANITIZER_MAC -void MprotectMallocZones(void *addr, int prot) {} -#endif - -fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) { - if (ShouldMockFailureToOpen(filename)) - return kInvalidFd; - int flags; - switch (mode) { - case RdOnly: flags = O_RDONLY; break; - case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break; - case RdWr: flags = O_RDWR | O_CREAT; break; - } - fd_t res = internal_open(filename, flags, 0660); - if (internal_iserror(res, errno_p)) - return kInvalidFd; - return ReserveStandardFds(res); -} - -void CloseFile(fd_t fd) { - internal_close(fd); -} - -bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, - error_t *error_p) { - uptr res = internal_read(fd, buff, buff_size); - if (internal_iserror(res, error_p)) - return false; - if (bytes_read) - *bytes_read = res; - return true; -} - -bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, - error_t *error_p) { - uptr res = internal_write(fd, buff, buff_size); - if (internal_iserror(res, error_p)) - return false; - if (bytes_written) - *bytes_written = res; - return true; -} - -void *MapFileToMemory(const char *file_name, uptr *buff_size) { - fd_t fd = OpenFile(file_name, RdOnly); - CHECK(fd != kInvalidFd); - uptr fsize = internal_filesize(fd); - CHECK_NE(fsize, (uptr)-1); - CHECK_GT(fsize, 0); - *buff_size = RoundUpTo(fsize, GetPageSizeCached()); - uptr map = internal_mmap(nullptr, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0); - return internal_iserror(map) ? nullptr : (void *)map; -} - -void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { - uptr flags = MAP_SHARED; - if (addr) flags |= MAP_FIXED; - uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset); - int mmap_errno = 0; - if (internal_iserror(p, &mmap_errno)) { - Printf("could not map writable file (%d, %lld, %zu): %zd, errno: %d\n", - fd, (long long)offset, size, p, mmap_errno); - return nullptr; - } - return (void *)p; -} - -static inline bool IntervalsAreSeparate(uptr start1, uptr end1, - uptr start2, uptr end2) { - CHECK(start1 <= end1); - CHECK(start2 <= end2); - return (end1 < start2) || (end2 < start1); -} - -// FIXME: this is thread-unsafe, but should not cause problems most of the time. -// When the shadow is mapped only a single thread usually exists (plus maybe -// several worker threads on Mac, which aren't expected to map big chunks of -// memory). -bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { - MemoryMappingLayout proc_maps(/*cache_enabled*/true); - if (proc_maps.Error()) - return true; // and hope for the best - MemoryMappedSegment segment; - while (proc_maps.Next(&segment)) { - if (segment.start == segment.end) continue; // Empty range. - CHECK_NE(0, segment.end); - if (!IntervalsAreSeparate(segment.start, segment.end - 1, range_start, - range_end)) - return false; - } - return true; -} - -void DumpProcessMap() { - MemoryMappingLayout proc_maps(/*cache_enabled*/true); - const sptr kBufSize = 4095; - char *filename = (char*)MmapOrDie(kBufSize, __func__); - MemoryMappedSegment segment(filename, kBufSize); - Report("Process memory map follows:\n"); - while (proc_maps.Next(&segment)) { - Printf("\t%p-%p\t%s\n", (void *)segment.start, (void *)segment.end, - segment.filename); - } - Report("End of process memory map.\n"); - UnmapOrDie(filename, kBufSize); -} - -const char *GetPwd() { - return GetEnv("PWD"); -} - -bool IsPathSeparator(const char c) { - return c == '/'; -} - -bool IsAbsolutePath(const char *path) { - return path != nullptr && IsPathSeparator(path[0]); -} - -void ReportFile::Write(const char *buffer, uptr length) { - SpinMutexLock l(mu); - ReopenIfNecessary(); - internal_write(fd, buffer, length); -} - -bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { - MemoryMappingLayout proc_maps(/*cache_enabled*/false); - InternalScopedString buff(kMaxPathLength); - MemoryMappedSegment segment(buff.data(), kMaxPathLength); - while (proc_maps.Next(&segment)) { - if (segment.IsExecutable() && - internal_strcmp(module, segment.filename) == 0) { - *start = segment.start; - *end = segment.end; - return true; - } - } - return false; -} - -uptr SignalContext::GetAddress() const { - auto si = static_cast(siginfo); - return (uptr)si->si_addr; -} - -bool SignalContext::IsMemoryAccess() const { - auto si = static_cast(siginfo); - return si->si_signo == SIGSEGV; -} - -int SignalContext::GetType() const { - return static_cast(siginfo)->si_signo; -} - -const char *SignalContext::Describe() const { - switch (GetType()) { - case SIGFPE: - return "FPE"; - case SIGILL: - return "ILL"; - case SIGABRT: - return "ABRT"; - case SIGSEGV: - return "SEGV"; - case SIGBUS: - return "BUS"; - } - return "UNKNOWN SIGNAL"; -} - -fd_t ReserveStandardFds(fd_t fd) { - CHECK_GE(fd, 0); - if (fd > 2) - return fd; - bool used[3]; - internal_memset(used, 0, sizeof(used)); - while (fd <= 2) { - used[fd] = true; - fd = internal_dup(fd); - } - for (int i = 0; i <= 2; ++i) - if (used[i]) - internal_close(i); - return fd; -} - -bool ShouldMockFailureToOpen(const char *path) { - return common_flags()->test_only_emulate_no_memorymap && - internal_strncmp(path, "/proc/", 6) == 0; -} - -#if SANITIZER_LINUX && !SANITIZER_ANDROID && !SANITIZER_GO -int GetNamedMappingFd(const char *name, uptr size, int *flags) { - if (!common_flags()->decorate_proc_maps || !name) - return -1; - char shmname[200]; - CHECK(internal_strlen(name) < sizeof(shmname) - 10); - internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]", - internal_getpid(), name); - int fd = ReserveStandardFds( - internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRWXU)); - CHECK_GE(fd, 0); - int res = internal_ftruncate(fd, size); - CHECK_EQ(0, res); - res = internal_unlink(shmname); - CHECK_EQ(0, res); - *flags &= ~(MAP_ANON | MAP_ANONYMOUS); - return fd; -} -#else -int GetNamedMappingFd(const char *name, uptr size, int *flags) { - return -1; -} -#endif - -#if SANITIZER_ANDROID -#define PR_SET_VMA 0x53564d41 -#define PR_SET_VMA_ANON_NAME 0 -void DecorateMapping(uptr addr, uptr size, const char *name) { - if (!common_flags()->decorate_proc_maps || !name) - return; - internal_prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, (uptr)name); -} -#else -void DecorateMapping(uptr addr, uptr size, const char *name) { -} -#endif - -uptr MmapNamed(void *addr, uptr length, int prot, int flags, const char *name) { - int fd = GetNamedMappingFd(name, length, &flags); - uptr res = internal_mmap(addr, length, prot, flags, fd, 0); - if (!internal_iserror(res)) - DecorateMapping(res, length, name); - return res; -} - - -} // namespace __sanitizer - -#endif // SANITIZER_POSIX diff --git a/lib/sanitizer_common/sanitizer_posix.cpp b/lib/sanitizer_common/sanitizer_posix.cpp new file mode 100644 index 000000000000..d890a3a31773 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_posix.cpp @@ -0,0 +1,390 @@ +//===-- sanitizer_posix.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries and implements POSIX-specific functions from +// sanitizer_posix.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_POSIX + +#include "sanitizer_common.h" +#include "sanitizer_file.h" +#include "sanitizer_flags.h" +#include "sanitizer_libc.h" +#include "sanitizer_posix.h" +#include "sanitizer_procmaps.h" + +#include +#include +#include +#include + +#if SANITIZER_FREEBSD +// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before +// that, it was never implemented. So just define it to zero. +#undef MAP_NORESERVE +#define MAP_NORESERVE 0 +#endif + +namespace __sanitizer { + +// ------------- sanitizer_common.h +uptr GetMmapGranularity() { + return GetPageSize(); +} + +void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { + size = RoundUpTo(size, GetPageSizeCached()); + uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, mem_type); + int reserrno; + if (UNLIKELY(internal_iserror(res, &reserrno))) + ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report); + IncreaseTotalMmap(size); + return (void *)res; +} + +void UnmapOrDie(void *addr, uptr size) { + if (!addr || !size) return; + uptr res = internal_munmap(addr, size); + if (UNLIKELY(internal_iserror(res))) { + Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", + SanitizerToolName, size, size, addr); + CHECK("unable to unmap" && 0); + } + DecreaseTotalMmap(size); +} + +void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { + size = RoundUpTo(size, GetPageSizeCached()); + uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, mem_type); + int reserrno; + if (UNLIKELY(internal_iserror(res, &reserrno))) { + if (reserrno == ENOMEM) + return nullptr; + ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); + } + IncreaseTotalMmap(size); + return (void *)res; +} + +// We want to map a chunk of address space aligned to 'alignment'. +// We do it by mapping a bit more and then unmapping redundant pieces. +// We probably can do it with fewer syscalls in some OS-dependent way. +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type) { + CHECK(IsPowerOfTwo(size)); + CHECK(IsPowerOfTwo(alignment)); + uptr map_size = size + alignment; + uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type); + if (UNLIKELY(!map_res)) + return nullptr; + uptr map_end = map_res + map_size; + uptr res = map_res; + if (!IsAligned(res, alignment)) { + res = (map_res + alignment - 1) & ~(alignment - 1); + UnmapOrDie((void*)map_res, res - map_res); + } + uptr end = res + size; + if (end != map_end) + UnmapOrDie((void*)end, map_end - end); + return (void*)res; +} + +void *MmapNoReserveOrDie(uptr size, const char *mem_type) { + size = RoundUpTo(size, GetPageSizeCached()); + uptr p = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, mem_type); + int reserrno; + if (UNLIKELY(internal_iserror(p, &reserrno))) + ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno); + IncreaseTotalMmap(size); + return (void *)p; +} + +static void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem, + const char *name) { + size = RoundUpTo(size, GetPageSizeCached()); + fixed_addr = RoundDownTo(fixed_addr, GetPageSizeCached()); + uptr p = MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, name); + int reserrno; + if (UNLIKELY(internal_iserror(p, &reserrno))) { + if (tolerate_enomem && reserrno == ENOMEM) + return nullptr; + char mem_type[40]; + internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", + fixed_addr); + ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); + } + IncreaseTotalMmap(size); + return (void *)p; +} + +void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) { + return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/, name); +} + +void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) { + return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/, name); +} + +bool MprotectNoAccess(uptr addr, uptr size) { + return 0 == internal_mprotect((void*)addr, size, PROT_NONE); +} + +bool MprotectReadOnly(uptr addr, uptr size) { + return 0 == internal_mprotect((void *)addr, size, PROT_READ); +} + +#if !SANITIZER_MAC +void MprotectMallocZones(void *addr, int prot) {} +#endif + +fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) { + if (ShouldMockFailureToOpen(filename)) + return kInvalidFd; + int flags; + switch (mode) { + case RdOnly: flags = O_RDONLY; break; + case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break; + case RdWr: flags = O_RDWR | O_CREAT; break; + } + fd_t res = internal_open(filename, flags, 0660); + if (internal_iserror(res, errno_p)) + return kInvalidFd; + return ReserveStandardFds(res); +} + +void CloseFile(fd_t fd) { + internal_close(fd); +} + +bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, + error_t *error_p) { + uptr res = internal_read(fd, buff, buff_size); + if (internal_iserror(res, error_p)) + return false; + if (bytes_read) + *bytes_read = res; + return true; +} + +bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, + error_t *error_p) { + uptr res = internal_write(fd, buff, buff_size); + if (internal_iserror(res, error_p)) + return false; + if (bytes_written) + *bytes_written = res; + return true; +} + +void *MapFileToMemory(const char *file_name, uptr *buff_size) { + fd_t fd = OpenFile(file_name, RdOnly); + CHECK(fd != kInvalidFd); + uptr fsize = internal_filesize(fd); + CHECK_NE(fsize, (uptr)-1); + CHECK_GT(fsize, 0); + *buff_size = RoundUpTo(fsize, GetPageSizeCached()); + uptr map = internal_mmap(nullptr, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0); + return internal_iserror(map) ? nullptr : (void *)map; +} + +void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { + uptr flags = MAP_SHARED; + if (addr) flags |= MAP_FIXED; + uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset); + int mmap_errno = 0; + if (internal_iserror(p, &mmap_errno)) { + Printf("could not map writable file (%d, %lld, %zu): %zd, errno: %d\n", + fd, (long long)offset, size, p, mmap_errno); + return nullptr; + } + return (void *)p; +} + +static inline bool IntervalsAreSeparate(uptr start1, uptr end1, + uptr start2, uptr end2) { + CHECK(start1 <= end1); + CHECK(start2 <= end2); + return (end1 < start2) || (end2 < start1); +} + +// FIXME: this is thread-unsafe, but should not cause problems most of the time. +// When the shadow is mapped only a single thread usually exists (plus maybe +// several worker threads on Mac, which aren't expected to map big chunks of +// memory). +bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { + MemoryMappingLayout proc_maps(/*cache_enabled*/true); + if (proc_maps.Error()) + return true; // and hope for the best + MemoryMappedSegment segment; + while (proc_maps.Next(&segment)) { + if (segment.start == segment.end) continue; // Empty range. + CHECK_NE(0, segment.end); + if (!IntervalsAreSeparate(segment.start, segment.end - 1, range_start, + range_end)) + return false; + } + return true; +} + +void DumpProcessMap() { + MemoryMappingLayout proc_maps(/*cache_enabled*/true); + const sptr kBufSize = 4095; + char *filename = (char*)MmapOrDie(kBufSize, __func__); + MemoryMappedSegment segment(filename, kBufSize); + Report("Process memory map follows:\n"); + while (proc_maps.Next(&segment)) { + Printf("\t%p-%p\t%s\n", (void *)segment.start, (void *)segment.end, + segment.filename); + } + Report("End of process memory map.\n"); + UnmapOrDie(filename, kBufSize); +} + +const char *GetPwd() { + return GetEnv("PWD"); +} + +bool IsPathSeparator(const char c) { + return c == '/'; +} + +bool IsAbsolutePath(const char *path) { + return path != nullptr && IsPathSeparator(path[0]); +} + +void ReportFile::Write(const char *buffer, uptr length) { + SpinMutexLock l(mu); + ReopenIfNecessary(); + internal_write(fd, buffer, length); +} + +bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { + MemoryMappingLayout proc_maps(/*cache_enabled*/false); + InternalScopedString buff(kMaxPathLength); + MemoryMappedSegment segment(buff.data(), kMaxPathLength); + while (proc_maps.Next(&segment)) { + if (segment.IsExecutable() && + internal_strcmp(module, segment.filename) == 0) { + *start = segment.start; + *end = segment.end; + return true; + } + } + return false; +} + +uptr SignalContext::GetAddress() const { + auto si = static_cast(siginfo); + return (uptr)si->si_addr; +} + +bool SignalContext::IsMemoryAccess() const { + auto si = static_cast(siginfo); + return si->si_signo == SIGSEGV; +} + +int SignalContext::GetType() const { + return static_cast(siginfo)->si_signo; +} + +const char *SignalContext::Describe() const { + switch (GetType()) { + case SIGFPE: + return "FPE"; + case SIGILL: + return "ILL"; + case SIGABRT: + return "ABRT"; + case SIGSEGV: + return "SEGV"; + case SIGBUS: + return "BUS"; + case SIGTRAP: + return "TRAP"; + } + return "UNKNOWN SIGNAL"; +} + +fd_t ReserveStandardFds(fd_t fd) { + CHECK_GE(fd, 0); + if (fd > 2) + return fd; + bool used[3]; + internal_memset(used, 0, sizeof(used)); + while (fd <= 2) { + used[fd] = true; + fd = internal_dup(fd); + } + for (int i = 0; i <= 2; ++i) + if (used[i]) + internal_close(i); + return fd; +} + +bool ShouldMockFailureToOpen(const char *path) { + return common_flags()->test_only_emulate_no_memorymap && + internal_strncmp(path, "/proc/", 6) == 0; +} + +#if SANITIZER_LINUX && !SANITIZER_ANDROID && !SANITIZER_GO +int GetNamedMappingFd(const char *name, uptr size, int *flags) { + if (!common_flags()->decorate_proc_maps || !name) + return -1; + char shmname[200]; + CHECK(internal_strlen(name) < sizeof(shmname) - 10); + internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]", + internal_getpid(), name); + int fd = ReserveStandardFds( + internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRWXU)); + CHECK_GE(fd, 0); + int res = internal_ftruncate(fd, size); + CHECK_EQ(0, res); + res = internal_unlink(shmname); + CHECK_EQ(0, res); + *flags &= ~(MAP_ANON | MAP_ANONYMOUS); + return fd; +} +#else +int GetNamedMappingFd(const char *name, uptr size, int *flags) { + return -1; +} +#endif + +#if SANITIZER_ANDROID +#define PR_SET_VMA 0x53564d41 +#define PR_SET_VMA_ANON_NAME 0 +void DecorateMapping(uptr addr, uptr size, const char *name) { + if (!common_flags()->decorate_proc_maps || !name) + return; + internal_prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, (uptr)name); +} +#else +void DecorateMapping(uptr addr, uptr size, const char *name) { +} +#endif + +uptr MmapNamed(void *addr, uptr length, int prot, int flags, const char *name) { + int fd = GetNamedMappingFd(name, length, &flags); + uptr res = internal_mmap(addr, length, prot, flags, fd, 0); + if (!internal_iserror(res)) + DecorateMapping(res, length, name); + return res; +} + + +} // namespace __sanitizer + +#endif // SANITIZER_POSIX diff --git a/lib/sanitizer_common/sanitizer_posix.h b/lib/sanitizer_common/sanitizer_posix.h index 6cf5ce75b12e..05fb0f630207 100644 --- a/lib/sanitizer_common/sanitizer_posix.h +++ b/lib/sanitizer_common/sanitizer_posix.h @@ -63,7 +63,7 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data); uptr internal_waitpid(int pid, int *status, int options); int internal_fork(); -int internal_forkpty(int *amaster); +fd_t internal_spawn(const char *argv[], pid_t *pid); int internal_sysctl(const int *name, unsigned int namelen, void *oldp, uptr *oldlenp, const void *newp, uptr newlen); diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc deleted file mode 100644 index 23a2f84ac887..000000000000 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ /dev/null @@ -1,486 +0,0 @@ -//===-- sanitizer_posix_libcdep.cc ----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries and implements libc-dependent POSIX-specific functions -// from sanitizer_libc.h. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_POSIX - -#include "sanitizer_common.h" -#include "sanitizer_flags.h" -#include "sanitizer_platform_limits_netbsd.h" -#include "sanitizer_platform_limits_openbsd.h" -#include "sanitizer_platform_limits_posix.h" -#include "sanitizer_platform_limits_solaris.h" -#include "sanitizer_posix.h" -#include "sanitizer_procmaps.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if SANITIZER_FREEBSD -// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before -// that, it was never implemented. So just define it to zero. -#undef MAP_NORESERVE -#define MAP_NORESERVE 0 -#endif - -typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); - -namespace __sanitizer { - -u32 GetUid() { - return getuid(); -} - -uptr GetThreadSelf() { - return (uptr)pthread_self(); -} - -void ReleaseMemoryPagesToOS(uptr beg, uptr end) { - uptr page_size = GetPageSizeCached(); - uptr beg_aligned = RoundUpTo(beg, page_size); - uptr end_aligned = RoundDownTo(end, page_size); - if (beg_aligned < end_aligned) - // In the default Solaris compilation environment, madvise() is declared - // to take a caddr_t arg; casting it to void * results in an invalid - // conversion error, so use char * instead. - madvise((char *)beg_aligned, end_aligned - beg_aligned, - SANITIZER_MADVISE_DONTNEED); -} - -bool NoHugePagesInRegion(uptr addr, uptr size) { -#ifdef MADV_NOHUGEPAGE // May not be defined on old systems. - return madvise((char *)addr, size, MADV_NOHUGEPAGE) == 0; -#else - return true; -#endif // MADV_NOHUGEPAGE -} - -bool DontDumpShadowMemory(uptr addr, uptr length) { -#if defined(MADV_DONTDUMP) - return madvise((char *)addr, length, MADV_DONTDUMP) == 0; -#elif defined(MADV_NOCORE) - return madvise((char *)addr, length, MADV_NOCORE) == 0; -#else - return true; -#endif // MADV_DONTDUMP -} - -static rlim_t getlim(int res) { - rlimit rlim; - CHECK_EQ(0, getrlimit(res, &rlim)); - return rlim.rlim_cur; -} - -static void setlim(int res, rlim_t lim) { - struct rlimit rlim; - if (getrlimit(res, const_cast(&rlim))) { - Report("ERROR: %s getrlimit() failed %d\n", SanitizerToolName, errno); - Die(); - } - rlim.rlim_cur = lim; - if (setrlimit(res, const_cast(&rlim))) { - Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno); - Die(); - } -} - -void DisableCoreDumperIfNecessary() { - if (common_flags()->disable_coredump) { - setlim(RLIMIT_CORE, 0); - } -} - -bool StackSizeIsUnlimited() { - rlim_t stack_size = getlim(RLIMIT_STACK); - return (stack_size == RLIM_INFINITY); -} - -void SetStackSizeLimitInBytes(uptr limit) { - setlim(RLIMIT_STACK, (rlim_t)limit); - CHECK(!StackSizeIsUnlimited()); -} - -bool AddressSpaceIsUnlimited() { - rlim_t as_size = getlim(RLIMIT_AS); - return (as_size == RLIM_INFINITY); -} - -void SetAddressSpaceUnlimited() { - setlim(RLIMIT_AS, RLIM_INFINITY); - CHECK(AddressSpaceIsUnlimited()); -} - -void SleepForSeconds(int seconds) { - sleep(seconds); -} - -void SleepForMillis(int millis) { - usleep(millis * 1000); -} - -void Abort() { -#if !SANITIZER_GO - // If we are handling SIGABRT, unhandle it first. - // TODO(vitalybuka): Check if handler belongs to sanitizer. - if (GetHandleSignalMode(SIGABRT) != kHandleSignalNo) { - struct sigaction sigact; - internal_memset(&sigact, 0, sizeof(sigact)); - sigact.sa_sigaction = (sa_sigaction_t)SIG_DFL; - internal_sigaction(SIGABRT, &sigact, nullptr); - } -#endif - - abort(); -} - -int Atexit(void (*function)(void)) { -#if !SANITIZER_GO - return atexit(function); -#else - return 0; -#endif -} - -bool SupportsColoredOutput(fd_t fd) { - return isatty(fd) != 0; -} - -#if !SANITIZER_GO -// TODO(glider): different tools may require different altstack size. -static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough. - -void SetAlternateSignalStack() { - stack_t altstack, oldstack; - CHECK_EQ(0, sigaltstack(nullptr, &oldstack)); - // If the alternate stack is already in place, do nothing. - // Android always sets an alternate stack, but it's too small for us. - if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE)) return; - // TODO(glider): the mapped stack should have the MAP_STACK flag in the - // future. It is not required by man 2 sigaltstack now (they're using - // malloc()). - void* base = MmapOrDie(kAltStackSize, __func__); - altstack.ss_sp = (char*) base; - altstack.ss_flags = 0; - altstack.ss_size = kAltStackSize; - CHECK_EQ(0, sigaltstack(&altstack, nullptr)); -} - -void UnsetAlternateSignalStack() { - stack_t altstack, oldstack; - altstack.ss_sp = nullptr; - altstack.ss_flags = SS_DISABLE; - altstack.ss_size = kAltStackSize; // Some sane value required on Darwin. - CHECK_EQ(0, sigaltstack(&altstack, &oldstack)); - UnmapOrDie(oldstack.ss_sp, oldstack.ss_size); -} - -static void MaybeInstallSigaction(int signum, - SignalHandlerType handler) { - if (GetHandleSignalMode(signum) == kHandleSignalNo) return; - - struct sigaction sigact; - internal_memset(&sigact, 0, sizeof(sigact)); - sigact.sa_sigaction = (sa_sigaction_t)handler; - // Do not block the signal from being received in that signal's handler. - // Clients are responsible for handling this correctly. - sigact.sa_flags = SA_SIGINFO | SA_NODEFER; - if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; - CHECK_EQ(0, internal_sigaction(signum, &sigact, nullptr)); - VReport(1, "Installed the sigaction for signal %d\n", signum); -} - -void InstallDeadlySignalHandlers(SignalHandlerType handler) { - // Set the alternate signal stack for the main thread. - // This will cause SetAlternateSignalStack to be called twice, but the stack - // will be actually set only once. - if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); - MaybeInstallSigaction(SIGSEGV, handler); - MaybeInstallSigaction(SIGBUS, handler); - MaybeInstallSigaction(SIGABRT, handler); - MaybeInstallSigaction(SIGFPE, handler); - MaybeInstallSigaction(SIGILL, handler); - MaybeInstallSigaction(SIGTRAP, handler); -} - -bool SignalContext::IsStackOverflow() const { - // Access at a reasonable offset above SP, or slightly below it (to account - // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is - // probably a stack overflow. -#ifdef __s390__ - // On s390, the fault address in siginfo points to start of the page, not - // to the precise word that was accessed. Mask off the low bits of sp to - // take it into account. - bool IsStackAccess = addr >= (sp & ~0xFFF) && addr < sp + 0xFFFF; -#else - // Let's accept up to a page size away from top of stack. Things like stack - // probing can trigger accesses with such large offsets. - bool IsStackAccess = addr + GetPageSizeCached() > sp && addr < sp + 0xFFFF; -#endif - -#if __powerpc__ - // Large stack frames can be allocated with e.g. - // lis r0,-10000 - // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000 - // If the store faults then sp will not have been updated, so test above - // will not work, because the fault address will be more than just "slightly" - // below sp. - if (!IsStackAccess && IsAccessibleMemoryRange(pc, 4)) { - u32 inst = *(unsigned *)pc; - u32 ra = (inst >> 16) & 0x1F; - u32 opcd = inst >> 26; - u32 xo = (inst >> 1) & 0x3FF; - // Check for store-with-update to sp. The instructions we accept are: - // stbu rs,d(ra) stbux rs,ra,rb - // sthu rs,d(ra) sthux rs,ra,rb - // stwu rs,d(ra) stwux rs,ra,rb - // stdu rs,ds(ra) stdux rs,ra,rb - // where ra is r1 (the stack pointer). - if (ra == 1 && - (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 || - (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181)))) - IsStackAccess = true; - } -#endif // __powerpc__ - - // We also check si_code to filter out SEGV caused by something else other - // then hitting the guard page or unmapped memory, like, for example, - // unaligned memory access. - auto si = static_cast(siginfo); - return IsStackAccess && - (si->si_code == si_SEGV_MAPERR || si->si_code == si_SEGV_ACCERR); -} - -#endif // SANITIZER_GO - -bool IsAccessibleMemoryRange(uptr beg, uptr size) { - uptr page_size = GetPageSizeCached(); - // Checking too large memory ranges is slow. - CHECK_LT(size, page_size * 10); - int sock_pair[2]; - if (pipe(sock_pair)) - return false; - uptr bytes_written = - internal_write(sock_pair[1], reinterpret_cast(beg), size); - int write_errno; - bool result; - if (internal_iserror(bytes_written, &write_errno)) { - CHECK_EQ(EFAULT, write_errno); - result = false; - } else { - result = (bytes_written == size); - } - internal_close(sock_pair[0]); - internal_close(sock_pair[1]); - return result; -} - -void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { - // Some kinds of sandboxes may forbid filesystem access, so we won't be able - // to read the file mappings from /proc/self/maps. Luckily, neither the - // process will be able to load additional libraries, so it's fine to use the - // cached mappings. - MemoryMappingLayout::CacheMemoryMappings(); -} - -bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { - size = RoundUpTo(size, GetPageSizeCached()); - fixed_addr = RoundDownTo(fixed_addr, GetPageSizeCached()); - uptr p = MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE | MAP_ANON, name); - int reserrno; - if (internal_iserror(p, &reserrno)) { - Report("ERROR: %s failed to " - "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n", - SanitizerToolName, size, size, fixed_addr, reserrno); - return false; - } - IncreaseTotalMmap(size); - return true; -} - -uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { - base_ = fixed_addr ? MmapFixedNoAccess(fixed_addr, size, name) - : MmapNoAccess(size); - size_ = size; - name_ = name; - (void)os_handle_; // unsupported - return reinterpret_cast(base_); -} - -// Uses fixed_addr for now. -// Will use offset instead once we've implemented this function for real. -uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, const char *name) { - return reinterpret_cast( - MmapFixedOrDieOnFatalError(fixed_addr, size, name)); -} - -uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size, - const char *name) { - return reinterpret_cast(MmapFixedOrDie(fixed_addr, size, name)); -} - -void ReservedAddressRange::Unmap(uptr addr, uptr size) { - CHECK_LE(size, size_); - if (addr == reinterpret_cast(base_)) - // If we unmap the whole range, just null out the base. - base_ = (size == size_) ? nullptr : reinterpret_cast(addr + size); - else - CHECK_EQ(addr + size, reinterpret_cast(base_) + size_); - size_ -= size; - UnmapOrDie(reinterpret_cast(addr), size); -} - -void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { - return (void *)MmapNamed((void *)fixed_addr, size, PROT_NONE, - MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE | MAP_ANON, - name); -} - -void *MmapNoAccess(uptr size) { - unsigned flags = MAP_PRIVATE | MAP_ANON | MAP_NORESERVE; - return (void *)internal_mmap(nullptr, size, PROT_NONE, flags, -1, 0); -} - -// This function is defined elsewhere if we intercepted pthread_attr_getstack. -extern "C" { -SANITIZER_WEAK_ATTRIBUTE int -real_pthread_attr_getstack(void *attr, void **addr, size_t *size); -} // extern "C" - -int my_pthread_attr_getstack(void *attr, void **addr, uptr *size) { -#if !SANITIZER_GO && !SANITIZER_MAC - if (&real_pthread_attr_getstack) - return real_pthread_attr_getstack((pthread_attr_t *)attr, addr, - (size_t *)size); -#endif - return pthread_attr_getstack((pthread_attr_t *)attr, addr, (size_t *)size); -} - -#if !SANITIZER_GO -void AdjustStackSize(void *attr_) { - pthread_attr_t *attr = (pthread_attr_t *)attr_; - uptr stackaddr = 0; - uptr stacksize = 0; - my_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize); - // GLibC will return (0 - stacksize) as the stack address in the case when - // stacksize is set, but stackaddr is not. - bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0); - // We place a lot of tool data into TLS, account for that. - const uptr minstacksize = GetTlsSize() + 128*1024; - if (stacksize < minstacksize) { - if (!stack_set) { - if (stacksize != 0) { - VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize, - minstacksize); - pthread_attr_setstacksize(attr, minstacksize); - } - } else { - Printf("Sanitizer: pre-allocated stack size is insufficient: " - "%zu < %zu\n", stacksize, minstacksize); - Printf("Sanitizer: pthread_create is likely to fail.\n"); - } - } -} -#endif // !SANITIZER_GO - -pid_t StartSubprocess(const char *program, const char *const argv[], - fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { - auto file_closer = at_scope_exit([&] { - if (stdin_fd != kInvalidFd) { - internal_close(stdin_fd); - } - if (stdout_fd != kInvalidFd) { - internal_close(stdout_fd); - } - if (stderr_fd != kInvalidFd) { - internal_close(stderr_fd); - } - }); - - int pid = internal_fork(); - - if (pid < 0) { - int rverrno; - if (internal_iserror(pid, &rverrno)) { - Report("WARNING: failed to fork (errno %d)\n", rverrno); - } - return pid; - } - - if (pid == 0) { - // Child subprocess - if (stdin_fd != kInvalidFd) { - internal_close(STDIN_FILENO); - internal_dup2(stdin_fd, STDIN_FILENO); - internal_close(stdin_fd); - } - if (stdout_fd != kInvalidFd) { - internal_close(STDOUT_FILENO); - internal_dup2(stdout_fd, STDOUT_FILENO); - internal_close(stdout_fd); - } - if (stderr_fd != kInvalidFd) { - internal_close(STDERR_FILENO); - internal_dup2(stderr_fd, STDERR_FILENO); - internal_close(stderr_fd); - } - - for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd); - - execv(program, const_cast(&argv[0])); - internal__exit(1); - } - - return pid; -} - -bool IsProcessRunning(pid_t pid) { - int process_status; - uptr waitpid_status = internal_waitpid(pid, &process_status, WNOHANG); - int local_errno; - if (internal_iserror(waitpid_status, &local_errno)) { - VReport(1, "Waiting on the process failed (errno %d).\n", local_errno); - return false; - } - return waitpid_status == 0; -} - -int WaitForProcess(pid_t pid) { - int process_status; - uptr waitpid_status = internal_waitpid(pid, &process_status, 0); - int local_errno; - if (internal_iserror(waitpid_status, &local_errno)) { - VReport(1, "Waiting on the process failed (errno %d).\n", local_errno); - return -1; - } - return process_status; -} - -bool IsStateDetached(int state) { - return state == PTHREAD_CREATE_DETACHED; -} - -} // namespace __sanitizer - -#endif // SANITIZER_POSIX diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/lib/sanitizer_common/sanitizer_posix_libcdep.cpp new file mode 100644 index 000000000000..304b3a01a08b --- /dev/null +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -0,0 +1,507 @@ +//===-- sanitizer_posix_libcdep.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries and implements libc-dependent POSIX-specific functions +// from sanitizer_libc.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_POSIX + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_platform_limits_netbsd.h" +#include "sanitizer_platform_limits_openbsd.h" +#include "sanitizer_platform_limits_posix.h" +#include "sanitizer_platform_limits_solaris.h" +#include "sanitizer_posix.h" +#include "sanitizer_procmaps.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if SANITIZER_FREEBSD +// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before +// that, it was never implemented. So just define it to zero. +#undef MAP_NORESERVE +#define MAP_NORESERVE 0 +#endif + +typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); + +namespace __sanitizer { + +u32 GetUid() { + return getuid(); +} + +uptr GetThreadSelf() { + return (uptr)pthread_self(); +} + +void ReleaseMemoryPagesToOS(uptr beg, uptr end) { + uptr page_size = GetPageSizeCached(); + uptr beg_aligned = RoundUpTo(beg, page_size); + uptr end_aligned = RoundDownTo(end, page_size); + if (beg_aligned < end_aligned) + // In the default Solaris compilation environment, madvise() is declared + // to take a caddr_t arg; casting it to void * results in an invalid + // conversion error, so use char * instead. + madvise((char *)beg_aligned, end_aligned - beg_aligned, + SANITIZER_MADVISE_DONTNEED); +} + +void SetShadowRegionHugePageMode(uptr addr, uptr size) { +#ifdef MADV_NOHUGEPAGE // May not be defined on old systems. + if (common_flags()->no_huge_pages_for_shadow) + madvise((char *)addr, size, MADV_NOHUGEPAGE); + else + madvise((char *)addr, size, MADV_HUGEPAGE); +#endif // MADV_NOHUGEPAGE +} + +bool DontDumpShadowMemory(uptr addr, uptr length) { +#if defined(MADV_DONTDUMP) + return madvise((char *)addr, length, MADV_DONTDUMP) == 0; +#elif defined(MADV_NOCORE) + return madvise((char *)addr, length, MADV_NOCORE) == 0; +#else + return true; +#endif // MADV_DONTDUMP +} + +static rlim_t getlim(int res) { + rlimit rlim; + CHECK_EQ(0, getrlimit(res, &rlim)); + return rlim.rlim_cur; +} + +static void setlim(int res, rlim_t lim) { + struct rlimit rlim; + if (getrlimit(res, const_cast(&rlim))) { + Report("ERROR: %s getrlimit() failed %d\n", SanitizerToolName, errno); + Die(); + } + rlim.rlim_cur = lim; + if (setrlimit(res, const_cast(&rlim))) { + Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno); + Die(); + } +} + +void DisableCoreDumperIfNecessary() { + if (common_flags()->disable_coredump) { + setlim(RLIMIT_CORE, 0); + } +} + +bool StackSizeIsUnlimited() { + rlim_t stack_size = getlim(RLIMIT_STACK); + return (stack_size == RLIM_INFINITY); +} + +void SetStackSizeLimitInBytes(uptr limit) { + setlim(RLIMIT_STACK, (rlim_t)limit); + CHECK(!StackSizeIsUnlimited()); +} + +bool AddressSpaceIsUnlimited() { + rlim_t as_size = getlim(RLIMIT_AS); + return (as_size == RLIM_INFINITY); +} + +void SetAddressSpaceUnlimited() { + setlim(RLIMIT_AS, RLIM_INFINITY); + CHECK(AddressSpaceIsUnlimited()); +} + +void SleepForSeconds(int seconds) { + sleep(seconds); +} + +void SleepForMillis(int millis) { + usleep(millis * 1000); +} + +void Abort() { +#if !SANITIZER_GO + // If we are handling SIGABRT, unhandle it first. + // TODO(vitalybuka): Check if handler belongs to sanitizer. + if (GetHandleSignalMode(SIGABRT) != kHandleSignalNo) { + struct sigaction sigact; + internal_memset(&sigact, 0, sizeof(sigact)); + sigact.sa_sigaction = (sa_sigaction_t)SIG_DFL; + internal_sigaction(SIGABRT, &sigact, nullptr); + } +#endif + + abort(); +} + +int Atexit(void (*function)(void)) { +#if !SANITIZER_GO + return atexit(function); +#else + return 0; +#endif +} + +bool SupportsColoredOutput(fd_t fd) { + return isatty(fd) != 0; +} + +#if !SANITIZER_GO +// TODO(glider): different tools may require different altstack size. +static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough. + +void SetAlternateSignalStack() { + stack_t altstack, oldstack; + CHECK_EQ(0, sigaltstack(nullptr, &oldstack)); + // If the alternate stack is already in place, do nothing. + // Android always sets an alternate stack, but it's too small for us. + if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE)) return; + // TODO(glider): the mapped stack should have the MAP_STACK flag in the + // future. It is not required by man 2 sigaltstack now (they're using + // malloc()). + void* base = MmapOrDie(kAltStackSize, __func__); + altstack.ss_sp = (char*) base; + altstack.ss_flags = 0; + altstack.ss_size = kAltStackSize; + CHECK_EQ(0, sigaltstack(&altstack, nullptr)); +} + +void UnsetAlternateSignalStack() { + stack_t altstack, oldstack; + altstack.ss_sp = nullptr; + altstack.ss_flags = SS_DISABLE; + altstack.ss_size = kAltStackSize; // Some sane value required on Darwin. + CHECK_EQ(0, sigaltstack(&altstack, &oldstack)); + UnmapOrDie(oldstack.ss_sp, oldstack.ss_size); +} + +static void MaybeInstallSigaction(int signum, + SignalHandlerType handler) { + if (GetHandleSignalMode(signum) == kHandleSignalNo) return; + + struct sigaction sigact; + internal_memset(&sigact, 0, sizeof(sigact)); + sigact.sa_sigaction = (sa_sigaction_t)handler; + // Do not block the signal from being received in that signal's handler. + // Clients are responsible for handling this correctly. + sigact.sa_flags = SA_SIGINFO | SA_NODEFER; + if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; + CHECK_EQ(0, internal_sigaction(signum, &sigact, nullptr)); + VReport(1, "Installed the sigaction for signal %d\n", signum); +} + +void InstallDeadlySignalHandlers(SignalHandlerType handler) { + // Set the alternate signal stack for the main thread. + // This will cause SetAlternateSignalStack to be called twice, but the stack + // will be actually set only once. + if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); + MaybeInstallSigaction(SIGSEGV, handler); + MaybeInstallSigaction(SIGBUS, handler); + MaybeInstallSigaction(SIGABRT, handler); + MaybeInstallSigaction(SIGFPE, handler); + MaybeInstallSigaction(SIGILL, handler); + MaybeInstallSigaction(SIGTRAP, handler); +} + +bool SignalContext::IsStackOverflow() const { + // Access at a reasonable offset above SP, or slightly below it (to account + // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is + // probably a stack overflow. +#ifdef __s390__ + // On s390, the fault address in siginfo points to start of the page, not + // to the precise word that was accessed. Mask off the low bits of sp to + // take it into account. + bool IsStackAccess = addr >= (sp & ~0xFFF) && addr < sp + 0xFFFF; +#else + // Let's accept up to a page size away from top of stack. Things like stack + // probing can trigger accesses with such large offsets. + bool IsStackAccess = addr + GetPageSizeCached() > sp && addr < sp + 0xFFFF; +#endif + +#if __powerpc__ + // Large stack frames can be allocated with e.g. + // lis r0,-10000 + // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000 + // If the store faults then sp will not have been updated, so test above + // will not work, because the fault address will be more than just "slightly" + // below sp. + if (!IsStackAccess && IsAccessibleMemoryRange(pc, 4)) { + u32 inst = *(unsigned *)pc; + u32 ra = (inst >> 16) & 0x1F; + u32 opcd = inst >> 26; + u32 xo = (inst >> 1) & 0x3FF; + // Check for store-with-update to sp. The instructions we accept are: + // stbu rs,d(ra) stbux rs,ra,rb + // sthu rs,d(ra) sthux rs,ra,rb + // stwu rs,d(ra) stwux rs,ra,rb + // stdu rs,ds(ra) stdux rs,ra,rb + // where ra is r1 (the stack pointer). + if (ra == 1 && + (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 || + (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181)))) + IsStackAccess = true; + } +#endif // __powerpc__ + + // We also check si_code to filter out SEGV caused by something else other + // then hitting the guard page or unmapped memory, like, for example, + // unaligned memory access. + auto si = static_cast(siginfo); + return IsStackAccess && + (si->si_code == si_SEGV_MAPERR || si->si_code == si_SEGV_ACCERR); +} + +#endif // SANITIZER_GO + +bool IsAccessibleMemoryRange(uptr beg, uptr size) { + uptr page_size = GetPageSizeCached(); + // Checking too large memory ranges is slow. + CHECK_LT(size, page_size * 10); + int sock_pair[2]; + if (pipe(sock_pair)) + return false; + uptr bytes_written = + internal_write(sock_pair[1], reinterpret_cast(beg), size); + int write_errno; + bool result; + if (internal_iserror(bytes_written, &write_errno)) { + CHECK_EQ(EFAULT, write_errno); + result = false; + } else { + result = (bytes_written == size); + } + internal_close(sock_pair[0]); + internal_close(sock_pair[1]); + return result; +} + +void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { + // Some kinds of sandboxes may forbid filesystem access, so we won't be able + // to read the file mappings from /proc/self/maps. Luckily, neither the + // process will be able to load additional libraries, so it's fine to use the + // cached mappings. + MemoryMappingLayout::CacheMemoryMappings(); +} + +static bool MmapFixed(uptr fixed_addr, uptr size, int additional_flags, + const char *name) { + size = RoundUpTo(size, GetPageSizeCached()); + fixed_addr = RoundDownTo(fixed_addr, GetPageSizeCached()); + uptr p = + MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED | additional_flags | MAP_ANON, name); + int reserrno; + if (internal_iserror(p, &reserrno)) { + Report("ERROR: %s failed to " + "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n", + SanitizerToolName, size, size, fixed_addr, reserrno); + return false; + } + IncreaseTotalMmap(size); + return true; +} + +bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { + return MmapFixed(fixed_addr, size, MAP_NORESERVE, name); +} + +bool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, const char *name) { +#if SANITIZER_FREEBSD + if (common_flags()->no_huge_pages_for_shadow) + return MmapFixedNoReserve(fixed_addr, size, name); + // MAP_NORESERVE is implicit with FreeBSD + return MmapFixed(fixed_addr, size, MAP_ALIGNED_SUPER, name); +#else + bool r = MmapFixedNoReserve(fixed_addr, size, name); + if (r) + SetShadowRegionHugePageMode(fixed_addr, size); + return r; +#endif +} + +uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { + base_ = fixed_addr ? MmapFixedNoAccess(fixed_addr, size, name) + : MmapNoAccess(size); + size_ = size; + name_ = name; + (void)os_handle_; // unsupported + return reinterpret_cast(base_); +} + +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, const char *name) { + return reinterpret_cast( + MmapFixedOrDieOnFatalError(fixed_addr, size, name)); +} + +uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size, + const char *name) { + return reinterpret_cast(MmapFixedOrDie(fixed_addr, size, name)); +} + +void ReservedAddressRange::Unmap(uptr addr, uptr size) { + CHECK_LE(size, size_); + if (addr == reinterpret_cast(base_)) + // If we unmap the whole range, just null out the base. + base_ = (size == size_) ? nullptr : reinterpret_cast(addr + size); + else + CHECK_EQ(addr + size, reinterpret_cast(base_) + size_); + size_ -= size; + UnmapOrDie(reinterpret_cast(addr), size); +} + +void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { + return (void *)MmapNamed((void *)fixed_addr, size, PROT_NONE, + MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE | MAP_ANON, + name); +} + +void *MmapNoAccess(uptr size) { + unsigned flags = MAP_PRIVATE | MAP_ANON | MAP_NORESERVE; + return (void *)internal_mmap(nullptr, size, PROT_NONE, flags, -1, 0); +} + +// This function is defined elsewhere if we intercepted pthread_attr_getstack. +extern "C" { +SANITIZER_WEAK_ATTRIBUTE int +real_pthread_attr_getstack(void *attr, void **addr, size_t *size); +} // extern "C" + +int my_pthread_attr_getstack(void *attr, void **addr, uptr *size) { +#if !SANITIZER_GO && !SANITIZER_MAC + if (&real_pthread_attr_getstack) + return real_pthread_attr_getstack((pthread_attr_t *)attr, addr, + (size_t *)size); +#endif + return pthread_attr_getstack((pthread_attr_t *)attr, addr, (size_t *)size); +} + +#if !SANITIZER_GO +void AdjustStackSize(void *attr_) { + pthread_attr_t *attr = (pthread_attr_t *)attr_; + uptr stackaddr = 0; + uptr stacksize = 0; + my_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize); + // GLibC will return (0 - stacksize) as the stack address in the case when + // stacksize is set, but stackaddr is not. + bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0); + // We place a lot of tool data into TLS, account for that. + const uptr minstacksize = GetTlsSize() + 128*1024; + if (stacksize < minstacksize) { + if (!stack_set) { + if (stacksize != 0) { + VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize, + minstacksize); + pthread_attr_setstacksize(attr, minstacksize); + } + } else { + Printf("Sanitizer: pre-allocated stack size is insufficient: " + "%zu < %zu\n", stacksize, minstacksize); + Printf("Sanitizer: pthread_create is likely to fail.\n"); + } + } +} +#endif // !SANITIZER_GO + +pid_t StartSubprocess(const char *program, const char *const argv[], + fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { + auto file_closer = at_scope_exit([&] { + if (stdin_fd != kInvalidFd) { + internal_close(stdin_fd); + } + if (stdout_fd != kInvalidFd) { + internal_close(stdout_fd); + } + if (stderr_fd != kInvalidFd) { + internal_close(stderr_fd); + } + }); + + int pid = internal_fork(); + + if (pid < 0) { + int rverrno; + if (internal_iserror(pid, &rverrno)) { + Report("WARNING: failed to fork (errno %d)\n", rverrno); + } + return pid; + } + + if (pid == 0) { + // Child subprocess + if (stdin_fd != kInvalidFd) { + internal_close(STDIN_FILENO); + internal_dup2(stdin_fd, STDIN_FILENO); + internal_close(stdin_fd); + } + if (stdout_fd != kInvalidFd) { + internal_close(STDOUT_FILENO); + internal_dup2(stdout_fd, STDOUT_FILENO); + internal_close(stdout_fd); + } + if (stderr_fd != kInvalidFd) { + internal_close(STDERR_FILENO); + internal_dup2(stderr_fd, STDERR_FILENO); + internal_close(stderr_fd); + } + + for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd); + + execv(program, const_cast(&argv[0])); + internal__exit(1); + } + + return pid; +} + +bool IsProcessRunning(pid_t pid) { + int process_status; + uptr waitpid_status = internal_waitpid(pid, &process_status, WNOHANG); + int local_errno; + if (internal_iserror(waitpid_status, &local_errno)) { + VReport(1, "Waiting on the process failed (errno %d).\n", local_errno); + return false; + } + return waitpid_status == 0; +} + +int WaitForProcess(pid_t pid) { + int process_status; + uptr waitpid_status = internal_waitpid(pid, &process_status, 0); + int local_errno; + if (internal_iserror(waitpid_status, &local_errno)) { + VReport(1, "Waiting on the process failed (errno %d).\n", local_errno); + return -1; + } + return process_status; +} + +bool IsStateDetached(int state) { + return state == PTHREAD_CREATE_DETACHED; +} + +} // namespace __sanitizer + +#endif // SANITIZER_POSIX diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc deleted file mode 100644 index f4e17a8f51fd..000000000000 --- a/lib/sanitizer_common/sanitizer_printf.cc +++ /dev/null @@ -1,358 +0,0 @@ -//===-- sanitizer_printf.cc -----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer. -// -// Internal printf function, used inside run-time libraries. -// We can't use libc printf because we intercept some of the functions used -// inside it. -//===----------------------------------------------------------------------===// - -#include "sanitizer_common.h" -#include "sanitizer_flags.h" -#include "sanitizer_libc.h" - -#include -#include - -#if SANITIZER_WINDOWS && defined(_MSC_VER) && _MSC_VER < 1800 && \ - !defined(va_copy) -# define va_copy(dst, src) ((dst) = (src)) -#endif - -namespace __sanitizer { - -static int AppendChar(char **buff, const char *buff_end, char c) { - if (*buff < buff_end) { - **buff = c; - (*buff)++; - } - return 1; -} - -// Appends number in a given base to buffer. If its length is less than -// |minimal_num_length|, it is padded with leading zeroes or spaces, depending -// on the value of |pad_with_zero|. -static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value, - u8 base, u8 minimal_num_length, bool pad_with_zero, - bool negative, bool uppercase) { - uptr const kMaxLen = 30; - RAW_CHECK(base == 10 || base == 16); - RAW_CHECK(base == 10 || !negative); - RAW_CHECK(absolute_value || !negative); - RAW_CHECK(minimal_num_length < kMaxLen); - int result = 0; - if (negative && minimal_num_length) - --minimal_num_length; - if (negative && pad_with_zero) - result += AppendChar(buff, buff_end, '-'); - uptr num_buffer[kMaxLen]; - int pos = 0; - do { - RAW_CHECK_MSG((uptr)pos < kMaxLen, "AppendNumber buffer overflow"); - num_buffer[pos++] = absolute_value % base; - absolute_value /= base; - } while (absolute_value > 0); - if (pos < minimal_num_length) { - // Make sure compiler doesn't insert call to memset here. - internal_memset(&num_buffer[pos], 0, - sizeof(num_buffer[0]) * (minimal_num_length - pos)); - pos = minimal_num_length; - } - RAW_CHECK(pos > 0); - pos--; - for (; pos >= 0 && num_buffer[pos] == 0; pos--) { - char c = (pad_with_zero || pos == 0) ? '0' : ' '; - result += AppendChar(buff, buff_end, c); - } - if (negative && !pad_with_zero) result += AppendChar(buff, buff_end, '-'); - for (; pos >= 0; pos--) { - char digit = static_cast(num_buffer[pos]); - digit = (digit < 10) ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10; - result += AppendChar(buff, buff_end, digit); - } - return result; -} - -static int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base, - u8 minimal_num_length, bool pad_with_zero, - bool uppercase) { - return AppendNumber(buff, buff_end, num, base, minimal_num_length, - pad_with_zero, false /* negative */, uppercase); -} - -static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num, - u8 minimal_num_length, bool pad_with_zero) { - bool negative = (num < 0); - return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10, - minimal_num_length, pad_with_zero, negative, - false /* uppercase */); -} - - -// Use the fact that explicitly requesting 0 width (%0s) results in UB and -// interpret width == 0 as "no width requested": -// width == 0 - no width requested -// width < 0 - left-justify s within and pad it to -width chars, if necessary -// width > 0 - right-justify s, not implemented yet -static int AppendString(char **buff, const char *buff_end, int width, - int max_chars, const char *s) { - if (!s) - s = ""; - int result = 0; - for (; *s; s++) { - if (max_chars >= 0 && result >= max_chars) - break; - result += AppendChar(buff, buff_end, *s); - } - // Only the left justified strings are supported. - while (width < -result) - result += AppendChar(buff, buff_end, ' '); - return result; -} - -static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) { - int result = 0; - result += AppendString(buff, buff_end, 0, -1, "0x"); - result += AppendUnsigned(buff, buff_end, ptr_value, 16, - SANITIZER_POINTER_FORMAT_LENGTH, - true /* pad_with_zero */, false /* uppercase */); - return result; -} - -int VSNPrintf(char *buff, int buff_length, - const char *format, va_list args) { - static const char *kPrintfFormatsHelp = - "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x,X}; %p; " - "%[-]([0-9]*)?(\\.\\*)?s; %c\n"; - RAW_CHECK(format); - RAW_CHECK(buff_length > 0); - const char *buff_end = &buff[buff_length - 1]; - const char *cur = format; - int result = 0; - for (; *cur; cur++) { - if (*cur != '%') { - result += AppendChar(&buff, buff_end, *cur); - continue; - } - cur++; - bool left_justified = *cur == '-'; - if (left_justified) - cur++; - bool have_width = (*cur >= '0' && *cur <= '9'); - bool pad_with_zero = (*cur == '0'); - int width = 0; - if (have_width) { - while (*cur >= '0' && *cur <= '9') { - width = width * 10 + *cur++ - '0'; - } - } - bool have_precision = (cur[0] == '.' && cur[1] == '*'); - int precision = -1; - if (have_precision) { - cur += 2; - precision = va_arg(args, int); - } - bool have_z = (*cur == 'z'); - cur += have_z; - bool have_ll = !have_z && (cur[0] == 'l' && cur[1] == 'l'); - cur += have_ll * 2; - s64 dval; - u64 uval; - const bool have_length = have_z || have_ll; - const bool have_flags = have_width || have_length; - // At the moment only %s supports precision and left-justification. - CHECK(!((precision >= 0 || left_justified) && *cur != 's')); - switch (*cur) { - case 'd': { - dval = have_ll ? va_arg(args, s64) - : have_z ? va_arg(args, sptr) - : va_arg(args, int); - result += AppendSignedDecimal(&buff, buff_end, dval, width, - pad_with_zero); - break; - } - case 'u': - case 'x': - case 'X': { - uval = have_ll ? va_arg(args, u64) - : have_z ? va_arg(args, uptr) - : va_arg(args, unsigned); - bool uppercase = (*cur == 'X'); - result += AppendUnsigned(&buff, buff_end, uval, (*cur == 'u') ? 10 : 16, - width, pad_with_zero, uppercase); - break; - } - case 'p': { - RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); - result += AppendPointer(&buff, buff_end, va_arg(args, uptr)); - break; - } - case 's': { - RAW_CHECK_MSG(!have_length, kPrintfFormatsHelp); - // Only left-justified width is supported. - CHECK(!have_width || left_justified); - result += AppendString(&buff, buff_end, left_justified ? -width : width, - precision, va_arg(args, char*)); - break; - } - case 'c': { - RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); - result += AppendChar(&buff, buff_end, va_arg(args, int)); - break; - } - case '%' : { - RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); - result += AppendChar(&buff, buff_end, '%'); - break; - } - default: { - RAW_CHECK_MSG(false, kPrintfFormatsHelp); - } - } - } - RAW_CHECK(buff <= buff_end); - AppendChar(&buff, buff_end + 1, '\0'); - return result; -} - -static void (*PrintfAndReportCallback)(const char *); -void SetPrintfAndReportCallback(void (*callback)(const char *)) { - PrintfAndReportCallback = callback; -} - -// Can be overriden in frontend. -#if SANITIZER_GO && defined(TSAN_EXTERNAL_HOOKS) -// Implementation must be defined in frontend. -extern "C" void OnPrint(const char *str); -#else -SANITIZER_INTERFACE_WEAK_DEF(void, OnPrint, const char *str) { - (void)str; -} -#endif - -static void CallPrintfAndReportCallback(const char *str) { - OnPrint(str); - if (PrintfAndReportCallback) - PrintfAndReportCallback(str); -} - -static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid, - char *local_buffer, - int buffer_size, - const char *format, - va_list args) { - va_list args2; - va_copy(args2, args); - const int kLen = 16 * 1024; - int needed_length; - char *buffer = local_buffer; - // First try to print a message using a local buffer, and then fall back to - // mmaped buffer. - for (int use_mmap = 0; use_mmap < 2; use_mmap++) { - if (use_mmap) { - va_end(args); - va_copy(args, args2); - buffer = (char*)MmapOrDie(kLen, "Report"); - buffer_size = kLen; - } - needed_length = 0; - // Check that data fits into the current buffer. -# define CHECK_NEEDED_LENGTH \ - if (needed_length >= buffer_size) { \ - if (!use_mmap) continue; \ - RAW_CHECK_MSG(needed_length < kLen, \ - "Buffer in Report is too short!\n"); \ - } - // Fuchsia's logging infrastructure always keeps track of the logging - // process, thread, and timestamp, so never prepend such information. - if (!SANITIZER_FUCHSIA && append_pid) { - int pid = internal_getpid(); - const char *exe_name = GetProcessName(); - if (common_flags()->log_exe_name && exe_name) { - needed_length += internal_snprintf(buffer, buffer_size, - "==%s", exe_name); - CHECK_NEEDED_LENGTH - } - needed_length += internal_snprintf( - buffer + needed_length, buffer_size - needed_length, "==%d==", pid); - CHECK_NEEDED_LENGTH - } - needed_length += VSNPrintf(buffer + needed_length, - buffer_size - needed_length, format, args); - CHECK_NEEDED_LENGTH - // If the message fit into the buffer, print it and exit. - break; -# undef CHECK_NEEDED_LENGTH - } - RawWrite(buffer); - - // Remove color sequences from the message. - RemoveANSIEscapeSequencesFromString(buffer); - CallPrintfAndReportCallback(buffer); - LogMessageOnPrintf(buffer); - - // If we had mapped any memory, clean up. - if (buffer != local_buffer) - UnmapOrDie((void *)buffer, buffer_size); - va_end(args2); -} - -static void NOINLINE SharedPrintfCode(bool append_pid, const char *format, - va_list args) { - // |local_buffer| is small enough not to overflow the stack and/or violate - // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other - // hand, the bigger the buffer is, the more the chance the error report will - // fit into it. - char local_buffer[400]; - SharedPrintfCodeNoBuffer(append_pid, local_buffer, ARRAY_SIZE(local_buffer), - format, args); -} - -FORMAT(1, 2) -void Printf(const char *format, ...) { - va_list args; - va_start(args, format); - SharedPrintfCode(false, format, args); - va_end(args); -} - -// Like Printf, but prints the current PID before the output string. -FORMAT(1, 2) -void Report(const char *format, ...) { - va_list args; - va_start(args, format); - SharedPrintfCode(true, format, args); - va_end(args); -} - -// Writes at most "length" symbols to "buffer" (including trailing '\0'). -// Returns the number of symbols that should have been written to buffer -// (not including trailing '\0'). Thus, the string is truncated -// iff return value is not less than "length". -FORMAT(3, 4) -int internal_snprintf(char *buffer, uptr length, const char *format, ...) { - va_list args; - va_start(args, format); - int needed_length = VSNPrintf(buffer, length, format, args); - va_end(args); - return needed_length; -} - -FORMAT(2, 3) -void InternalScopedString::append(const char *format, ...) { - CHECK_LT(length_, size()); - va_list args; - va_start(args, format); - VSNPrintf(data() + length_, size() - length_, format, args); - va_end(args); - length_ += internal_strlen(data() + length_); - CHECK_LT(length_, size()); -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_printf.cpp b/lib/sanitizer_common/sanitizer_printf.cpp new file mode 100644 index 000000000000..a032787114bb --- /dev/null +++ b/lib/sanitizer_common/sanitizer_printf.cpp @@ -0,0 +1,358 @@ +//===-- sanitizer_printf.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer. +// +// Internal printf function, used inside run-time libraries. +// We can't use libc printf because we intercept some of the functions used +// inside it. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_libc.h" + +#include +#include + +#if SANITIZER_WINDOWS && defined(_MSC_VER) && _MSC_VER < 1800 && \ + !defined(va_copy) +# define va_copy(dst, src) ((dst) = (src)) +#endif + +namespace __sanitizer { + +static int AppendChar(char **buff, const char *buff_end, char c) { + if (*buff < buff_end) { + **buff = c; + (*buff)++; + } + return 1; +} + +// Appends number in a given base to buffer. If its length is less than +// |minimal_num_length|, it is padded with leading zeroes or spaces, depending +// on the value of |pad_with_zero|. +static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value, + u8 base, u8 minimal_num_length, bool pad_with_zero, + bool negative, bool uppercase) { + uptr const kMaxLen = 30; + RAW_CHECK(base == 10 || base == 16); + RAW_CHECK(base == 10 || !negative); + RAW_CHECK(absolute_value || !negative); + RAW_CHECK(minimal_num_length < kMaxLen); + int result = 0; + if (negative && minimal_num_length) + --minimal_num_length; + if (negative && pad_with_zero) + result += AppendChar(buff, buff_end, '-'); + uptr num_buffer[kMaxLen]; + int pos = 0; + do { + RAW_CHECK_MSG((uptr)pos < kMaxLen, "AppendNumber buffer overflow"); + num_buffer[pos++] = absolute_value % base; + absolute_value /= base; + } while (absolute_value > 0); + if (pos < minimal_num_length) { + // Make sure compiler doesn't insert call to memset here. + internal_memset(&num_buffer[pos], 0, + sizeof(num_buffer[0]) * (minimal_num_length - pos)); + pos = minimal_num_length; + } + RAW_CHECK(pos > 0); + pos--; + for (; pos >= 0 && num_buffer[pos] == 0; pos--) { + char c = (pad_with_zero || pos == 0) ? '0' : ' '; + result += AppendChar(buff, buff_end, c); + } + if (negative && !pad_with_zero) result += AppendChar(buff, buff_end, '-'); + for (; pos >= 0; pos--) { + char digit = static_cast(num_buffer[pos]); + digit = (digit < 10) ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10; + result += AppendChar(buff, buff_end, digit); + } + return result; +} + +static int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base, + u8 minimal_num_length, bool pad_with_zero, + bool uppercase) { + return AppendNumber(buff, buff_end, num, base, minimal_num_length, + pad_with_zero, false /* negative */, uppercase); +} + +static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num, + u8 minimal_num_length, bool pad_with_zero) { + bool negative = (num < 0); + return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10, + minimal_num_length, pad_with_zero, negative, + false /* uppercase */); +} + + +// Use the fact that explicitly requesting 0 width (%0s) results in UB and +// interpret width == 0 as "no width requested": +// width == 0 - no width requested +// width < 0 - left-justify s within and pad it to -width chars, if necessary +// width > 0 - right-justify s, not implemented yet +static int AppendString(char **buff, const char *buff_end, int width, + int max_chars, const char *s) { + if (!s) + s = ""; + int result = 0; + for (; *s; s++) { + if (max_chars >= 0 && result >= max_chars) + break; + result += AppendChar(buff, buff_end, *s); + } + // Only the left justified strings are supported. + while (width < -result) + result += AppendChar(buff, buff_end, ' '); + return result; +} + +static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) { + int result = 0; + result += AppendString(buff, buff_end, 0, -1, "0x"); + result += AppendUnsigned(buff, buff_end, ptr_value, 16, + SANITIZER_POINTER_FORMAT_LENGTH, + true /* pad_with_zero */, false /* uppercase */); + return result; +} + +int VSNPrintf(char *buff, int buff_length, + const char *format, va_list args) { + static const char *kPrintfFormatsHelp = + "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x,X}; %p; " + "%[-]([0-9]*)?(\\.\\*)?s; %c\n"; + RAW_CHECK(format); + RAW_CHECK(buff_length > 0); + const char *buff_end = &buff[buff_length - 1]; + const char *cur = format; + int result = 0; + for (; *cur; cur++) { + if (*cur != '%') { + result += AppendChar(&buff, buff_end, *cur); + continue; + } + cur++; + bool left_justified = *cur == '-'; + if (left_justified) + cur++; + bool have_width = (*cur >= '0' && *cur <= '9'); + bool pad_with_zero = (*cur == '0'); + int width = 0; + if (have_width) { + while (*cur >= '0' && *cur <= '9') { + width = width * 10 + *cur++ - '0'; + } + } + bool have_precision = (cur[0] == '.' && cur[1] == '*'); + int precision = -1; + if (have_precision) { + cur += 2; + precision = va_arg(args, int); + } + bool have_z = (*cur == 'z'); + cur += have_z; + bool have_ll = !have_z && (cur[0] == 'l' && cur[1] == 'l'); + cur += have_ll * 2; + s64 dval; + u64 uval; + const bool have_length = have_z || have_ll; + const bool have_flags = have_width || have_length; + // At the moment only %s supports precision and left-justification. + CHECK(!((precision >= 0 || left_justified) && *cur != 's')); + switch (*cur) { + case 'd': { + dval = have_ll ? va_arg(args, s64) + : have_z ? va_arg(args, sptr) + : va_arg(args, int); + result += AppendSignedDecimal(&buff, buff_end, dval, width, + pad_with_zero); + break; + } + case 'u': + case 'x': + case 'X': { + uval = have_ll ? va_arg(args, u64) + : have_z ? va_arg(args, uptr) + : va_arg(args, unsigned); + bool uppercase = (*cur == 'X'); + result += AppendUnsigned(&buff, buff_end, uval, (*cur == 'u') ? 10 : 16, + width, pad_with_zero, uppercase); + break; + } + case 'p': { + RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); + result += AppendPointer(&buff, buff_end, va_arg(args, uptr)); + break; + } + case 's': { + RAW_CHECK_MSG(!have_length, kPrintfFormatsHelp); + // Only left-justified width is supported. + CHECK(!have_width || left_justified); + result += AppendString(&buff, buff_end, left_justified ? -width : width, + precision, va_arg(args, char*)); + break; + } + case 'c': { + RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); + result += AppendChar(&buff, buff_end, va_arg(args, int)); + break; + } + case '%' : { + RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); + result += AppendChar(&buff, buff_end, '%'); + break; + } + default: { + RAW_CHECK_MSG(false, kPrintfFormatsHelp); + } + } + } + RAW_CHECK(buff <= buff_end); + AppendChar(&buff, buff_end + 1, '\0'); + return result; +} + +static void (*PrintfAndReportCallback)(const char *); +void SetPrintfAndReportCallback(void (*callback)(const char *)) { + PrintfAndReportCallback = callback; +} + +// Can be overriden in frontend. +#if SANITIZER_GO && defined(TSAN_EXTERNAL_HOOKS) +// Implementation must be defined in frontend. +extern "C" void __sanitizer_on_print(const char *str); +#else +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_on_print, const char *str) { + (void)str; +} +#endif + +static void CallPrintfAndReportCallback(const char *str) { + __sanitizer_on_print(str); + if (PrintfAndReportCallback) + PrintfAndReportCallback(str); +} + +static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid, + char *local_buffer, + int buffer_size, + const char *format, + va_list args) { + va_list args2; + va_copy(args2, args); + const int kLen = 16 * 1024; + int needed_length; + char *buffer = local_buffer; + // First try to print a message using a local buffer, and then fall back to + // mmaped buffer. + for (int use_mmap = 0; use_mmap < 2; use_mmap++) { + if (use_mmap) { + va_end(args); + va_copy(args, args2); + buffer = (char*)MmapOrDie(kLen, "Report"); + buffer_size = kLen; + } + needed_length = 0; + // Check that data fits into the current buffer. +# define CHECK_NEEDED_LENGTH \ + if (needed_length >= buffer_size) { \ + if (!use_mmap) continue; \ + RAW_CHECK_MSG(needed_length < kLen, \ + "Buffer in Report is too short!\n"); \ + } + // Fuchsia's logging infrastructure always keeps track of the logging + // process, thread, and timestamp, so never prepend such information. + if (!SANITIZER_FUCHSIA && append_pid) { + int pid = internal_getpid(); + const char *exe_name = GetProcessName(); + if (common_flags()->log_exe_name && exe_name) { + needed_length += internal_snprintf(buffer, buffer_size, + "==%s", exe_name); + CHECK_NEEDED_LENGTH + } + needed_length += internal_snprintf( + buffer + needed_length, buffer_size - needed_length, "==%d==", pid); + CHECK_NEEDED_LENGTH + } + needed_length += VSNPrintf(buffer + needed_length, + buffer_size - needed_length, format, args); + CHECK_NEEDED_LENGTH + // If the message fit into the buffer, print it and exit. + break; +# undef CHECK_NEEDED_LENGTH + } + RawWrite(buffer); + + // Remove color sequences from the message. + RemoveANSIEscapeSequencesFromString(buffer); + CallPrintfAndReportCallback(buffer); + LogMessageOnPrintf(buffer); + + // If we had mapped any memory, clean up. + if (buffer != local_buffer) + UnmapOrDie((void *)buffer, buffer_size); + va_end(args2); +} + +static void NOINLINE SharedPrintfCode(bool append_pid, const char *format, + va_list args) { + // |local_buffer| is small enough not to overflow the stack and/or violate + // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other + // hand, the bigger the buffer is, the more the chance the error report will + // fit into it. + char local_buffer[400]; + SharedPrintfCodeNoBuffer(append_pid, local_buffer, ARRAY_SIZE(local_buffer), + format, args); +} + +FORMAT(1, 2) +void Printf(const char *format, ...) { + va_list args; + va_start(args, format); + SharedPrintfCode(false, format, args); + va_end(args); +} + +// Like Printf, but prints the current PID before the output string. +FORMAT(1, 2) +void Report(const char *format, ...) { + va_list args; + va_start(args, format); + SharedPrintfCode(true, format, args); + va_end(args); +} + +// Writes at most "length" symbols to "buffer" (including trailing '\0'). +// Returns the number of symbols that should have been written to buffer +// (not including trailing '\0'). Thus, the string is truncated +// iff return value is not less than "length". +FORMAT(3, 4) +int internal_snprintf(char *buffer, uptr length, const char *format, ...) { + va_list args; + va_start(args, format); + int needed_length = VSNPrintf(buffer, length, format, args); + va_end(args); + return needed_length; +} + +FORMAT(2, 3) +void InternalScopedString::append(const char *format, ...) { + CHECK_LT(length_, size()); + va_list args; + va_start(args, format); + VSNPrintf(data() + length_, size() - length_, format, args); + va_end(args); + length_ += internal_strlen(data() + length_); + CHECK_LT(length_, size()); +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h index 052027111ceb..d0e5245f84da 100644 --- a/lib/sanitizer_common/sanitizer_procmaps.h +++ b/lib/sanitizer_common/sanitizer_procmaps.h @@ -37,7 +37,7 @@ struct MemoryMappedSegmentData; class MemoryMappedSegment { public: - MemoryMappedSegment(char *buff = nullptr, uptr size = 0) + explicit MemoryMappedSegment(char *buff = nullptr, uptr size = 0) : filename(buff), filename_size(size), data_(nullptr) {} ~MemoryMappedSegment() {} diff --git a/lib/sanitizer_common/sanitizer_procmaps_bsd.cc b/lib/sanitizer_common/sanitizer_procmaps_bsd.cc deleted file mode 100644 index c38bafd9f52f..000000000000 --- a/lib/sanitizer_common/sanitizer_procmaps_bsd.cc +++ /dev/null @@ -1,139 +0,0 @@ -//===-- sanitizer_procmaps_bsd.cc -----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Information about the process mappings -// (FreeBSD, OpenBSD and NetBSD-specific parts). -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD -#include "sanitizer_common.h" -#if SANITIZER_FREEBSD -#include "sanitizer_freebsd.h" -#endif -#include "sanitizer_procmaps.h" - -// clang-format off -#include -#include -// clang-format on -#include -#if SANITIZER_FREEBSD -#include -#endif - -#include -#if SANITIZER_OPENBSD -#define KVME_PROT_READ KVE_PROT_READ -#define KVME_PROT_WRITE KVE_PROT_WRITE -#define KVME_PROT_EXEC KVE_PROT_EXEC -#endif - -// Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode. -#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) -#include -#if __FreeBSD_version <= 902001 // v9.2 -#define kinfo_vmentry xkinfo_vmentry -#endif -#endif - -namespace __sanitizer { - -void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { - const int Mib[] = { -#if SANITIZER_FREEBSD - CTL_KERN, - KERN_PROC, - KERN_PROC_VMMAP, - getpid() -#elif SANITIZER_OPENBSD - CTL_KERN, - KERN_PROC_VMMAP, - getpid() -#elif SANITIZER_NETBSD - CTL_VM, - VM_PROC, - VM_PROC_MAP, - getpid(), - sizeof(struct kinfo_vmentry) -#else -#error "not supported" -#endif - }; - - uptr Size = 0; - int Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), NULL, &Size, NULL, 0); - CHECK_EQ(Err, 0); - CHECK_GT(Size, 0); - -#if !SANITIZER_OPENBSD - size_t MmapedSize = Size * 4 / 3; - void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()"); - Size = MmapedSize; - Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), VmMap, &Size, NULL, 0); - CHECK_EQ(Err, 0); - proc_maps->data = (char *)VmMap; -#else - size_t PageSize = GetPageSize(); - size_t MmapedSize = Size; - MmapedSize = ((MmapedSize - 1) / PageSize + 1) * PageSize; - char *Mem = (char *)MmapOrDie(MmapedSize, "ReadProcMaps()"); - Size = 2 * Size + 10 * sizeof(struct kinfo_vmentry); - if (Size > 0x10000) - Size = 0x10000; - Size = (Size / sizeof(struct kinfo_vmentry)) * sizeof(struct kinfo_vmentry); - Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), Mem, &Size, NULL, 0); - CHECK_EQ(Err, 0); - MmapedSize = Size; - proc_maps->data = Mem; -#endif - - proc_maps->mmaped_size = MmapedSize; - proc_maps->len = Size; -} - -bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { - CHECK(!Error()); // can not fail - char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; - if (data_.current >= last) - return false; - const struct kinfo_vmentry *VmEntry = - (const struct kinfo_vmentry *)data_.current; - - segment->start = (uptr)VmEntry->kve_start; - segment->end = (uptr)VmEntry->kve_end; - segment->offset = (uptr)VmEntry->kve_offset; - - segment->protection = 0; - if ((VmEntry->kve_protection & KVME_PROT_READ) != 0) - segment->protection |= kProtectionRead; - if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0) - segment->protection |= kProtectionWrite; - if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0) - segment->protection |= kProtectionExecute; - -#if !SANITIZER_OPENBSD - if (segment->filename != NULL && segment->filename_size > 0) { - internal_snprintf(segment->filename, - Min(segment->filename_size, (uptr)PATH_MAX), "%s", - VmEntry->kve_path); - } -#endif - -#if SANITIZER_FREEBSD - data_.current += VmEntry->kve_structsize; -#else - data_.current += sizeof(*VmEntry); -#endif - - return true; -} - -} // namespace __sanitizer - -#endif diff --git a/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp b/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp new file mode 100644 index 000000000000..02ff7c0e91a8 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp @@ -0,0 +1,139 @@ +//===-- sanitizer_procmaps_bsd.cpp ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Information about the process mappings +// (FreeBSD, OpenBSD and NetBSD-specific parts). +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD +#include "sanitizer_common.h" +#if SANITIZER_FREEBSD +#include "sanitizer_freebsd.h" +#endif +#include "sanitizer_procmaps.h" + +// clang-format off +#include +#include +// clang-format on +#include +#if SANITIZER_FREEBSD +#include +#endif + +#include +#if SANITIZER_OPENBSD +#define KVME_PROT_READ KVE_PROT_READ +#define KVME_PROT_WRITE KVE_PROT_WRITE +#define KVME_PROT_EXEC KVE_PROT_EXEC +#endif + +// Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode. +#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) +#include +#if __FreeBSD_version <= 902001 // v9.2 +#define kinfo_vmentry xkinfo_vmentry +#endif +#endif + +namespace __sanitizer { + +void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { + const int Mib[] = { +#if SANITIZER_FREEBSD + CTL_KERN, + KERN_PROC, + KERN_PROC_VMMAP, + getpid() +#elif SANITIZER_OPENBSD + CTL_KERN, + KERN_PROC_VMMAP, + getpid() +#elif SANITIZER_NETBSD + CTL_VM, + VM_PROC, + VM_PROC_MAP, + getpid(), + sizeof(struct kinfo_vmentry) +#else +#error "not supported" +#endif + }; + + uptr Size = 0; + int Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), NULL, &Size, NULL, 0); + CHECK_EQ(Err, 0); + CHECK_GT(Size, 0); + +#if !SANITIZER_OPENBSD + size_t MmapedSize = Size * 4 / 3; + void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()"); + Size = MmapedSize; + Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), VmMap, &Size, NULL, 0); + CHECK_EQ(Err, 0); + proc_maps->data = (char *)VmMap; +#else + size_t PageSize = GetPageSize(); + size_t MmapedSize = Size; + MmapedSize = ((MmapedSize - 1) / PageSize + 1) * PageSize; + char *Mem = (char *)MmapOrDie(MmapedSize, "ReadProcMaps()"); + Size = 2 * Size + 10 * sizeof(struct kinfo_vmentry); + if (Size > 0x10000) + Size = 0x10000; + Size = (Size / sizeof(struct kinfo_vmentry)) * sizeof(struct kinfo_vmentry); + Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), Mem, &Size, NULL, 0); + CHECK_EQ(Err, 0); + MmapedSize = Size; + proc_maps->data = Mem; +#endif + + proc_maps->mmaped_size = MmapedSize; + proc_maps->len = Size; +} + +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { + CHECK(!Error()); // can not fail + char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; + if (data_.current >= last) + return false; + const struct kinfo_vmentry *VmEntry = + (const struct kinfo_vmentry *)data_.current; + + segment->start = (uptr)VmEntry->kve_start; + segment->end = (uptr)VmEntry->kve_end; + segment->offset = (uptr)VmEntry->kve_offset; + + segment->protection = 0; + if ((VmEntry->kve_protection & KVME_PROT_READ) != 0) + segment->protection |= kProtectionRead; + if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0) + segment->protection |= kProtectionWrite; + if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0) + segment->protection |= kProtectionExecute; + +#if !SANITIZER_OPENBSD + if (segment->filename != NULL && segment->filename_size > 0) { + internal_snprintf(segment->filename, + Min(segment->filename_size, (uptr)PATH_MAX), "%s", + VmEntry->kve_path); + } +#endif + +#if SANITIZER_FREEBSD + data_.current += VmEntry->kve_structsize; +#else + data_.current += sizeof(*VmEntry); +#endif + + return true; +} + +} // namespace __sanitizer + +#endif diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc deleted file mode 100644 index 4a2b0a047ad6..000000000000 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ /dev/null @@ -1,174 +0,0 @@ -//===-- sanitizer_procmaps_common.cc --------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Information about the process mappings (common parts). -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS - -#include "sanitizer_common.h" -#include "sanitizer_placement_new.h" -#include "sanitizer_procmaps.h" - -namespace __sanitizer { - -static ProcSelfMapsBuff cached_proc_self_maps; -static StaticSpinMutex cache_lock; - -static int TranslateDigit(char c) { - if (c >= '0' && c <= '9') - return c - '0'; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - return -1; -} - -// Parse a number and promote 'p' up to the first non-digit character. -static uptr ParseNumber(const char **p, int base) { - uptr n = 0; - int d; - CHECK(base >= 2 && base <= 16); - while ((d = TranslateDigit(**p)) >= 0 && d < base) { - n = n * base + d; - (*p)++; - } - return n; -} - -bool IsDecimal(char c) { - int d = TranslateDigit(c); - return d >= 0 && d < 10; -} - -uptr ParseDecimal(const char **p) { - return ParseNumber(p, 10); -} - -bool IsHex(char c) { - int d = TranslateDigit(c); - return d >= 0 && d < 16; -} - -uptr ParseHex(const char **p) { - return ParseNumber(p, 16); -} - -void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { - // data_ should be unused on this platform - CHECK(!data_); - module->addAddressRange(start, end, IsExecutable(), IsWritable()); -} - -MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { - // FIXME: in the future we may want to cache the mappings on demand only. - if (cache_enabled) - CacheMemoryMappings(); - - // Read maps after the cache update to capture the maps/unmaps happening in - // the process of updating. - ReadProcMaps(&data_.proc_self_maps); - if (cache_enabled && data_.proc_self_maps.mmaped_size == 0) - LoadFromCache(); - - Reset(); -} - -bool MemoryMappingLayout::Error() const { - return data_.current == nullptr; -} - -MemoryMappingLayout::~MemoryMappingLayout() { - // Only unmap the buffer if it is different from the cached one. Otherwise - // it will be unmapped when the cache is refreshed. - if (data_.proc_self_maps.data != cached_proc_self_maps.data) - UnmapOrDie(data_.proc_self_maps.data, data_.proc_self_maps.mmaped_size); -} - -void MemoryMappingLayout::Reset() { - data_.current = data_.proc_self_maps.data; -} - -// static -void MemoryMappingLayout::CacheMemoryMappings() { - ProcSelfMapsBuff new_proc_self_maps; - ReadProcMaps(&new_proc_self_maps); - // Don't invalidate the cache if the mappings are unavailable. - if (new_proc_self_maps.mmaped_size == 0) - return; - SpinMutexLock l(&cache_lock); - if (cached_proc_self_maps.mmaped_size) - UnmapOrDie(cached_proc_self_maps.data, cached_proc_self_maps.mmaped_size); - cached_proc_self_maps = new_proc_self_maps; -} - -void MemoryMappingLayout::LoadFromCache() { - SpinMutexLock l(&cache_lock); - if (cached_proc_self_maps.data) - data_.proc_self_maps = cached_proc_self_maps; -} - -void MemoryMappingLayout::DumpListOfModules( - InternalMmapVectorNoCtor *modules) { - Reset(); - InternalScopedString module_name(kMaxPathLength); - MemoryMappedSegment segment(module_name.data(), module_name.size()); - for (uptr i = 0; Next(&segment); i++) { - const char *cur_name = segment.filename; - if (cur_name[0] == '\0') - continue; - // Don't subtract 'cur_beg' from the first entry: - // * If a binary is compiled w/o -pie, then the first entry in - // process maps is likely the binary itself (all dynamic libs - // are mapped higher in address space). For such a binary, - // instruction offset in binary coincides with the actual - // instruction address in virtual memory (as code section - // is mapped to a fixed memory range). - // * If a binary is compiled with -pie, all the modules are - // mapped high at address space (in particular, higher than - // shadow memory of the tool), so the module can't be the - // first entry. - uptr base_address = (i ? segment.start : 0) - segment.offset; - LoadedModule cur_module; - cur_module.set(cur_name, base_address); - segment.AddAddressRanges(&cur_module); - modules->push_back(cur_module); - } -} - -void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { - char *smaps = nullptr; - uptr smaps_cap = 0; - uptr smaps_len = 0; - if (!ReadFileToBuffer("/proc/self/smaps", &smaps, &smaps_cap, &smaps_len)) - return; - uptr start = 0; - bool file = false; - const char *pos = smaps; - while (pos < smaps + smaps_len) { - if (IsHex(pos[0])) { - start = ParseHex(&pos); - for (; *pos != '/' && *pos > '\n'; pos++) {} - file = *pos == '/'; - } else if (internal_strncmp(pos, "Rss:", 4) == 0) { - while (!IsDecimal(*pos)) pos++; - uptr rss = ParseDecimal(&pos) * 1024; - cb(start, rss, file, stats, stats_size); - } - while (*pos++ != '\n') {} - } - UnmapOrDie(smaps, smaps_cap); -} - -} // namespace __sanitizer - -#endif diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cpp b/lib/sanitizer_common/sanitizer_procmaps_common.cpp new file mode 100644 index 000000000000..e0cb47f8ca9a --- /dev/null +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cpp @@ -0,0 +1,174 @@ +//===-- sanitizer_procmaps_common.cpp -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Information about the process mappings (common parts). +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ + SANITIZER_OPENBSD || SANITIZER_SOLARIS + +#include "sanitizer_common.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_procmaps.h" + +namespace __sanitizer { + +static ProcSelfMapsBuff cached_proc_self_maps; +static StaticSpinMutex cache_lock; + +static int TranslateDigit(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +// Parse a number and promote 'p' up to the first non-digit character. +static uptr ParseNumber(const char **p, int base) { + uptr n = 0; + int d; + CHECK(base >= 2 && base <= 16); + while ((d = TranslateDigit(**p)) >= 0 && d < base) { + n = n * base + d; + (*p)++; + } + return n; +} + +bool IsDecimal(char c) { + int d = TranslateDigit(c); + return d >= 0 && d < 10; +} + +uptr ParseDecimal(const char **p) { + return ParseNumber(p, 10); +} + +bool IsHex(char c) { + int d = TranslateDigit(c); + return d >= 0 && d < 16; +} + +uptr ParseHex(const char **p) { + return ParseNumber(p, 16); +} + +void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { + // data_ should be unused on this platform + CHECK(!data_); + module->addAddressRange(start, end, IsExecutable(), IsWritable()); +} + +MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { + // FIXME: in the future we may want to cache the mappings on demand only. + if (cache_enabled) + CacheMemoryMappings(); + + // Read maps after the cache update to capture the maps/unmaps happening in + // the process of updating. + ReadProcMaps(&data_.proc_self_maps); + if (cache_enabled && data_.proc_self_maps.mmaped_size == 0) + LoadFromCache(); + + Reset(); +} + +bool MemoryMappingLayout::Error() const { + return data_.current == nullptr; +} + +MemoryMappingLayout::~MemoryMappingLayout() { + // Only unmap the buffer if it is different from the cached one. Otherwise + // it will be unmapped when the cache is refreshed. + if (data_.proc_self_maps.data != cached_proc_self_maps.data) + UnmapOrDie(data_.proc_self_maps.data, data_.proc_self_maps.mmaped_size); +} + +void MemoryMappingLayout::Reset() { + data_.current = data_.proc_self_maps.data; +} + +// static +void MemoryMappingLayout::CacheMemoryMappings() { + ProcSelfMapsBuff new_proc_self_maps; + ReadProcMaps(&new_proc_self_maps); + // Don't invalidate the cache if the mappings are unavailable. + if (new_proc_self_maps.mmaped_size == 0) + return; + SpinMutexLock l(&cache_lock); + if (cached_proc_self_maps.mmaped_size) + UnmapOrDie(cached_proc_self_maps.data, cached_proc_self_maps.mmaped_size); + cached_proc_self_maps = new_proc_self_maps; +} + +void MemoryMappingLayout::LoadFromCache() { + SpinMutexLock l(&cache_lock); + if (cached_proc_self_maps.data) + data_.proc_self_maps = cached_proc_self_maps; +} + +void MemoryMappingLayout::DumpListOfModules( + InternalMmapVectorNoCtor *modules) { + Reset(); + InternalScopedString module_name(kMaxPathLength); + MemoryMappedSegment segment(module_name.data(), module_name.size()); + for (uptr i = 0; Next(&segment); i++) { + const char *cur_name = segment.filename; + if (cur_name[0] == '\0') + continue; + // Don't subtract 'cur_beg' from the first entry: + // * If a binary is compiled w/o -pie, then the first entry in + // process maps is likely the binary itself (all dynamic libs + // are mapped higher in address space). For such a binary, + // instruction offset in binary coincides with the actual + // instruction address in virtual memory (as code section + // is mapped to a fixed memory range). + // * If a binary is compiled with -pie, all the modules are + // mapped high at address space (in particular, higher than + // shadow memory of the tool), so the module can't be the + // first entry. + uptr base_address = (i ? segment.start : 0) - segment.offset; + LoadedModule cur_module; + cur_module.set(cur_name, base_address); + segment.AddAddressRanges(&cur_module); + modules->push_back(cur_module); + } +} + +void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { + char *smaps = nullptr; + uptr smaps_cap = 0; + uptr smaps_len = 0; + if (!ReadFileToBuffer("/proc/self/smaps", &smaps, &smaps_cap, &smaps_len)) + return; + uptr start = 0; + bool file = false; + const char *pos = smaps; + while (pos < smaps + smaps_len) { + if (IsHex(pos[0])) { + start = ParseHex(&pos); + for (; *pos != '/' && *pos > '\n'; pos++) {} + file = *pos == '/'; + } else if (internal_strncmp(pos, "Rss:", 4) == 0) { + while (!IsDecimal(*pos)) pos++; + uptr rss = ParseDecimal(&pos) * 1024; + cb(start, rss, file, stats, stats_size); + } + while (*pos++ != '\n') {} + } + UnmapOrDie(smaps, smaps_cap); +} + +} // namespace __sanitizer + +#endif diff --git a/lib/sanitizer_common/sanitizer_procmaps_linux.cc b/lib/sanitizer_common/sanitizer_procmaps_linux.cc deleted file mode 100644 index fd5e03619bdd..000000000000 --- a/lib/sanitizer_common/sanitizer_procmaps_linux.cc +++ /dev/null @@ -1,81 +0,0 @@ -//===-- sanitizer_procmaps_linux.cc ---------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Information about the process mappings (Linux-specific parts). -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_LINUX -#include "sanitizer_common.h" -#include "sanitizer_procmaps.h" - -namespace __sanitizer { - -void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { - if (!ReadFileToBuffer("/proc/self/maps", &proc_maps->data, - &proc_maps->mmaped_size, &proc_maps->len)) { - proc_maps->data = nullptr; - proc_maps->mmaped_size = 0; - proc_maps->len = 0; - } -} - -static bool IsOneOf(char c, char c1, char c2) { - return c == c1 || c == c2; -} - -bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { - if (Error()) return false; // simulate empty maps - char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; - if (data_.current >= last) return false; - char *next_line = - (char *)internal_memchr(data_.current, '\n', last - data_.current); - if (next_line == 0) - next_line = last; - // Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar - segment->start = ParseHex(&data_.current); - CHECK_EQ(*data_.current++, '-'); - segment->end = ParseHex(&data_.current); - CHECK_EQ(*data_.current++, ' '); - CHECK(IsOneOf(*data_.current, '-', 'r')); - segment->protection = 0; - if (*data_.current++ == 'r') segment->protection |= kProtectionRead; - CHECK(IsOneOf(*data_.current, '-', 'w')); - if (*data_.current++ == 'w') segment->protection |= kProtectionWrite; - CHECK(IsOneOf(*data_.current, '-', 'x')); - if (*data_.current++ == 'x') segment->protection |= kProtectionExecute; - CHECK(IsOneOf(*data_.current, 's', 'p')); - if (*data_.current++ == 's') segment->protection |= kProtectionShared; - CHECK_EQ(*data_.current++, ' '); - segment->offset = ParseHex(&data_.current); - CHECK_EQ(*data_.current++, ' '); - ParseHex(&data_.current); - CHECK_EQ(*data_.current++, ':'); - ParseHex(&data_.current); - CHECK_EQ(*data_.current++, ' '); - while (IsDecimal(*data_.current)) data_.current++; - // Qemu may lack the trailing space. - // https://github.com/google/sanitizers/issues/160 - // CHECK_EQ(*data_.current++, ' '); - // Skip spaces. - while (data_.current < next_line && *data_.current == ' ') data_.current++; - // Fill in the filename. - if (segment->filename) { - uptr len = - Min((uptr)(next_line - data_.current), segment->filename_size - 1); - internal_strncpy(segment->filename, data_.current, len); - segment->filename[len] = 0; - } - - data_.current = next_line + 1; - return true; -} - -} // namespace __sanitizer - -#endif // SANITIZER_LINUX diff --git a/lib/sanitizer_common/sanitizer_procmaps_linux.cpp b/lib/sanitizer_common/sanitizer_procmaps_linux.cpp new file mode 100644 index 000000000000..c7af57355b91 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_procmaps_linux.cpp @@ -0,0 +1,81 @@ +//===-- sanitizer_procmaps_linux.cpp --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Information about the process mappings (Linux-specific parts). +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_LINUX +#include "sanitizer_common.h" +#include "sanitizer_procmaps.h" + +namespace __sanitizer { + +void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { + if (!ReadFileToBuffer("/proc/self/maps", &proc_maps->data, + &proc_maps->mmaped_size, &proc_maps->len)) { + proc_maps->data = nullptr; + proc_maps->mmaped_size = 0; + proc_maps->len = 0; + } +} + +static bool IsOneOf(char c, char c1, char c2) { + return c == c1 || c == c2; +} + +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { + if (Error()) return false; // simulate empty maps + char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; + if (data_.current >= last) return false; + char *next_line = + (char *)internal_memchr(data_.current, '\n', last - data_.current); + if (next_line == 0) + next_line = last; + // Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar + segment->start = ParseHex(&data_.current); + CHECK_EQ(*data_.current++, '-'); + segment->end = ParseHex(&data_.current); + CHECK_EQ(*data_.current++, ' '); + CHECK(IsOneOf(*data_.current, '-', 'r')); + segment->protection = 0; + if (*data_.current++ == 'r') segment->protection |= kProtectionRead; + CHECK(IsOneOf(*data_.current, '-', 'w')); + if (*data_.current++ == 'w') segment->protection |= kProtectionWrite; + CHECK(IsOneOf(*data_.current, '-', 'x')); + if (*data_.current++ == 'x') segment->protection |= kProtectionExecute; + CHECK(IsOneOf(*data_.current, 's', 'p')); + if (*data_.current++ == 's') segment->protection |= kProtectionShared; + CHECK_EQ(*data_.current++, ' '); + segment->offset = ParseHex(&data_.current); + CHECK_EQ(*data_.current++, ' '); + ParseHex(&data_.current); + CHECK_EQ(*data_.current++, ':'); + ParseHex(&data_.current); + CHECK_EQ(*data_.current++, ' '); + while (IsDecimal(*data_.current)) data_.current++; + // Qemu may lack the trailing space. + // https://github.com/google/sanitizers/issues/160 + // CHECK_EQ(*data_.current++, ' '); + // Skip spaces. + while (data_.current < next_line && *data_.current == ' ') data_.current++; + // Fill in the filename. + if (segment->filename) { + uptr len = + Min((uptr)(next_line - data_.current), segment->filename_size - 1); + internal_strncpy(segment->filename, data_.current, len); + segment->filename[len] = 0; + } + + data_.current = next_line + 1; + return true; +} + +} // namespace __sanitizer + +#endif // SANITIZER_LINUX diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc deleted file mode 100644 index 148910f42061..000000000000 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ /dev/null @@ -1,378 +0,0 @@ -//===-- sanitizer_procmaps_mac.cc -----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Information about the process mappings (Mac-specific parts). -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_MAC -#include "sanitizer_common.h" -#include "sanitizer_placement_new.h" -#include "sanitizer_procmaps.h" - -#include -#include -#include - -// These are not available in older macOS SDKs. -#ifndef CPU_SUBTYPE_X86_64_H -#define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) /* Haswell */ -#endif -#ifndef CPU_SUBTYPE_ARM_V7S -#define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t)11) /* Swift */ -#endif -#ifndef CPU_SUBTYPE_ARM_V7K -#define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t)12) -#endif -#ifndef CPU_TYPE_ARM64 -#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) -#endif - -namespace __sanitizer { - -// Contains information used to iterate through sections. -struct MemoryMappedSegmentData { - char name[kMaxSegName]; - uptr nsects; - const char *current_load_cmd_addr; - u32 lc_type; - uptr base_virt_addr; - uptr addr_mask; -}; - -template -static void NextSectionLoad(LoadedModule *module, MemoryMappedSegmentData *data, - bool isWritable) { - const Section *sc = (const Section *)data->current_load_cmd_addr; - data->current_load_cmd_addr += sizeof(Section); - - uptr sec_start = (sc->addr & data->addr_mask) + data->base_virt_addr; - uptr sec_end = sec_start + sc->size; - module->addAddressRange(sec_start, sec_end, /*executable=*/false, isWritable, - sc->sectname); -} - -void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { - // Don't iterate over sections when the caller hasn't set up the - // data pointer, when there are no sections, or when the segment - // is executable. Avoid iterating over executable sections because - // it will confuse libignore, and because the extra granularity - // of information is not needed by any sanitizers. - if (!data_ || !data_->nsects || IsExecutable()) { - module->addAddressRange(start, end, IsExecutable(), IsWritable(), - data_ ? data_->name : nullptr); - return; - } - - do { - if (data_->lc_type == LC_SEGMENT) { - NextSectionLoad(module, data_, IsWritable()); -#ifdef MH_MAGIC_64 - } else if (data_->lc_type == LC_SEGMENT_64) { - NextSectionLoad(module, data_, IsWritable()); -#endif - } - } while (--data_->nsects); -} - -MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { - Reset(); -} - -MemoryMappingLayout::~MemoryMappingLayout() { -} - -bool MemoryMappingLayout::Error() const { - return false; -} - -// More information about Mach-O headers can be found in mach-o/loader.h -// Each Mach-O image has a header (mach_header or mach_header_64) starting with -// a magic number, and a list of linker load commands directly following the -// header. -// A load command is at least two 32-bit words: the command type and the -// command size in bytes. We're interested only in segment load commands -// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped -// into the task's address space. -// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or -// segment_command_64 correspond to the memory address, memory size and the -// file offset of the current memory segment. -// Because these fields are taken from the images as is, one needs to add -// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime. - -void MemoryMappingLayout::Reset() { - // Count down from the top. - // TODO(glider): as per man 3 dyld, iterating over the headers with - // _dyld_image_count is thread-unsafe. We need to register callbacks for - // adding and removing images which will invalidate the MemoryMappingLayout - // state. - data_.current_image = _dyld_image_count(); - data_.current_load_cmd_count = -1; - data_.current_load_cmd_addr = 0; - data_.current_magic = 0; - data_.current_filetype = 0; - data_.current_arch = kModuleArchUnknown; - internal_memset(data_.current_uuid, 0, kModuleUUIDSize); -} - -// The dyld load address should be unchanged throughout process execution, -// and it is expensive to compute once many libraries have been loaded, -// so cache it here and do not reset. -static mach_header *dyld_hdr = 0; -static const char kDyldPath[] = "/usr/lib/dyld"; -static const int kDyldImageIdx = -1; - -// static -void MemoryMappingLayout::CacheMemoryMappings() { - // No-op on Mac for now. -} - -void MemoryMappingLayout::LoadFromCache() { - // No-op on Mac for now. -} - -// _dyld_get_image_header() and related APIs don't report dyld itself. -// We work around this by manually recursing through the memory map -// until we hit a Mach header matching dyld instead. These recurse -// calls are expensive, but the first memory map generation occurs -// early in the process, when dyld is one of the only images loaded, -// so it will be hit after only a few iterations. -static mach_header *get_dyld_image_header() { - unsigned depth = 1; - vm_size_t size = 0; - vm_address_t address = 0; - kern_return_t err = KERN_SUCCESS; - mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; - - while (true) { - struct vm_region_submap_info_64 info; - err = vm_region_recurse_64(mach_task_self(), &address, &size, &depth, - (vm_region_info_t)&info, &count); - if (err != KERN_SUCCESS) return nullptr; - - if (size >= sizeof(mach_header) && info.protection & kProtectionRead) { - mach_header *hdr = (mach_header *)address; - if ((hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) && - hdr->filetype == MH_DYLINKER) { - return hdr; - } - } - address += size; - } -} - -const mach_header *get_dyld_hdr() { - if (!dyld_hdr) dyld_hdr = get_dyld_image_header(); - - return dyld_hdr; -} - -// Next and NextSegmentLoad were inspired by base/sysinfo.cc in -// Google Perftools, https://github.com/gperftools/gperftools. - -// NextSegmentLoad scans the current image for the next segment load command -// and returns the start and end addresses and file offset of the corresponding -// segment. -// Note that the segment addresses are not necessarily sorted. -template -static bool NextSegmentLoad(MemoryMappedSegment *segment, -MemoryMappedSegmentData *seg_data, MemoryMappingLayoutData &layout_data) { - const char *lc = layout_data.current_load_cmd_addr; - layout_data.current_load_cmd_addr += ((const load_command *)lc)->cmdsize; - if (((const load_command *)lc)->cmd == kLCSegment) { - const SegmentCommand* sc = (const SegmentCommand *)lc; - uptr base_virt_addr, addr_mask; - if (layout_data.current_image == kDyldImageIdx) { - base_virt_addr = (uptr)get_dyld_hdr(); - // vmaddr is masked with 0xfffff because on macOS versions < 10.12, - // it contains an absolute address rather than an offset for dyld. - // To make matters even more complicated, this absolute address - // isn't actually the absolute segment address, but the offset portion - // of the address is accurate when combined with the dyld base address, - // and the mask will give just this offset. - addr_mask = 0xfffff; - } else { - base_virt_addr = - (uptr)_dyld_get_image_vmaddr_slide(layout_data.current_image); - addr_mask = ~0; - } - - segment->start = (sc->vmaddr & addr_mask) + base_virt_addr; - segment->end = segment->start + sc->vmsize; - // Most callers don't need section information, so only fill this struct - // when required. - if (seg_data) { - seg_data->nsects = sc->nsects; - seg_data->current_load_cmd_addr = - (const char *)lc + sizeof(SegmentCommand); - seg_data->lc_type = kLCSegment; - seg_data->base_virt_addr = base_virt_addr; - seg_data->addr_mask = addr_mask; - internal_strncpy(seg_data->name, sc->segname, - ARRAY_SIZE(seg_data->name)); - } - - // Return the initial protection. - segment->protection = sc->initprot; - segment->offset = (layout_data.current_filetype == - /*MH_EXECUTE*/ 0x2) - ? sc->vmaddr - : sc->fileoff; - if (segment->filename) { - const char *src = (layout_data.current_image == kDyldImageIdx) - ? kDyldPath - : _dyld_get_image_name(layout_data.current_image); - internal_strncpy(segment->filename, src, segment->filename_size); - } - segment->arch = layout_data.current_arch; - internal_memcpy(segment->uuid, layout_data.current_uuid, kModuleUUIDSize); - return true; - } - return false; -} - -ModuleArch ModuleArchFromCpuType(cpu_type_t cputype, cpu_subtype_t cpusubtype) { - cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK; - switch (cputype) { - case CPU_TYPE_I386: - return kModuleArchI386; - case CPU_TYPE_X86_64: - if (cpusubtype == CPU_SUBTYPE_X86_64_ALL) return kModuleArchX86_64; - if (cpusubtype == CPU_SUBTYPE_X86_64_H) return kModuleArchX86_64H; - CHECK(0 && "Invalid subtype of x86_64"); - return kModuleArchUnknown; - case CPU_TYPE_ARM: - if (cpusubtype == CPU_SUBTYPE_ARM_V6) return kModuleArchARMV6; - if (cpusubtype == CPU_SUBTYPE_ARM_V7) return kModuleArchARMV7; - if (cpusubtype == CPU_SUBTYPE_ARM_V7S) return kModuleArchARMV7S; - if (cpusubtype == CPU_SUBTYPE_ARM_V7K) return kModuleArchARMV7K; - CHECK(0 && "Invalid subtype of ARM"); - return kModuleArchUnknown; - case CPU_TYPE_ARM64: - return kModuleArchARM64; - default: - CHECK(0 && "Invalid CPU type"); - return kModuleArchUnknown; - } -} - -static const load_command *NextCommand(const load_command *lc) { - return (const load_command *)((const char *)lc + lc->cmdsize); -} - -static void FindUUID(const load_command *first_lc, u8 *uuid_output) { - for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) { - if (lc->cmd != LC_UUID) continue; - - const uuid_command *uuid_lc = (const uuid_command *)lc; - const uint8_t *uuid = &uuid_lc->uuid[0]; - internal_memcpy(uuid_output, uuid, kModuleUUIDSize); - return; - } -} - -static bool IsModuleInstrumented(const load_command *first_lc) { - for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) { - if (lc->cmd != LC_LOAD_DYLIB) continue; - - const dylib_command *dylib_lc = (const dylib_command *)lc; - uint32_t dylib_name_offset = dylib_lc->dylib.name.offset; - const char *dylib_name = ((const char *)dylib_lc) + dylib_name_offset; - dylib_name = StripModuleName(dylib_name); - if (dylib_name != 0 && (internal_strstr(dylib_name, "libclang_rt."))) { - return true; - } - } - return false; -} - -bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { - for (; data_.current_image >= kDyldImageIdx; data_.current_image--) { - const mach_header *hdr = (data_.current_image == kDyldImageIdx) - ? get_dyld_hdr() - : _dyld_get_image_header(data_.current_image); - if (!hdr) continue; - if (data_.current_load_cmd_count < 0) { - // Set up for this image; - data_.current_load_cmd_count = hdr->ncmds; - data_.current_magic = hdr->magic; - data_.current_filetype = hdr->filetype; - data_.current_arch = ModuleArchFromCpuType(hdr->cputype, hdr->cpusubtype); - switch (data_.current_magic) { -#ifdef MH_MAGIC_64 - case MH_MAGIC_64: { - data_.current_load_cmd_addr = - (const char *)hdr + sizeof(mach_header_64); - break; - } -#endif - case MH_MAGIC: { - data_.current_load_cmd_addr = (const char *)hdr + sizeof(mach_header); - break; - } - default: { - continue; - } - } - FindUUID((const load_command *)data_.current_load_cmd_addr, - data_.current_uuid); - data_.current_instrumented = IsModuleInstrumented( - (const load_command *)data_.current_load_cmd_addr); - } - - for (; data_.current_load_cmd_count >= 0; data_.current_load_cmd_count--) { - switch (data_.current_magic) { - // data_.current_magic may be only one of MH_MAGIC, MH_MAGIC_64. -#ifdef MH_MAGIC_64 - case MH_MAGIC_64: { - if (NextSegmentLoad( - segment, segment->data_, data_)) - return true; - break; - } -#endif - case MH_MAGIC: { - if (NextSegmentLoad( - segment, segment->data_, data_)) - return true; - break; - } - } - } - // If we get here, no more load_cmd's in this image talk about - // segments. Go on to the next image. - } - return false; -} - -void MemoryMappingLayout::DumpListOfModules( - InternalMmapVectorNoCtor *modules) { - Reset(); - InternalScopedString module_name(kMaxPathLength); - MemoryMappedSegment segment(module_name.data(), kMaxPathLength); - MemoryMappedSegmentData data; - segment.data_ = &data; - while (Next(&segment)) { - if (segment.filename[0] == '\0') continue; - LoadedModule *cur_module = nullptr; - if (!modules->empty() && - 0 == internal_strcmp(segment.filename, modules->back().full_name())) { - cur_module = &modules->back(); - } else { - modules->push_back(LoadedModule()); - cur_module = &modules->back(); - cur_module->set(segment.filename, segment.start, segment.arch, - segment.uuid, data_.current_instrumented); - } - segment.AddAddressRanges(cur_module); - } -} - -} // namespace __sanitizer - -#endif // SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cpp b/lib/sanitizer_common/sanitizer_procmaps_mac.cpp new file mode 100644 index 000000000000..d02afcfe87ae --- /dev/null +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cpp @@ -0,0 +1,379 @@ +//===-- sanitizer_procmaps_mac.cpp ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Information about the process mappings (Mac-specific parts). +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_MAC +#include "sanitizer_common.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_procmaps.h" + +#include +#include +#include + +// These are not available in older macOS SDKs. +#ifndef CPU_SUBTYPE_X86_64_H +#define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) /* Haswell */ +#endif +#ifndef CPU_SUBTYPE_ARM_V7S +#define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t)11) /* Swift */ +#endif +#ifndef CPU_SUBTYPE_ARM_V7K +#define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t)12) +#endif +#ifndef CPU_TYPE_ARM64 +#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) +#endif + +namespace __sanitizer { + +// Contains information used to iterate through sections. +struct MemoryMappedSegmentData { + char name[kMaxSegName]; + uptr nsects; + const char *current_load_cmd_addr; + u32 lc_type; + uptr base_virt_addr; + uptr addr_mask; +}; + +template +static void NextSectionLoad(LoadedModule *module, MemoryMappedSegmentData *data, + bool isWritable) { + const Section *sc = (const Section *)data->current_load_cmd_addr; + data->current_load_cmd_addr += sizeof(Section); + + uptr sec_start = (sc->addr & data->addr_mask) + data->base_virt_addr; + uptr sec_end = sec_start + sc->size; + module->addAddressRange(sec_start, sec_end, /*executable=*/false, isWritable, + sc->sectname); +} + +void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { + // Don't iterate over sections when the caller hasn't set up the + // data pointer, when there are no sections, or when the segment + // is executable. Avoid iterating over executable sections because + // it will confuse libignore, and because the extra granularity + // of information is not needed by any sanitizers. + if (!data_ || !data_->nsects || IsExecutable()) { + module->addAddressRange(start, end, IsExecutable(), IsWritable(), + data_ ? data_->name : nullptr); + return; + } + + do { + if (data_->lc_type == LC_SEGMENT) { + NextSectionLoad(module, data_, IsWritable()); +#ifdef MH_MAGIC_64 + } else if (data_->lc_type == LC_SEGMENT_64) { + NextSectionLoad(module, data_, IsWritable()); +#endif + } + } while (--data_->nsects); +} + +MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { + Reset(); +} + +MemoryMappingLayout::~MemoryMappingLayout() { +} + +bool MemoryMappingLayout::Error() const { + return false; +} + +// More information about Mach-O headers can be found in mach-o/loader.h +// Each Mach-O image has a header (mach_header or mach_header_64) starting with +// a magic number, and a list of linker load commands directly following the +// header. +// A load command is at least two 32-bit words: the command type and the +// command size in bytes. We're interested only in segment load commands +// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped +// into the task's address space. +// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or +// segment_command_64 correspond to the memory address, memory size and the +// file offset of the current memory segment. +// Because these fields are taken from the images as is, one needs to add +// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime. + +void MemoryMappingLayout::Reset() { + // Count down from the top. + // TODO(glider): as per man 3 dyld, iterating over the headers with + // _dyld_image_count is thread-unsafe. We need to register callbacks for + // adding and removing images which will invalidate the MemoryMappingLayout + // state. + data_.current_image = _dyld_image_count(); + data_.current_load_cmd_count = -1; + data_.current_load_cmd_addr = 0; + data_.current_magic = 0; + data_.current_filetype = 0; + data_.current_arch = kModuleArchUnknown; + internal_memset(data_.current_uuid, 0, kModuleUUIDSize); +} + +// The dyld load address should be unchanged throughout process execution, +// and it is expensive to compute once many libraries have been loaded, +// so cache it here and do not reset. +static mach_header *dyld_hdr = 0; +static const char kDyldPath[] = "/usr/lib/dyld"; +static const int kDyldImageIdx = -1; + +// static +void MemoryMappingLayout::CacheMemoryMappings() { + // No-op on Mac for now. +} + +void MemoryMappingLayout::LoadFromCache() { + // No-op on Mac for now. +} + +// _dyld_get_image_header() and related APIs don't report dyld itself. +// We work around this by manually recursing through the memory map +// until we hit a Mach header matching dyld instead. These recurse +// calls are expensive, but the first memory map generation occurs +// early in the process, when dyld is one of the only images loaded, +// so it will be hit after only a few iterations. +static mach_header *get_dyld_image_header() { + unsigned depth = 1; + vm_size_t size = 0; + vm_address_t address = 0; + kern_return_t err = KERN_SUCCESS; + mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; + + while (true) { + struct vm_region_submap_info_64 info; + err = vm_region_recurse_64(mach_task_self(), &address, &size, &depth, + (vm_region_info_t)&info, &count); + if (err != KERN_SUCCESS) return nullptr; + + if (size >= sizeof(mach_header) && info.protection & kProtectionRead) { + mach_header *hdr = (mach_header *)address; + if ((hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) && + hdr->filetype == MH_DYLINKER) { + return hdr; + } + } + address += size; + } +} + +const mach_header *get_dyld_hdr() { + if (!dyld_hdr) dyld_hdr = get_dyld_image_header(); + + return dyld_hdr; +} + +// Next and NextSegmentLoad were inspired by base/sysinfo.cc in +// Google Perftools, https://github.com/gperftools/gperftools. + +// NextSegmentLoad scans the current image for the next segment load command +// and returns the start and end addresses and file offset of the corresponding +// segment. +// Note that the segment addresses are not necessarily sorted. +template +static bool NextSegmentLoad(MemoryMappedSegment *segment, + MemoryMappedSegmentData *seg_data, + MemoryMappingLayoutData *layout_data) { + const char *lc = layout_data->current_load_cmd_addr; + layout_data->current_load_cmd_addr += ((const load_command *)lc)->cmdsize; + if (((const load_command *)lc)->cmd == kLCSegment) { + const SegmentCommand* sc = (const SegmentCommand *)lc; + uptr base_virt_addr, addr_mask; + if (layout_data->current_image == kDyldImageIdx) { + base_virt_addr = (uptr)get_dyld_hdr(); + // vmaddr is masked with 0xfffff because on macOS versions < 10.12, + // it contains an absolute address rather than an offset for dyld. + // To make matters even more complicated, this absolute address + // isn't actually the absolute segment address, but the offset portion + // of the address is accurate when combined with the dyld base address, + // and the mask will give just this offset. + addr_mask = 0xfffff; + } else { + base_virt_addr = + (uptr)_dyld_get_image_vmaddr_slide(layout_data->current_image); + addr_mask = ~0; + } + + segment->start = (sc->vmaddr & addr_mask) + base_virt_addr; + segment->end = segment->start + sc->vmsize; + // Most callers don't need section information, so only fill this struct + // when required. + if (seg_data) { + seg_data->nsects = sc->nsects; + seg_data->current_load_cmd_addr = + (const char *)lc + sizeof(SegmentCommand); + seg_data->lc_type = kLCSegment; + seg_data->base_virt_addr = base_virt_addr; + seg_data->addr_mask = addr_mask; + internal_strncpy(seg_data->name, sc->segname, + ARRAY_SIZE(seg_data->name)); + } + + // Return the initial protection. + segment->protection = sc->initprot; + segment->offset = (layout_data->current_filetype == + /*MH_EXECUTE*/ 0x2) + ? sc->vmaddr + : sc->fileoff; + if (segment->filename) { + const char *src = (layout_data->current_image == kDyldImageIdx) + ? kDyldPath + : _dyld_get_image_name(layout_data->current_image); + internal_strncpy(segment->filename, src, segment->filename_size); + } + segment->arch = layout_data->current_arch; + internal_memcpy(segment->uuid, layout_data->current_uuid, kModuleUUIDSize); + return true; + } + return false; +} + +ModuleArch ModuleArchFromCpuType(cpu_type_t cputype, cpu_subtype_t cpusubtype) { + cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK; + switch (cputype) { + case CPU_TYPE_I386: + return kModuleArchI386; + case CPU_TYPE_X86_64: + if (cpusubtype == CPU_SUBTYPE_X86_64_ALL) return kModuleArchX86_64; + if (cpusubtype == CPU_SUBTYPE_X86_64_H) return kModuleArchX86_64H; + CHECK(0 && "Invalid subtype of x86_64"); + return kModuleArchUnknown; + case CPU_TYPE_ARM: + if (cpusubtype == CPU_SUBTYPE_ARM_V6) return kModuleArchARMV6; + if (cpusubtype == CPU_SUBTYPE_ARM_V7) return kModuleArchARMV7; + if (cpusubtype == CPU_SUBTYPE_ARM_V7S) return kModuleArchARMV7S; + if (cpusubtype == CPU_SUBTYPE_ARM_V7K) return kModuleArchARMV7K; + CHECK(0 && "Invalid subtype of ARM"); + return kModuleArchUnknown; + case CPU_TYPE_ARM64: + return kModuleArchARM64; + default: + CHECK(0 && "Invalid CPU type"); + return kModuleArchUnknown; + } +} + +static const load_command *NextCommand(const load_command *lc) { + return (const load_command *)((const char *)lc + lc->cmdsize); +} + +static void FindUUID(const load_command *first_lc, u8 *uuid_output) { + for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) { + if (lc->cmd != LC_UUID) continue; + + const uuid_command *uuid_lc = (const uuid_command *)lc; + const uint8_t *uuid = &uuid_lc->uuid[0]; + internal_memcpy(uuid_output, uuid, kModuleUUIDSize); + return; + } +} + +static bool IsModuleInstrumented(const load_command *first_lc) { + for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) { + if (lc->cmd != LC_LOAD_DYLIB) continue; + + const dylib_command *dylib_lc = (const dylib_command *)lc; + uint32_t dylib_name_offset = dylib_lc->dylib.name.offset; + const char *dylib_name = ((const char *)dylib_lc) + dylib_name_offset; + dylib_name = StripModuleName(dylib_name); + if (dylib_name != 0 && (internal_strstr(dylib_name, "libclang_rt."))) { + return true; + } + } + return false; +} + +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { + for (; data_.current_image >= kDyldImageIdx; data_.current_image--) { + const mach_header *hdr = (data_.current_image == kDyldImageIdx) + ? get_dyld_hdr() + : _dyld_get_image_header(data_.current_image); + if (!hdr) continue; + if (data_.current_load_cmd_count < 0) { + // Set up for this image; + data_.current_load_cmd_count = hdr->ncmds; + data_.current_magic = hdr->magic; + data_.current_filetype = hdr->filetype; + data_.current_arch = ModuleArchFromCpuType(hdr->cputype, hdr->cpusubtype); + switch (data_.current_magic) { +#ifdef MH_MAGIC_64 + case MH_MAGIC_64: { + data_.current_load_cmd_addr = + (const char *)hdr + sizeof(mach_header_64); + break; + } +#endif + case MH_MAGIC: { + data_.current_load_cmd_addr = (const char *)hdr + sizeof(mach_header); + break; + } + default: { + continue; + } + } + FindUUID((const load_command *)data_.current_load_cmd_addr, + data_.current_uuid); + data_.current_instrumented = IsModuleInstrumented( + (const load_command *)data_.current_load_cmd_addr); + } + + for (; data_.current_load_cmd_count >= 0; data_.current_load_cmd_count--) { + switch (data_.current_magic) { + // data_.current_magic may be only one of MH_MAGIC, MH_MAGIC_64. +#ifdef MH_MAGIC_64 + case MH_MAGIC_64: { + if (NextSegmentLoad( + segment, segment->data_, &data_)) + return true; + break; + } +#endif + case MH_MAGIC: { + if (NextSegmentLoad( + segment, segment->data_, &data_)) + return true; + break; + } + } + } + // If we get here, no more load_cmd's in this image talk about + // segments. Go on to the next image. + } + return false; +} + +void MemoryMappingLayout::DumpListOfModules( + InternalMmapVectorNoCtor *modules) { + Reset(); + InternalScopedString module_name(kMaxPathLength); + MemoryMappedSegment segment(module_name.data(), kMaxPathLength); + MemoryMappedSegmentData data; + segment.data_ = &data; + while (Next(&segment)) { + if (segment.filename[0] == '\0') continue; + LoadedModule *cur_module = nullptr; + if (!modules->empty() && + 0 == internal_strcmp(segment.filename, modules->back().full_name())) { + cur_module = &modules->back(); + } else { + modules->push_back(LoadedModule()); + cur_module = &modules->back(); + cur_module->set(segment.filename, segment.start, segment.arch, + segment.uuid, data_.current_instrumented); + } + segment.AddAddressRanges(cur_module); + } +} + +} // namespace __sanitizer + +#endif // SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_procmaps_solaris.cc b/lib/sanitizer_common/sanitizer_procmaps_solaris.cc deleted file mode 100644 index b5df6fe4c41e..000000000000 --- a/lib/sanitizer_common/sanitizer_procmaps_solaris.cc +++ /dev/null @@ -1,67 +0,0 @@ -//===-- sanitizer_procmaps_solaris.cc -------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Information about the process mappings (Solaris-specific parts). -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_SOLARIS -#include "sanitizer_common.h" -#include "sanitizer_procmaps.h" - -// Before Solaris 11.4, doesn't work in a largefile environment. -#undef _FILE_OFFSET_BITS -#include -#include - -namespace __sanitizer { - -void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { - if (!ReadFileToBuffer("/proc/self/xmap", &proc_maps->data, - &proc_maps->mmaped_size, &proc_maps->len)) { - proc_maps->data = nullptr; - proc_maps->mmaped_size = 0; - proc_maps->len = 0; - } -} - -bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { - if (Error()) return false; // simulate empty maps - char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; - if (data_.current >= last) return false; - - prxmap_t *xmapentry = (prxmap_t*)data_.current; - - segment->start = (uptr)xmapentry->pr_vaddr; - segment->end = (uptr)(xmapentry->pr_vaddr + xmapentry->pr_size); - segment->offset = (uptr)xmapentry->pr_offset; - - segment->protection = 0; - if ((xmapentry->pr_mflags & MA_READ) != 0) - segment->protection |= kProtectionRead; - if ((xmapentry->pr_mflags & MA_WRITE) != 0) - segment->protection |= kProtectionWrite; - if ((xmapentry->pr_mflags & MA_EXEC) != 0) - segment->protection |= kProtectionExecute; - - if (segment->filename != NULL && segment->filename_size > 0) { - char proc_path[PATH_MAX + 1]; - - internal_snprintf(proc_path, sizeof(proc_path), "/proc/self/path/%s", - xmapentry->pr_mapname); - internal_readlink(proc_path, segment->filename, segment->filename_size); - } - - data_.current += sizeof(prxmap_t); - - return true; -} - -} // namespace __sanitizer - -#endif // SANITIZER_SOLARIS diff --git a/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp b/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp new file mode 100644 index 000000000000..8793423a6017 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp @@ -0,0 +1,67 @@ +//===-- sanitizer_procmaps_solaris.cpp ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Information about the process mappings (Solaris-specific parts). +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_SOLARIS +#include "sanitizer_common.h" +#include "sanitizer_procmaps.h" + +// Before Solaris 11.4, doesn't work in a largefile environment. +#undef _FILE_OFFSET_BITS +#include +#include + +namespace __sanitizer { + +void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { + if (!ReadFileToBuffer("/proc/self/xmap", &proc_maps->data, + &proc_maps->mmaped_size, &proc_maps->len)) { + proc_maps->data = nullptr; + proc_maps->mmaped_size = 0; + proc_maps->len = 0; + } +} + +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { + if (Error()) return false; // simulate empty maps + char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; + if (data_.current >= last) return false; + + prxmap_t *xmapentry = (prxmap_t*)data_.current; + + segment->start = (uptr)xmapentry->pr_vaddr; + segment->end = (uptr)(xmapentry->pr_vaddr + xmapentry->pr_size); + segment->offset = (uptr)xmapentry->pr_offset; + + segment->protection = 0; + if ((xmapentry->pr_mflags & MA_READ) != 0) + segment->protection |= kProtectionRead; + if ((xmapentry->pr_mflags & MA_WRITE) != 0) + segment->protection |= kProtectionWrite; + if ((xmapentry->pr_mflags & MA_EXEC) != 0) + segment->protection |= kProtectionExecute; + + if (segment->filename != NULL && segment->filename_size > 0) { + char proc_path[PATH_MAX + 1]; + + internal_snprintf(proc_path, sizeof(proc_path), "/proc/self/path/%s", + xmapentry->pr_mapname); + internal_readlink(proc_path, segment->filename, segment->filename_size); + } + + data_.current += sizeof(prxmap_t); + + return true; +} + +} // namespace __sanitizer + +#endif // SANITIZER_SOLARIS diff --git a/lib/sanitizer_common/sanitizer_rtems.cc b/lib/sanitizer_common/sanitizer_rtems.cc deleted file mode 100644 index ffc21b958b8e..000000000000 --- a/lib/sanitizer_common/sanitizer_rtems.cc +++ /dev/null @@ -1,279 +0,0 @@ -//===-- sanitizer_rtems.cc ------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between various sanitizers' runtime libraries and -// implements RTEMS-specific functions. -//===----------------------------------------------------------------------===// - -#include "sanitizer_rtems.h" -#if SANITIZER_RTEMS - -#define posix_memalign __real_posix_memalign -#define free __real_free -#define memset __real_memset - -#include "sanitizer_file.h" -#include "sanitizer_symbolizer.h" -#include -#include -#include -#include -#include -#include -#include -#include - -// There is no mmap on RTEMS. Use memalign, etc. -#define __mmap_alloc_aligned posix_memalign -#define __mmap_free free -#define __mmap_memset memset - -namespace __sanitizer { - -#include "sanitizer_syscall_generic.inc" - -void NORETURN internal__exit(int exitcode) { - _exit(exitcode); -} - -uptr internal_sched_yield() { - return sched_yield(); -} - -uptr internal_getpid() { - return getpid(); -} - -bool FileExists(const char *filename) { - struct stat st; - if (stat(filename, &st)) - return false; - // Sanity check: filename is a regular file. - return S_ISREG(st.st_mode); -} - -uptr GetThreadSelf() { return static_cast(pthread_self()); } - -tid_t GetTid() { return GetThreadSelf(); } - -void Abort() { abort(); } - -int Atexit(void (*function)(void)) { return atexit(function); } - -void SleepForSeconds(int seconds) { sleep(seconds); } - -void SleepForMillis(int millis) { usleep(millis * 1000); } - -bool SupportsColoredOutput(fd_t fd) { return false; } - -void GetThreadStackTopAndBottom(bool at_initialization, - uptr *stack_top, uptr *stack_bottom) { - pthread_attr_t attr; - pthread_attr_init(&attr); - CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); - void *base = nullptr; - size_t size = 0; - CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0); - CHECK_EQ(pthread_attr_destroy(&attr), 0); - - *stack_bottom = reinterpret_cast(base); - *stack_top = *stack_bottom + size; -} - -void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, - uptr *tls_addr, uptr *tls_size) { - uptr stack_top, stack_bottom; - GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); - *stk_addr = stack_bottom; - *stk_size = stack_top - stack_bottom; - *tls_addr = *tls_size = 0; -} - -void InitializePlatformEarly() {} -void MaybeReexec() {} -void CheckASLR() {} -void CheckMPROTECT() {} -void DisableCoreDumperIfNecessary() {} -void InstallDeadlySignalHandlers(SignalHandlerType handler) {} -void SetAlternateSignalStack() {} -void UnsetAlternateSignalStack() {} -void InitTlsSize() {} - -void PrintModuleMap() {} - -void SignalContext::DumpAllRegisters(void *context) {} -const char *DescribeSignalOrException(int signo) { UNIMPLEMENTED(); } - -enum MutexState { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 }; - -BlockingMutex::BlockingMutex() { - internal_memset(this, 0, sizeof(*this)); -} - -void BlockingMutex::Lock() { - CHECK_EQ(owner_, 0); - atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); - if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked) - return; - while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) { - internal_sched_yield(); - } -} - -void BlockingMutex::Unlock() { - atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); - u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release); - CHECK_NE(v, MtxUnlocked); -} - -void BlockingMutex::CheckLocked() { - atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); - CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed)); -} - -uptr GetPageSize() { return getpagesize(); } - -uptr GetMmapGranularity() { return GetPageSize(); } - -uptr GetMaxVirtualAddress() { - return (1ULL << 32) - 1; // 0xffffffff -} - -void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { - void* ptr = 0; - int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size); - if (UNLIKELY(res)) - ReportMmapFailureAndDie(size, mem_type, "allocate", res, raw_report); - __mmap_memset(ptr, 0, size); - IncreaseTotalMmap(size); - return ptr; -} - -void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { - void* ptr = 0; - int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size); - if (UNLIKELY(res)) { - if (res == ENOMEM) - return nullptr; - ReportMmapFailureAndDie(size, mem_type, "allocate", false); - } - __mmap_memset(ptr, 0, size); - IncreaseTotalMmap(size); - return ptr; -} - -void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, - const char *mem_type) { - CHECK(IsPowerOfTwo(size)); - CHECK(IsPowerOfTwo(alignment)); - void* ptr = 0; - int res = __mmap_alloc_aligned(&ptr, alignment, size); - if (res) - ReportMmapFailureAndDie(size, mem_type, "align allocate", res, false); - __mmap_memset(ptr, 0, size); - IncreaseTotalMmap(size); - return ptr; -} - -void *MmapNoReserveOrDie(uptr size, const char *mem_type) { - return MmapOrDie(size, mem_type, false); -} - -void UnmapOrDie(void *addr, uptr size) { - if (!addr || !size) return; - __mmap_free(addr); - DecreaseTotalMmap(size); -} - -fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) { - int flags; - switch (mode) { - case RdOnly: flags = O_RDONLY; break; - case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break; - case RdWr: flags = O_RDWR | O_CREAT; break; - } - fd_t res = open(filename, flags, 0660); - if (internal_iserror(res, errno_p)) - return kInvalidFd; - return res; -} - -void CloseFile(fd_t fd) { - close(fd); -} - -bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, - error_t *error_p) { - uptr res = read(fd, buff, buff_size); - if (internal_iserror(res, error_p)) - return false; - if (bytes_read) - *bytes_read = res; - return true; -} - -bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, - error_t *error_p) { - uptr res = write(fd, buff, buff_size); - if (internal_iserror(res, error_p)) - return false; - if (bytes_written) - *bytes_written = res; - return true; -} - -void ReleaseMemoryPagesToOS(uptr beg, uptr end) {} -void DumpProcessMap() {} - -// There is no page protection so everything is "accessible." -bool IsAccessibleMemoryRange(uptr beg, uptr size) { - return true; -} - -char **GetArgv() { return nullptr; } -char **GetEnviron() { return nullptr; } - -const char *GetEnv(const char *name) { - return getenv(name); -} - -uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { - internal_strncpy(buf, "StubBinaryName", buf_len); - return internal_strlen(buf); -} - -uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { - internal_strncpy(buf, "StubProcessName", buf_len); - return internal_strlen(buf); -} - -bool IsPathSeparator(const char c) { - return c == '/'; -} - -bool IsAbsolutePath(const char *path) { - return path != nullptr && IsPathSeparator(path[0]); -} - -void ReportFile::Write(const char *buffer, uptr length) { - SpinMutexLock l(mu); - static const char *kWriteError = - "ReportFile::Write() can't output requested buffer!\n"; - ReopenIfNecessary(); - if (length != write(fd, buffer, length)) { - write(fd, kWriteError, internal_strlen(kWriteError)); - Die(); - } -} - -uptr MainThreadStackBase, MainThreadStackSize; -uptr MainThreadTlsBase, MainThreadTlsSize; - -} // namespace __sanitizer - -#endif // SANITIZER_RTEMS diff --git a/lib/sanitizer_common/sanitizer_rtems.cpp b/lib/sanitizer_common/sanitizer_rtems.cpp new file mode 100644 index 000000000000..0d2576c00ab3 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_rtems.cpp @@ -0,0 +1,279 @@ +//===-- sanitizer_rtems.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries and +// implements RTEMS-specific functions. +//===----------------------------------------------------------------------===// + +#include "sanitizer_rtems.h" +#if SANITIZER_RTEMS + +#define posix_memalign __real_posix_memalign +#define free __real_free +#define memset __real_memset + +#include "sanitizer_file.h" +#include "sanitizer_symbolizer.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// There is no mmap on RTEMS. Use memalign, etc. +#define __mmap_alloc_aligned posix_memalign +#define __mmap_free free +#define __mmap_memset memset + +namespace __sanitizer { + +#include "sanitizer_syscall_generic.inc" + +void NORETURN internal__exit(int exitcode) { + _exit(exitcode); +} + +uptr internal_sched_yield() { + return sched_yield(); +} + +uptr internal_getpid() { + return getpid(); +} + +bool FileExists(const char *filename) { + struct stat st; + if (stat(filename, &st)) + return false; + // Sanity check: filename is a regular file. + return S_ISREG(st.st_mode); +} + +uptr GetThreadSelf() { return static_cast(pthread_self()); } + +tid_t GetTid() { return GetThreadSelf(); } + +void Abort() { abort(); } + +int Atexit(void (*function)(void)) { return atexit(function); } + +void SleepForSeconds(int seconds) { sleep(seconds); } + +void SleepForMillis(int millis) { usleep(millis * 1000); } + +bool SupportsColoredOutput(fd_t fd) { return false; } + +void GetThreadStackTopAndBottom(bool at_initialization, + uptr *stack_top, uptr *stack_bottom) { + pthread_attr_t attr; + pthread_attr_init(&attr); + CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); + void *base = nullptr; + size_t size = 0; + CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0); + CHECK_EQ(pthread_attr_destroy(&attr), 0); + + *stack_bottom = reinterpret_cast(base); + *stack_top = *stack_bottom + size; +} + +void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, + uptr *tls_addr, uptr *tls_size) { + uptr stack_top, stack_bottom; + GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); + *stk_addr = stack_bottom; + *stk_size = stack_top - stack_bottom; + *tls_addr = *tls_size = 0; +} + +void InitializePlatformEarly() {} +void MaybeReexec() {} +void CheckASLR() {} +void CheckMPROTECT() {} +void DisableCoreDumperIfNecessary() {} +void InstallDeadlySignalHandlers(SignalHandlerType handler) {} +void SetAlternateSignalStack() {} +void UnsetAlternateSignalStack() {} +void InitTlsSize() {} + +void PrintModuleMap() {} + +void SignalContext::DumpAllRegisters(void *context) {} +const char *DescribeSignalOrException(int signo) { UNIMPLEMENTED(); } + +enum MutexState { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 }; + +BlockingMutex::BlockingMutex() { + internal_memset(this, 0, sizeof(*this)); +} + +void BlockingMutex::Lock() { + CHECK_EQ(owner_, 0); + atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); + if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked) + return; + while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) { + internal_sched_yield(); + } +} + +void BlockingMutex::Unlock() { + atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); + u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release); + CHECK_NE(v, MtxUnlocked); +} + +void BlockingMutex::CheckLocked() { + atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); + CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed)); +} + +uptr GetPageSize() { return getpagesize(); } + +uptr GetMmapGranularity() { return GetPageSize(); } + +uptr GetMaxVirtualAddress() { + return (1ULL << 32) - 1; // 0xffffffff +} + +void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { + void* ptr = 0; + int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size); + if (UNLIKELY(res)) + ReportMmapFailureAndDie(size, mem_type, "allocate", res, raw_report); + __mmap_memset(ptr, 0, size); + IncreaseTotalMmap(size); + return ptr; +} + +void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { + void* ptr = 0; + int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size); + if (UNLIKELY(res)) { + if (res == ENOMEM) + return nullptr; + ReportMmapFailureAndDie(size, mem_type, "allocate", false); + } + __mmap_memset(ptr, 0, size); + IncreaseTotalMmap(size); + return ptr; +} + +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type) { + CHECK(IsPowerOfTwo(size)); + CHECK(IsPowerOfTwo(alignment)); + void* ptr = 0; + int res = __mmap_alloc_aligned(&ptr, alignment, size); + if (res) + ReportMmapFailureAndDie(size, mem_type, "align allocate", res, false); + __mmap_memset(ptr, 0, size); + IncreaseTotalMmap(size); + return ptr; +} + +void *MmapNoReserveOrDie(uptr size, const char *mem_type) { + return MmapOrDie(size, mem_type, false); +} + +void UnmapOrDie(void *addr, uptr size) { + if (!addr || !size) return; + __mmap_free(addr); + DecreaseTotalMmap(size); +} + +fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) { + int flags; + switch (mode) { + case RdOnly: flags = O_RDONLY; break; + case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break; + case RdWr: flags = O_RDWR | O_CREAT; break; + } + fd_t res = open(filename, flags, 0660); + if (internal_iserror(res, errno_p)) + return kInvalidFd; + return res; +} + +void CloseFile(fd_t fd) { + close(fd); +} + +bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, + error_t *error_p) { + uptr res = read(fd, buff, buff_size); + if (internal_iserror(res, error_p)) + return false; + if (bytes_read) + *bytes_read = res; + return true; +} + +bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, + error_t *error_p) { + uptr res = write(fd, buff, buff_size); + if (internal_iserror(res, error_p)) + return false; + if (bytes_written) + *bytes_written = res; + return true; +} + +void ReleaseMemoryPagesToOS(uptr beg, uptr end) {} +void DumpProcessMap() {} + +// There is no page protection so everything is "accessible." +bool IsAccessibleMemoryRange(uptr beg, uptr size) { + return true; +} + +char **GetArgv() { return nullptr; } +char **GetEnviron() { return nullptr; } + +const char *GetEnv(const char *name) { + return getenv(name); +} + +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { + internal_strncpy(buf, "StubBinaryName", buf_len); + return internal_strlen(buf); +} + +uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { + internal_strncpy(buf, "StubProcessName", buf_len); + return internal_strlen(buf); +} + +bool IsPathSeparator(const char c) { + return c == '/'; +} + +bool IsAbsolutePath(const char *path) { + return path != nullptr && IsPathSeparator(path[0]); +} + +void ReportFile::Write(const char *buffer, uptr length) { + SpinMutexLock l(mu); + static const char *kWriteError = + "ReportFile::Write() can't output requested buffer!\n"; + ReopenIfNecessary(); + if (length != write(fd, buffer, length)) { + write(fd, kWriteError, internal_strlen(kWriteError)); + Die(); + } +} + +uptr MainThreadStackBase, MainThreadStackSize; +uptr MainThreadTlsBase, MainThreadTlsSize; + +} // namespace __sanitizer + +#endif // SANITIZER_RTEMS diff --git a/lib/sanitizer_common/sanitizer_solaris.cc b/lib/sanitizer_common/sanitizer_solaris.cc deleted file mode 100644 index 37b50c6b243a..000000000000 --- a/lib/sanitizer_common/sanitizer_solaris.cc +++ /dev/null @@ -1,230 +0,0 @@ -//===-- sanitizer_solaris.cc ----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between various sanitizers' runtime libraries and -// implements Solaris-specific functions. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_SOLARIS - -#include - -#include "sanitizer_common.h" -#include "sanitizer_flags.h" -#include "sanitizer_internal_defs.h" -#include "sanitizer_libc.h" -#include "sanitizer_placement_new.h" -#include "sanitizer_platform_limits_posix.h" -#include "sanitizer_procmaps.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace __sanitizer { - -//#include "sanitizer_syscall_generic.inc" - -#define _REAL(func) _ ## func -#define DECLARE__REAL(ret_type, func, ...) \ - extern "C" ret_type _REAL(func)(__VA_ARGS__) -#define DECLARE__REAL_AND_INTERNAL(ret_type, func, ...) \ - DECLARE__REAL(ret_type, func, __VA_ARGS__); \ - ret_type internal_ ## func(__VA_ARGS__) - -#if !defined(_LP64) && _FILE_OFFSET_BITS == 64 -#define _REAL64(func) _ ## func ## 64 -#else -#define _REAL64(func) _REAL(func) -#endif -#define DECLARE__REAL64(ret_type, func, ...) \ - extern "C" ret_type _REAL64(func)(__VA_ARGS__) -#define DECLARE__REAL_AND_INTERNAL64(ret_type, func, ...) \ - DECLARE__REAL64(ret_type, func, __VA_ARGS__); \ - ret_type internal_ ## func(__VA_ARGS__) - -// ---------------------- sanitizer_libc.h -DECLARE__REAL_AND_INTERNAL64(uptr, mmap, void *addr, uptr /*size_t*/ length, - int prot, int flags, int fd, OFF_T offset) { - return (uptr)_REAL64(mmap)(addr, length, prot, flags, fd, offset); -} - -DECLARE__REAL_AND_INTERNAL(uptr, munmap, void *addr, uptr length) { - return _REAL(munmap)(addr, length); -} - -DECLARE__REAL_AND_INTERNAL(int, mprotect, void *addr, uptr length, int prot) { - return _REAL(mprotect)(addr, length, prot); -} - -DECLARE__REAL_AND_INTERNAL(uptr, close, fd_t fd) { - return _REAL(close)(fd); -} - -extern "C" int _REAL64(open)(const char *, int, ...); - -uptr internal_open(const char *filename, int flags) { - return _REAL64(open)(filename, flags); -} - -uptr internal_open(const char *filename, int flags, u32 mode) { - return _REAL64(open)(filename, flags, mode); -} - -DECLARE__REAL_AND_INTERNAL(uptr, read, fd_t fd, void *buf, uptr count) { - return _REAL(read)(fd, buf, count); -} - -DECLARE__REAL_AND_INTERNAL(uptr, write, fd_t fd, const void *buf, uptr count) { - return _REAL(write)(fd, buf, count); -} - -// FIXME: There's only _ftruncate64 beginning with Solaris 11. -DECLARE__REAL_AND_INTERNAL(uptr, ftruncate, fd_t fd, uptr size) { - return ftruncate(fd, size); -} - -DECLARE__REAL_AND_INTERNAL64(uptr, stat, const char *path, void *buf) { - return _REAL64(stat)(path, (struct stat *)buf); -} - -DECLARE__REAL_AND_INTERNAL64(uptr, lstat, const char *path, void *buf) { - return _REAL64(lstat)(path, (struct stat *)buf); -} - -DECLARE__REAL_AND_INTERNAL64(uptr, fstat, fd_t fd, void *buf) { - return _REAL64(fstat)(fd, (struct stat *)buf); -} - -uptr internal_filesize(fd_t fd) { - struct stat st; - if (internal_fstat(fd, &st)) - return -1; - return (uptr)st.st_size; -} - -DECLARE__REAL_AND_INTERNAL(uptr, dup, int oldfd) { - return _REAL(dup)(oldfd); -} - -DECLARE__REAL_AND_INTERNAL(uptr, dup2, int oldfd, int newfd) { - return _REAL(dup2)(oldfd, newfd); -} - -DECLARE__REAL_AND_INTERNAL(uptr, readlink, const char *path, char *buf, - uptr bufsize) { - return _REAL(readlink)(path, buf, bufsize); -} - -DECLARE__REAL_AND_INTERNAL(uptr, unlink, const char *path) { - return _REAL(unlink)(path); -} - -DECLARE__REAL_AND_INTERNAL(uptr, rename, const char *oldpath, - const char *newpath) { - return _REAL(rename)(oldpath, newpath); -} - -DECLARE__REAL_AND_INTERNAL(uptr, sched_yield, void) { - return sched_yield(); -} - -DECLARE__REAL_AND_INTERNAL(void, _exit, int exitcode) { - _exit(exitcode); -} - -DECLARE__REAL_AND_INTERNAL(uptr, execve, const char *filename, - char *const argv[], char *const envp[]) { - return _REAL(execve)(filename, argv, envp); -} - -DECLARE__REAL_AND_INTERNAL(uptr, waitpid, int pid, int *status, int options) { - return _REAL(waitpid)(pid, status, options); -} - -DECLARE__REAL_AND_INTERNAL(uptr, getpid, void) { - return _REAL(getpid)(); -} - -// FIXME: This might be wrong: _getdents doesn't take a struct linux_dirent *. -DECLARE__REAL_AND_INTERNAL64(uptr, getdents, fd_t fd, struct linux_dirent *dirp, - unsigned int count) { - return _REAL64(getdents)(fd, dirp, count); -} - -DECLARE__REAL_AND_INTERNAL64(uptr, lseek, fd_t fd, OFF_T offset, int whence) { - return _REAL64(lseek)(fd, offset, whence); -} - -// FIXME: This might be wrong: _sigfillset doesn't take a -// __sanitizer_sigset_t *. -DECLARE__REAL_AND_INTERNAL(void, sigfillset, __sanitizer_sigset_t *set) { - _REAL(sigfillset)(set); -} - -// FIXME: This might be wrong: _sigprocmask doesn't take __sanitizer_sigset_t *. -DECLARE__REAL_AND_INTERNAL(uptr, sigprocmask, int how, - __sanitizer_sigset_t *set, - __sanitizer_sigset_t *oldset) { - return _REAL(sigprocmask)(how, set, oldset); -} - -DECLARE__REAL_AND_INTERNAL(int, fork, void) { - // TODO(glider): this may call user's pthread_atfork() handlers which is bad. - return _REAL(fork)(); -} - -u64 NanoTime() { - return gethrtime(); -} - -uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { - // FIXME: No internal variant. - return clock_gettime(clk_id, (timespec *)tp); -} - -// ----------------- sanitizer_common.h -BlockingMutex::BlockingMutex() { - CHECK(sizeof(mutex_t) <= sizeof(opaque_storage_)); - internal_memset(this, 0, sizeof(*this)); - CHECK_EQ(mutex_init((mutex_t *)&opaque_storage_, USYNC_THREAD, NULL), 0); -} - -void BlockingMutex::Lock() { - CHECK(sizeof(mutex_t) <= sizeof(opaque_storage_)); - CHECK_NE(owner_, (uptr)thr_self()); - CHECK_EQ(mutex_lock((mutex_t *)&opaque_storage_), 0); - CHECK(!owner_); - owner_ = (uptr)thr_self(); -} - -void BlockingMutex::Unlock() { - CHECK(owner_ == (uptr)thr_self()); - owner_ = 0; - CHECK_EQ(mutex_unlock((mutex_t *)&opaque_storage_), 0); -} - -void BlockingMutex::CheckLocked() { - CHECK_EQ((uptr)thr_self(), owner_); -} - -} // namespace __sanitizer - -#endif // SANITIZER_SOLARIS diff --git a/lib/sanitizer_common/sanitizer_solaris.cpp b/lib/sanitizer_common/sanitizer_solaris.cpp new file mode 100644 index 000000000000..035f2d0ca292 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_solaris.cpp @@ -0,0 +1,230 @@ +//===-- sanitizer_solaris.cpp ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries and +// implements Solaris-specific functions. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_SOLARIS + +#include + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_platform_limits_posix.h" +#include "sanitizer_procmaps.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace __sanitizer { + +//#include "sanitizer_syscall_generic.inc" + +#define _REAL(func) _ ## func +#define DECLARE__REAL(ret_type, func, ...) \ + extern "C" ret_type _REAL(func)(__VA_ARGS__) +#define DECLARE__REAL_AND_INTERNAL(ret_type, func, ...) \ + DECLARE__REAL(ret_type, func, __VA_ARGS__); \ + ret_type internal_ ## func(__VA_ARGS__) + +#if !defined(_LP64) && _FILE_OFFSET_BITS == 64 +#define _REAL64(func) _ ## func ## 64 +#else +#define _REAL64(func) _REAL(func) +#endif +#define DECLARE__REAL64(ret_type, func, ...) \ + extern "C" ret_type _REAL64(func)(__VA_ARGS__) +#define DECLARE__REAL_AND_INTERNAL64(ret_type, func, ...) \ + DECLARE__REAL64(ret_type, func, __VA_ARGS__); \ + ret_type internal_ ## func(__VA_ARGS__) + +// ---------------------- sanitizer_libc.h +DECLARE__REAL_AND_INTERNAL64(uptr, mmap, void *addr, uptr /*size_t*/ length, + int prot, int flags, int fd, OFF_T offset) { + return (uptr)_REAL64(mmap)(addr, length, prot, flags, fd, offset); +} + +DECLARE__REAL_AND_INTERNAL(uptr, munmap, void *addr, uptr length) { + return _REAL(munmap)(addr, length); +} + +DECLARE__REAL_AND_INTERNAL(int, mprotect, void *addr, uptr length, int prot) { + return _REAL(mprotect)(addr, length, prot); +} + +DECLARE__REAL_AND_INTERNAL(uptr, close, fd_t fd) { + return _REAL(close)(fd); +} + +extern "C" int _REAL64(open)(const char *, int, ...); + +uptr internal_open(const char *filename, int flags) { + return _REAL64(open)(filename, flags); +} + +uptr internal_open(const char *filename, int flags, u32 mode) { + return _REAL64(open)(filename, flags, mode); +} + +DECLARE__REAL_AND_INTERNAL(uptr, read, fd_t fd, void *buf, uptr count) { + return _REAL(read)(fd, buf, count); +} + +DECLARE__REAL_AND_INTERNAL(uptr, write, fd_t fd, const void *buf, uptr count) { + return _REAL(write)(fd, buf, count); +} + +// FIXME: There's only _ftruncate64 beginning with Solaris 11. +DECLARE__REAL_AND_INTERNAL(uptr, ftruncate, fd_t fd, uptr size) { + return ftruncate(fd, size); +} + +DECLARE__REAL_AND_INTERNAL64(uptr, stat, const char *path, void *buf) { + return _REAL64(stat)(path, (struct stat *)buf); +} + +DECLARE__REAL_AND_INTERNAL64(uptr, lstat, const char *path, void *buf) { + return _REAL64(lstat)(path, (struct stat *)buf); +} + +DECLARE__REAL_AND_INTERNAL64(uptr, fstat, fd_t fd, void *buf) { + return _REAL64(fstat)(fd, (struct stat *)buf); +} + +uptr internal_filesize(fd_t fd) { + struct stat st; + if (internal_fstat(fd, &st)) + return -1; + return (uptr)st.st_size; +} + +DECLARE__REAL_AND_INTERNAL(uptr, dup, int oldfd) { + return _REAL(dup)(oldfd); +} + +DECLARE__REAL_AND_INTERNAL(uptr, dup2, int oldfd, int newfd) { + return _REAL(dup2)(oldfd, newfd); +} + +DECLARE__REAL_AND_INTERNAL(uptr, readlink, const char *path, char *buf, + uptr bufsize) { + return _REAL(readlink)(path, buf, bufsize); +} + +DECLARE__REAL_AND_INTERNAL(uptr, unlink, const char *path) { + return _REAL(unlink)(path); +} + +DECLARE__REAL_AND_INTERNAL(uptr, rename, const char *oldpath, + const char *newpath) { + return _REAL(rename)(oldpath, newpath); +} + +DECLARE__REAL_AND_INTERNAL(uptr, sched_yield, void) { + return sched_yield(); +} + +DECLARE__REAL_AND_INTERNAL(void, _exit, int exitcode) { + _exit(exitcode); +} + +DECLARE__REAL_AND_INTERNAL(uptr, execve, const char *filename, + char *const argv[], char *const envp[]) { + return _REAL(execve)(filename, argv, envp); +} + +DECLARE__REAL_AND_INTERNAL(uptr, waitpid, int pid, int *status, int options) { + return _REAL(waitpid)(pid, status, options); +} + +DECLARE__REAL_AND_INTERNAL(uptr, getpid, void) { + return _REAL(getpid)(); +} + +// FIXME: This might be wrong: _getdents doesn't take a struct linux_dirent *. +DECLARE__REAL_AND_INTERNAL64(uptr, getdents, fd_t fd, struct linux_dirent *dirp, + unsigned int count) { + return _REAL64(getdents)(fd, dirp, count); +} + +DECLARE__REAL_AND_INTERNAL64(uptr, lseek, fd_t fd, OFF_T offset, int whence) { + return _REAL64(lseek)(fd, offset, whence); +} + +// FIXME: This might be wrong: _sigfillset doesn't take a +// __sanitizer_sigset_t *. +DECLARE__REAL_AND_INTERNAL(void, sigfillset, __sanitizer_sigset_t *set) { + _REAL(sigfillset)(set); +} + +// FIXME: This might be wrong: _sigprocmask doesn't take __sanitizer_sigset_t *. +DECLARE__REAL_AND_INTERNAL(uptr, sigprocmask, int how, + __sanitizer_sigset_t *set, + __sanitizer_sigset_t *oldset) { + return _REAL(sigprocmask)(how, set, oldset); +} + +DECLARE__REAL_AND_INTERNAL(int, fork, void) { + // TODO(glider): this may call user's pthread_atfork() handlers which is bad. + return _REAL(fork)(); +} + +u64 NanoTime() { + return gethrtime(); +} + +uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { + // FIXME: No internal variant. + return clock_gettime(clk_id, (timespec *)tp); +} + +// ----------------- sanitizer_common.h +BlockingMutex::BlockingMutex() { + CHECK(sizeof(mutex_t) <= sizeof(opaque_storage_)); + internal_memset(this, 0, sizeof(*this)); + CHECK_EQ(mutex_init((mutex_t *)&opaque_storage_, USYNC_THREAD, NULL), 0); +} + +void BlockingMutex::Lock() { + CHECK(sizeof(mutex_t) <= sizeof(opaque_storage_)); + CHECK_NE(owner_, (uptr)thr_self()); + CHECK_EQ(mutex_lock((mutex_t *)&opaque_storage_), 0); + CHECK(!owner_); + owner_ = (uptr)thr_self(); +} + +void BlockingMutex::Unlock() { + CHECK(owner_ == (uptr)thr_self()); + owner_ = 0; + CHECK_EQ(mutex_unlock((mutex_t *)&opaque_storage_), 0); +} + +void BlockingMutex::CheckLocked() { + CHECK_EQ((uptr)thr_self(), owner_); +} + +} // namespace __sanitizer + +#endif // SANITIZER_SOLARIS diff --git a/lib/sanitizer_common/sanitizer_stackdepot.cc b/lib/sanitizer_common/sanitizer_stackdepot.cc deleted file mode 100644 index 1cdedfa32fbe..000000000000 --- a/lib/sanitizer_common/sanitizer_stackdepot.cc +++ /dev/null @@ -1,149 +0,0 @@ -//===-- sanitizer_stackdepot.cc -------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. -//===----------------------------------------------------------------------===// - -#include "sanitizer_stackdepot.h" - -#include "sanitizer_common.h" -#include "sanitizer_hash.h" -#include "sanitizer_stackdepotbase.h" - -namespace __sanitizer { - -struct StackDepotNode { - StackDepotNode *link; - u32 id; - atomic_uint32_t hash_and_use_count; // hash_bits : 12; use_count : 20; - u32 size; - u32 tag; - uptr stack[1]; // [size] - - static const u32 kTabSizeLog = SANITIZER_ANDROID ? 16 : 20; - // Lower kTabSizeLog bits are equal for all items in one bucket. - // We use these bits to store the per-stack use counter. - static const u32 kUseCountBits = kTabSizeLog; - static const u32 kMaxUseCount = 1 << kUseCountBits; - static const u32 kUseCountMask = (1 << kUseCountBits) - 1; - static const u32 kHashMask = ~kUseCountMask; - - typedef StackTrace args_type; - bool eq(u32 hash, const args_type &args) const { - u32 hash_bits = - atomic_load(&hash_and_use_count, memory_order_relaxed) & kHashMask; - if ((hash & kHashMask) != hash_bits || args.size != size || args.tag != tag) - return false; - uptr i = 0; - for (; i < size; i++) { - if (stack[i] != args.trace[i]) return false; - } - return true; - } - static uptr storage_size(const args_type &args) { - return sizeof(StackDepotNode) + (args.size - 1) * sizeof(uptr); - } - static u32 hash(const args_type &args) { - MurMur2HashBuilder H(args.size * sizeof(uptr)); - for (uptr i = 0; i < args.size; i++) H.add(args.trace[i]); - return H.get(); - } - static bool is_valid(const args_type &args) { - return args.size > 0 && args.trace; - } - void store(const args_type &args, u32 hash) { - atomic_store(&hash_and_use_count, hash & kHashMask, memory_order_relaxed); - size = args.size; - tag = args.tag; - internal_memcpy(stack, args.trace, size * sizeof(uptr)); - } - args_type load() const { - return args_type(&stack[0], size, tag); - } - StackDepotHandle get_handle() { return StackDepotHandle(this); } - - typedef StackDepotHandle handle_type; -}; - -COMPILER_CHECK(StackDepotNode::kMaxUseCount == (u32)kStackDepotMaxUseCount); - -u32 StackDepotHandle::id() { return node_->id; } -int StackDepotHandle::use_count() { - return atomic_load(&node_->hash_and_use_count, memory_order_relaxed) & - StackDepotNode::kUseCountMask; -} -void StackDepotHandle::inc_use_count_unsafe() { - u32 prev = - atomic_fetch_add(&node_->hash_and_use_count, 1, memory_order_relaxed) & - StackDepotNode::kUseCountMask; - CHECK_LT(prev + 1, StackDepotNode::kMaxUseCount); -} - -// FIXME(dvyukov): this single reserved bit is used in TSan. -typedef StackDepotBase - StackDepot; -static StackDepot theDepot; - -StackDepotStats *StackDepotGetStats() { - return theDepot.GetStats(); -} - -u32 StackDepotPut(StackTrace stack) { - StackDepotHandle h = theDepot.Put(stack); - return h.valid() ? h.id() : 0; -} - -StackDepotHandle StackDepotPut_WithHandle(StackTrace stack) { - return theDepot.Put(stack); -} - -StackTrace StackDepotGet(u32 id) { - return theDepot.Get(id); -} - -void StackDepotLockAll() { - theDepot.LockAll(); -} - -void StackDepotUnlockAll() { - theDepot.UnlockAll(); -} - -bool StackDepotReverseMap::IdDescPair::IdComparator( - const StackDepotReverseMap::IdDescPair &a, - const StackDepotReverseMap::IdDescPair &b) { - return a.id < b.id; -} - -StackDepotReverseMap::StackDepotReverseMap() { - map_.reserve(StackDepotGetStats()->n_uniq_ids + 100); - for (int idx = 0; idx < StackDepot::kTabSize; idx++) { - atomic_uintptr_t *p = &theDepot.tab[idx]; - uptr v = atomic_load(p, memory_order_consume); - StackDepotNode *s = (StackDepotNode*)(v & ~1); - for (; s; s = s->link) { - IdDescPair pair = {s->id, s}; - map_.push_back(pair); - } - } - Sort(map_.data(), map_.size(), &IdDescPair::IdComparator); -} - -StackTrace StackDepotReverseMap::Get(u32 id) { - if (!map_.size()) - return StackTrace(); - IdDescPair pair = {id, nullptr}; - uptr idx = - InternalLowerBound(map_, 0, map_.size(), pair, IdDescPair::IdComparator); - if (idx > map_.size() || map_[idx].id != id) - return StackTrace(); - return map_[idx].desc->load(); -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_stackdepot.cpp b/lib/sanitizer_common/sanitizer_stackdepot.cpp new file mode 100644 index 000000000000..30073a96ceeb --- /dev/null +++ b/lib/sanitizer_common/sanitizer_stackdepot.cpp @@ -0,0 +1,149 @@ +//===-- sanitizer_stackdepot.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#include "sanitizer_stackdepot.h" + +#include "sanitizer_common.h" +#include "sanitizer_hash.h" +#include "sanitizer_stackdepotbase.h" + +namespace __sanitizer { + +struct StackDepotNode { + StackDepotNode *link; + u32 id; + atomic_uint32_t hash_and_use_count; // hash_bits : 12; use_count : 20; + u32 size; + u32 tag; + uptr stack[1]; // [size] + + static const u32 kTabSizeLog = SANITIZER_ANDROID ? 16 : 20; + // Lower kTabSizeLog bits are equal for all items in one bucket. + // We use these bits to store the per-stack use counter. + static const u32 kUseCountBits = kTabSizeLog; + static const u32 kMaxUseCount = 1 << kUseCountBits; + static const u32 kUseCountMask = (1 << kUseCountBits) - 1; + static const u32 kHashMask = ~kUseCountMask; + + typedef StackTrace args_type; + bool eq(u32 hash, const args_type &args) const { + u32 hash_bits = + atomic_load(&hash_and_use_count, memory_order_relaxed) & kHashMask; + if ((hash & kHashMask) != hash_bits || args.size != size || args.tag != tag) + return false; + uptr i = 0; + for (; i < size; i++) { + if (stack[i] != args.trace[i]) return false; + } + return true; + } + static uptr storage_size(const args_type &args) { + return sizeof(StackDepotNode) + (args.size - 1) * sizeof(uptr); + } + static u32 hash(const args_type &args) { + MurMur2HashBuilder H(args.size * sizeof(uptr)); + for (uptr i = 0; i < args.size; i++) H.add(args.trace[i]); + return H.get(); + } + static bool is_valid(const args_type &args) { + return args.size > 0 && args.trace; + } + void store(const args_type &args, u32 hash) { + atomic_store(&hash_and_use_count, hash & kHashMask, memory_order_relaxed); + size = args.size; + tag = args.tag; + internal_memcpy(stack, args.trace, size * sizeof(uptr)); + } + args_type load() const { + return args_type(&stack[0], size, tag); + } + StackDepotHandle get_handle() { return StackDepotHandle(this); } + + typedef StackDepotHandle handle_type; +}; + +COMPILER_CHECK(StackDepotNode::kMaxUseCount == (u32)kStackDepotMaxUseCount); + +u32 StackDepotHandle::id() { return node_->id; } +int StackDepotHandle::use_count() { + return atomic_load(&node_->hash_and_use_count, memory_order_relaxed) & + StackDepotNode::kUseCountMask; +} +void StackDepotHandle::inc_use_count_unsafe() { + u32 prev = + atomic_fetch_add(&node_->hash_and_use_count, 1, memory_order_relaxed) & + StackDepotNode::kUseCountMask; + CHECK_LT(prev + 1, StackDepotNode::kMaxUseCount); +} + +// FIXME(dvyukov): this single reserved bit is used in TSan. +typedef StackDepotBase + StackDepot; +static StackDepot theDepot; + +StackDepotStats *StackDepotGetStats() { + return theDepot.GetStats(); +} + +u32 StackDepotPut(StackTrace stack) { + StackDepotHandle h = theDepot.Put(stack); + return h.valid() ? h.id() : 0; +} + +StackDepotHandle StackDepotPut_WithHandle(StackTrace stack) { + return theDepot.Put(stack); +} + +StackTrace StackDepotGet(u32 id) { + return theDepot.Get(id); +} + +void StackDepotLockAll() { + theDepot.LockAll(); +} + +void StackDepotUnlockAll() { + theDepot.UnlockAll(); +} + +bool StackDepotReverseMap::IdDescPair::IdComparator( + const StackDepotReverseMap::IdDescPair &a, + const StackDepotReverseMap::IdDescPair &b) { + return a.id < b.id; +} + +StackDepotReverseMap::StackDepotReverseMap() { + map_.reserve(StackDepotGetStats()->n_uniq_ids + 100); + for (int idx = 0; idx < StackDepot::kTabSize; idx++) { + atomic_uintptr_t *p = &theDepot.tab[idx]; + uptr v = atomic_load(p, memory_order_consume); + StackDepotNode *s = (StackDepotNode*)(v & ~1); + for (; s; s = s->link) { + IdDescPair pair = {s->id, s}; + map_.push_back(pair); + } + } + Sort(map_.data(), map_.size(), &IdDescPair::IdComparator); +} + +StackTrace StackDepotReverseMap::Get(u32 id) { + if (!map_.size()) + return StackTrace(); + IdDescPair pair = {id, nullptr}; + uptr idx = + InternalLowerBound(map_, 0, map_.size(), pair, IdDescPair::IdComparator); + if (idx > map_.size() || map_[idx].id != id) + return StackTrace(); + return map_[idx].desc->load(); +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_stacktrace.cc b/lib/sanitizer_common/sanitizer_stacktrace.cc deleted file mode 100644 index 26474037ff35..000000000000 --- a/lib/sanitizer_common/sanitizer_stacktrace.cc +++ /dev/null @@ -1,133 +0,0 @@ -//===-- sanitizer_stacktrace.cc -------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. -//===----------------------------------------------------------------------===// - -#include "sanitizer_common.h" -#include "sanitizer_flags.h" -#include "sanitizer_stacktrace.h" - -namespace __sanitizer { - -uptr StackTrace::GetNextInstructionPc(uptr pc) { -#if defined(__sparc__) || defined(__mips__) - return pc + 8; -#elif defined(__powerpc__) || defined(__arm__) || defined(__aarch64__) - return pc + 4; -#else - return pc + 1; -#endif -} - -uptr StackTrace::GetCurrentPc() { - return GET_CALLER_PC(); -} - -void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) { - size = cnt + !!extra_top_pc; - CHECK_LE(size, kStackTraceMax); - internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0])); - if (extra_top_pc) - trace_buffer[cnt] = extra_top_pc; - top_frame_bp = 0; -} - -// Sparc implemention is in its own file. -#if !defined(__sparc__) - -// In GCC on ARM bp points to saved lr, not fp, so we should check the next -// cell in stack to be a saved frame pointer. GetCanonicFrame returns the -// pointer to saved frame pointer in any case. -static inline uhwptr *GetCanonicFrame(uptr bp, - uptr stack_top, - uptr stack_bottom) { - CHECK_GT(stack_top, stack_bottom); -#ifdef __arm__ - if (!IsValidFrame(bp, stack_top, stack_bottom)) return 0; - uhwptr *bp_prev = (uhwptr *)bp; - if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) return bp_prev; - // The next frame pointer does not look right. This could be a GCC frame, step - // back by 1 word and try again. - if (IsValidFrame((uptr)bp_prev[-1], stack_top, stack_bottom)) - return bp_prev - 1; - // Nope, this does not look right either. This means the frame after next does - // not have a valid frame pointer, but we can still extract the caller PC. - // Unfortunately, there is no way to decide between GCC and LLVM frame - // layouts. Assume LLVM. - return bp_prev; -#else - return (uhwptr*)bp; -#endif -} - -void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top, - uptr stack_bottom, u32 max_depth) { - // TODO(yln): add arg sanity check for stack_top/stack_bottom - CHECK_GE(max_depth, 2); - const uptr kPageSize = GetPageSizeCached(); - trace_buffer[0] = pc; - size = 1; - if (stack_top < 4096) return; // Sanity check for stack top. - uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom); - // Lowest possible address that makes sense as the next frame pointer. - // Goes up as we walk the stack. - uptr bottom = stack_bottom; - // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. - while (IsValidFrame((uptr)frame, stack_top, bottom) && - IsAligned((uptr)frame, sizeof(*frame)) && - size < max_depth) { -#ifdef __powerpc__ - // PowerPC ABIs specify that the return address is saved at offset - // 16 of the *caller's* stack frame. Thus we must dereference the - // back chain to find the caller frame before extracting it. - uhwptr *caller_frame = (uhwptr*)frame[0]; - if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) || - !IsAligned((uptr)caller_frame, sizeof(uhwptr))) - break; - uhwptr pc1 = caller_frame[2]; -#elif defined(__s390__) - uhwptr pc1 = frame[14]; -#else - uhwptr pc1 = frame[1]; -#endif - // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and - // x86_64) is invalid and stop unwinding here. If we're adding support for - // a platform where this isn't true, we need to reconsider this check. - if (pc1 < kPageSize) - break; - if (pc1 != pc) { - trace_buffer[size++] = (uptr) pc1; - } - bottom = (uptr)frame; - frame = GetCanonicFrame((uptr)frame[0], stack_top, bottom); - } -} - -#endif // !defined(__sparc__) - -void BufferedStackTrace::PopStackFrames(uptr count) { - CHECK_LT(count, size); - size -= count; - for (uptr i = 0; i < size; ++i) { - trace_buffer[i] = trace_buffer[i + count]; - } -} - -static uptr Distance(uptr a, uptr b) { return a < b ? b - a : a - b; } - -uptr BufferedStackTrace::LocatePcInTrace(uptr pc) { - uptr best = 0; - for (uptr i = 1; i < size; ++i) { - if (Distance(trace[i], pc) < Distance(trace[best], pc)) best = i; - } - return best; -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_stacktrace.cpp b/lib/sanitizer_common/sanitizer_stacktrace.cpp new file mode 100644 index 000000000000..ef14fb704eed --- /dev/null +++ b/lib/sanitizer_common/sanitizer_stacktrace.cpp @@ -0,0 +1,133 @@ +//===-- sanitizer_stacktrace.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_stacktrace.h" + +namespace __sanitizer { + +uptr StackTrace::GetNextInstructionPc(uptr pc) { +#if defined(__sparc__) || defined(__mips__) + return pc + 8; +#elif defined(__powerpc__) || defined(__arm__) || defined(__aarch64__) + return pc + 4; +#else + return pc + 1; +#endif +} + +uptr StackTrace::GetCurrentPc() { + return GET_CALLER_PC(); +} + +void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) { + size = cnt + !!extra_top_pc; + CHECK_LE(size, kStackTraceMax); + internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0])); + if (extra_top_pc) + trace_buffer[cnt] = extra_top_pc; + top_frame_bp = 0; +} + +// Sparc implemention is in its own file. +#if !defined(__sparc__) + +// In GCC on ARM bp points to saved lr, not fp, so we should check the next +// cell in stack to be a saved frame pointer. GetCanonicFrame returns the +// pointer to saved frame pointer in any case. +static inline uhwptr *GetCanonicFrame(uptr bp, + uptr stack_top, + uptr stack_bottom) { + CHECK_GT(stack_top, stack_bottom); +#ifdef __arm__ + if (!IsValidFrame(bp, stack_top, stack_bottom)) return 0; + uhwptr *bp_prev = (uhwptr *)bp; + if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) return bp_prev; + // The next frame pointer does not look right. This could be a GCC frame, step + // back by 1 word and try again. + if (IsValidFrame((uptr)bp_prev[-1], stack_top, stack_bottom)) + return bp_prev - 1; + // Nope, this does not look right either. This means the frame after next does + // not have a valid frame pointer, but we can still extract the caller PC. + // Unfortunately, there is no way to decide between GCC and LLVM frame + // layouts. Assume LLVM. + return bp_prev; +#else + return (uhwptr*)bp; +#endif +} + +void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top, + uptr stack_bottom, u32 max_depth) { + // TODO(yln): add arg sanity check for stack_top/stack_bottom + CHECK_GE(max_depth, 2); + const uptr kPageSize = GetPageSizeCached(); + trace_buffer[0] = pc; + size = 1; + if (stack_top < 4096) return; // Sanity check for stack top. + uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom); + // Lowest possible address that makes sense as the next frame pointer. + // Goes up as we walk the stack. + uptr bottom = stack_bottom; + // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. + while (IsValidFrame((uptr)frame, stack_top, bottom) && + IsAligned((uptr)frame, sizeof(*frame)) && + size < max_depth) { +#ifdef __powerpc__ + // PowerPC ABIs specify that the return address is saved at offset + // 16 of the *caller's* stack frame. Thus we must dereference the + // back chain to find the caller frame before extracting it. + uhwptr *caller_frame = (uhwptr*)frame[0]; + if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) || + !IsAligned((uptr)caller_frame, sizeof(uhwptr))) + break; + uhwptr pc1 = caller_frame[2]; +#elif defined(__s390__) + uhwptr pc1 = frame[14]; +#else + uhwptr pc1 = frame[1]; +#endif + // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and + // x86_64) is invalid and stop unwinding here. If we're adding support for + // a platform where this isn't true, we need to reconsider this check. + if (pc1 < kPageSize) + break; + if (pc1 != pc) { + trace_buffer[size++] = (uptr) pc1; + } + bottom = (uptr)frame; + frame = GetCanonicFrame((uptr)frame[0], stack_top, bottom); + } +} + +#endif // !defined(__sparc__) + +void BufferedStackTrace::PopStackFrames(uptr count) { + CHECK_LT(count, size); + size -= count; + for (uptr i = 0; i < size; ++i) { + trace_buffer[i] = trace_buffer[i + count]; + } +} + +static uptr Distance(uptr a, uptr b) { return a < b ? b - a : a - b; } + +uptr BufferedStackTrace::LocatePcInTrace(uptr pc) { + uptr best = 0; + for (uptr i = 1; i < size; ++i) { + if (Distance(trace[i], pc) < Distance(trace[best], pc)) best = i; + } + return best; +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc deleted file mode 100644 index 859032ba84e1..000000000000 --- a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc +++ /dev/null @@ -1,158 +0,0 @@ -//===-- sanitizer_stacktrace_libcdep.cc -----------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. -//===----------------------------------------------------------------------===// - -#include "sanitizer_common.h" -#include "sanitizer_placement_new.h" -#include "sanitizer_stacktrace.h" -#include "sanitizer_stacktrace_printer.h" -#include "sanitizer_symbolizer.h" - -namespace __sanitizer { - -void StackTrace::Print() const { - if (trace == nullptr || size == 0) { - Printf(" \n\n"); - return; - } - InternalScopedString frame_desc(GetPageSizeCached() * 2); - InternalScopedString dedup_token(GetPageSizeCached()); - int dedup_frames = common_flags()->dedup_token_length; - uptr frame_num = 0; - for (uptr i = 0; i < size && trace[i]; i++) { - // PCs in stack traces are actually the return addresses, that is, - // addresses of the next instructions after the call. - uptr pc = GetPreviousInstructionPc(trace[i]); - SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc); - CHECK(frames); - for (SymbolizedStack *cur = frames; cur; cur = cur->next) { - frame_desc.clear(); - RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++, - cur->info, common_flags()->symbolize_vs_style, - common_flags()->strip_path_prefix); - Printf("%s\n", frame_desc.data()); - if (dedup_frames-- > 0) { - if (dedup_token.length()) - dedup_token.append("--"); - if (cur->info.function != nullptr) - dedup_token.append(cur->info.function); - } - } - frames->ClearAll(); - } - // Always print a trailing empty line after stack trace. - Printf("\n"); - if (dedup_token.length()) - Printf("DEDUP_TOKEN: %s\n", dedup_token.data()); -} - -void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context, - uptr stack_top, uptr stack_bottom, - bool request_fast_unwind) { - // Ensures all call sites get what they requested. - CHECK_EQ(request_fast_unwind, WillUseFastUnwind(request_fast_unwind)); - top_frame_bp = (max_depth > 0) ? bp : 0; - // Avoid doing any work for small max_depth. - if (max_depth == 0) { - size = 0; - return; - } - if (max_depth == 1) { - size = 1; - trace_buffer[0] = pc; - return; - } - if (!WillUseFastUnwind(request_fast_unwind)) { -#if SANITIZER_CAN_SLOW_UNWIND - if (context) - UnwindSlow(pc, context, max_depth); - else - UnwindSlow(pc, max_depth); -#else - UNREACHABLE("slow unwind requested but not available"); -#endif - } else { - UnwindFast(pc, bp, stack_top, stack_bottom, max_depth); - } -} - -static int GetModuleAndOffsetForPc(uptr pc, char *module_name, - uptr module_name_len, uptr *pc_offset) { - const char *found_module_name = nullptr; - bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC( - pc, &found_module_name, pc_offset); - - if (!ok) return false; - - if (module_name && module_name_len) { - internal_strncpy(module_name, found_module_name, module_name_len); - module_name[module_name_len - 1] = '\x00'; - } - return true; -} - -} // namespace __sanitizer -using namespace __sanitizer; - -extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf, - uptr out_buf_size) { - if (!out_buf_size) return; - pc = StackTrace::GetPreviousInstructionPc(pc); - SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); - if (!frame) { - internal_strncpy(out_buf, "", out_buf_size); - out_buf[out_buf_size - 1] = 0; - return; - } - InternalScopedString frame_desc(GetPageSizeCached()); - uptr frame_num = 0; - // Reserve one byte for the final 0. - char *out_end = out_buf + out_buf_size - 1; - for (SymbolizedStack *cur = frame; cur && out_buf < out_end; - cur = cur->next) { - frame_desc.clear(); - RenderFrame(&frame_desc, fmt, frame_num++, cur->info, - common_flags()->symbolize_vs_style, - common_flags()->strip_path_prefix); - if (!frame_desc.length()) - continue; - // Reserve one byte for the terminating 0. - uptr n = out_end - out_buf - 1; - internal_strncpy(out_buf, frame_desc.data(), n); - out_buf += __sanitizer::Min(n, frame_desc.length()); - *out_buf++ = 0; - } - CHECK(out_buf <= out_end); - *out_buf = 0; -} - -SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_symbolize_global(uptr data_addr, const char *fmt, - char *out_buf, uptr out_buf_size) { - if (!out_buf_size) return; - out_buf[0] = 0; - DataInfo DI; - if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return; - InternalScopedString data_desc(GetPageSizeCached()); - RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix); - internal_strncpy(out_buf, data_desc.data(), out_buf_size); - out_buf[out_buf_size - 1] = 0; -} - -SANITIZER_INTERFACE_ATTRIBUTE -int __sanitizer_get_module_and_offset_for_pc( // NOLINT - uptr pc, char *module_name, uptr module_name_len, uptr *pc_offset) { - return __sanitizer::GetModuleAndOffsetForPc(pc, module_name, module_name_len, - pc_offset); -} -} // extern "C" diff --git a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp new file mode 100644 index 000000000000..4ef305cf1799 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp @@ -0,0 +1,159 @@ +//===-- sanitizer_stacktrace_libcdep.cpp ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_stacktrace.h" +#include "sanitizer_stacktrace_printer.h" +#include "sanitizer_symbolizer.h" + +namespace __sanitizer { + +void StackTrace::Print() const { + if (trace == nullptr || size == 0) { + Printf(" \n\n"); + return; + } + InternalScopedString frame_desc(GetPageSizeCached() * 2); + InternalScopedString dedup_token(GetPageSizeCached()); + int dedup_frames = common_flags()->dedup_token_length; + uptr frame_num = 0; + for (uptr i = 0; i < size && trace[i]; i++) { + // PCs in stack traces are actually the return addresses, that is, + // addresses of the next instructions after the call. + uptr pc = GetPreviousInstructionPc(trace[i]); + SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc); + CHECK(frames); + for (SymbolizedStack *cur = frames; cur; cur = cur->next) { + frame_desc.clear(); + RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++, + cur->info, common_flags()->symbolize_vs_style, + common_flags()->strip_path_prefix); + Printf("%s\n", frame_desc.data()); + if (dedup_frames-- > 0) { + if (dedup_token.length()) + dedup_token.append("--"); + if (cur->info.function != nullptr) + dedup_token.append(cur->info.function); + } + } + frames->ClearAll(); + } + // Always print a trailing empty line after stack trace. + Printf("\n"); + if (dedup_token.length()) + Printf("DEDUP_TOKEN: %s\n", dedup_token.data()); +} + +void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context, + uptr stack_top, uptr stack_bottom, + bool request_fast_unwind) { + // Ensures all call sites get what they requested. + CHECK_EQ(request_fast_unwind, WillUseFastUnwind(request_fast_unwind)); + top_frame_bp = (max_depth > 0) ? bp : 0; + // Avoid doing any work for small max_depth. + if (max_depth == 0) { + size = 0; + return; + } + if (max_depth == 1) { + size = 1; + trace_buffer[0] = pc; + return; + } + if (!WillUseFastUnwind(request_fast_unwind)) { +#if SANITIZER_CAN_SLOW_UNWIND + if (context) + UnwindSlow(pc, context, max_depth); + else + UnwindSlow(pc, max_depth); +#else + UNREACHABLE("slow unwind requested but not available"); +#endif + } else { + UnwindFast(pc, bp, stack_top, stack_bottom, max_depth); + } +} + +static int GetModuleAndOffsetForPc(uptr pc, char *module_name, + uptr module_name_len, uptr *pc_offset) { + const char *found_module_name = nullptr; + bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC( + pc, &found_module_name, pc_offset); + + if (!ok) return false; + + if (module_name && module_name_len) { + internal_strncpy(module_name, found_module_name, module_name_len); + module_name[module_name_len - 1] = '\x00'; + } + return true; +} + +} // namespace __sanitizer +using namespace __sanitizer; + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf, + uptr out_buf_size) { + if (!out_buf_size) return; + pc = StackTrace::GetPreviousInstructionPc(pc); + SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); + if (!frame) { + internal_strncpy(out_buf, "", out_buf_size); + out_buf[out_buf_size - 1] = 0; + return; + } + InternalScopedString frame_desc(GetPageSizeCached()); + uptr frame_num = 0; + // Reserve one byte for the final 0. + char *out_end = out_buf + out_buf_size - 1; + for (SymbolizedStack *cur = frame; cur && out_buf < out_end; + cur = cur->next) { + frame_desc.clear(); + RenderFrame(&frame_desc, fmt, frame_num++, cur->info, + common_flags()->symbolize_vs_style, + common_flags()->strip_path_prefix); + if (!frame_desc.length()) + continue; + // Reserve one byte for the terminating 0. + uptr n = out_end - out_buf - 1; + internal_strncpy(out_buf, frame_desc.data(), n); + out_buf += __sanitizer::Min(n, frame_desc.length()); + *out_buf++ = 0; + } + CHECK(out_buf <= out_end); + *out_buf = 0; +} + +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_symbolize_global(uptr data_addr, const char *fmt, + char *out_buf, uptr out_buf_size) { + if (!out_buf_size) return; + out_buf[0] = 0; + DataInfo DI; + if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return; + InternalScopedString data_desc(GetPageSizeCached()); + RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix); + internal_strncpy(out_buf, data_desc.data(), out_buf_size); + out_buf[out_buf_size - 1] = 0; +} + +SANITIZER_INTERFACE_ATTRIBUTE +int __sanitizer_get_module_and_offset_for_pc(uptr pc, char *module_name, + uptr module_name_len, + uptr *pc_offset) { + return __sanitizer::GetModuleAndOffsetForPc(pc, module_name, module_name_len, + pc_offset); +} +} // extern "C" diff --git a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc deleted file mode 100644 index 17bbf6c0b868..000000000000 --- a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc +++ /dev/null @@ -1,263 +0,0 @@ -//===-- sanitizer_common.cc -----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between sanitizers' run-time libraries. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_stacktrace_printer.h" -#include "sanitizer_file.h" -#include "sanitizer_fuchsia.h" - -namespace __sanitizer { - -// sanitizer_symbolizer_markup.cc implements these differently. -#if !SANITIZER_SYMBOLIZER_MARKUP - -static const char *StripFunctionName(const char *function, const char *prefix) { - if (!function) return nullptr; - if (!prefix) return function; - uptr prefix_len = internal_strlen(prefix); - if (0 == internal_strncmp(function, prefix, prefix_len)) - return function + prefix_len; - return function; -} - -static const char *DemangleFunctionName(const char *function) { - if (!function) return nullptr; - - // NetBSD uses indirection for old threading functions for historical reasons - // The mangled names are internal implementation detail and should not be - // exposed even in backtraces. -#if SANITIZER_NETBSD - if (!internal_strcmp(function, "__libc_mutex_init")) - return "pthread_mutex_init"; - if (!internal_strcmp(function, "__libc_mutex_lock")) - return "pthread_mutex_lock"; - if (!internal_strcmp(function, "__libc_mutex_trylock")) - return "pthread_mutex_trylock"; - if (!internal_strcmp(function, "__libc_mutex_unlock")) - return "pthread_mutex_unlock"; - if (!internal_strcmp(function, "__libc_mutex_destroy")) - return "pthread_mutex_destroy"; - if (!internal_strcmp(function, "__libc_mutexattr_init")) - return "pthread_mutexattr_init"; - if (!internal_strcmp(function, "__libc_mutexattr_settype")) - return "pthread_mutexattr_settype"; - if (!internal_strcmp(function, "__libc_mutexattr_destroy")) - return "pthread_mutexattr_destroy"; - if (!internal_strcmp(function, "__libc_cond_init")) - return "pthread_cond_init"; - if (!internal_strcmp(function, "__libc_cond_signal")) - return "pthread_cond_signal"; - if (!internal_strcmp(function, "__libc_cond_broadcast")) - return "pthread_cond_broadcast"; - if (!internal_strcmp(function, "__libc_cond_wait")) - return "pthread_cond_wait"; - if (!internal_strcmp(function, "__libc_cond_timedwait")) - return "pthread_cond_timedwait"; - if (!internal_strcmp(function, "__libc_cond_destroy")) - return "pthread_cond_destroy"; - if (!internal_strcmp(function, "__libc_rwlock_init")) - return "pthread_rwlock_init"; - if (!internal_strcmp(function, "__libc_rwlock_rdlock")) - return "pthread_rwlock_rdlock"; - if (!internal_strcmp(function, "__libc_rwlock_wrlock")) - return "pthread_rwlock_wrlock"; - if (!internal_strcmp(function, "__libc_rwlock_tryrdlock")) - return "pthread_rwlock_tryrdlock"; - if (!internal_strcmp(function, "__libc_rwlock_trywrlock")) - return "pthread_rwlock_trywrlock"; - if (!internal_strcmp(function, "__libc_rwlock_unlock")) - return "pthread_rwlock_unlock"; - if (!internal_strcmp(function, "__libc_rwlock_destroy")) - return "pthread_rwlock_destroy"; - if (!internal_strcmp(function, "__libc_thr_keycreate")) - return "pthread_key_create"; - if (!internal_strcmp(function, "__libc_thr_setspecific")) - return "pthread_setspecific"; - if (!internal_strcmp(function, "__libc_thr_getspecific")) - return "pthread_getspecific"; - if (!internal_strcmp(function, "__libc_thr_keydelete")) - return "pthread_key_delete"; - if (!internal_strcmp(function, "__libc_thr_once")) - return "pthread_once"; - if (!internal_strcmp(function, "__libc_thr_self")) - return "pthread_self"; - if (!internal_strcmp(function, "__libc_thr_exit")) - return "pthread_exit"; - if (!internal_strcmp(function, "__libc_thr_setcancelstate")) - return "pthread_setcancelstate"; - if (!internal_strcmp(function, "__libc_thr_equal")) - return "pthread_equal"; - if (!internal_strcmp(function, "__libc_thr_curcpu")) - return "pthread_curcpu_np"; - if (!internal_strcmp(function, "__libc_thr_sigsetmask")) - return "pthread_sigmask"; -#endif - - return function; -} - -static const char kDefaultFormat[] = " #%n %p %F %L"; - -void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, - const AddressInfo &info, bool vs_style, - const char *strip_path_prefix, const char *strip_func_prefix) { - if (0 == internal_strcmp(format, "DEFAULT")) - format = kDefaultFormat; - for (const char *p = format; *p != '\0'; p++) { - if (*p != '%') { - buffer->append("%c", *p); - continue; - } - p++; - switch (*p) { - case '%': - buffer->append("%%"); - break; - // Frame number and all fields of AddressInfo structure. - case 'n': - buffer->append("%zu", frame_no); - break; - case 'p': - buffer->append("0x%zx", info.address); - break; - case 'm': - buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix)); - break; - case 'o': - buffer->append("0x%zx", info.module_offset); - break; - case 'f': - buffer->append("%s", - DemangleFunctionName( - StripFunctionName(info.function, strip_func_prefix))); - break; - case 'q': - buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown - ? info.function_offset - : 0x0); - break; - case 's': - buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix)); - break; - case 'l': - buffer->append("%d", info.line); - break; - case 'c': - buffer->append("%d", info.column); - break; - // Smarter special cases. - case 'F': - // Function name and offset, if file is unknown. - if (info.function) { - buffer->append("in %s", - DemangleFunctionName( - StripFunctionName(info.function, strip_func_prefix))); - if (!info.file && info.function_offset != AddressInfo::kUnknown) - buffer->append("+0x%zx", info.function_offset); - } - break; - case 'S': - // File/line information. - RenderSourceLocation(buffer, info.file, info.line, info.column, vs_style, - strip_path_prefix); - break; - case 'L': - // Source location, or module location. - if (info.file) { - RenderSourceLocation(buffer, info.file, info.line, info.column, - vs_style, strip_path_prefix); - } else if (info.module) { - RenderModuleLocation(buffer, info.module, info.module_offset, - info.module_arch, strip_path_prefix); - } else { - buffer->append("()"); - } - break; - case 'M': - // Module basename and offset, or PC. - if (info.address & kExternalPCBit) - {} // There PCs are not meaningful. - else if (info.module) - // Always strip the module name for %M. - RenderModuleLocation(buffer, StripModuleName(info.module), - info.module_offset, info.module_arch, ""); - else - buffer->append("(%p)", (void *)info.address); - break; - default: - Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p, - *p); - Die(); - } - } -} - -void RenderData(InternalScopedString *buffer, const char *format, - const DataInfo *DI, const char *strip_path_prefix) { - for (const char *p = format; *p != '\0'; p++) { - if (*p != '%') { - buffer->append("%c", *p); - continue; - } - p++; - switch (*p) { - case '%': - buffer->append("%%"); - break; - case 's': - buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix)); - break; - case 'l': - buffer->append("%d", DI->line); - break; - case 'g': - buffer->append("%s", DI->name); - break; - default: - Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p, - *p); - Die(); - } - } -} - -#endif // !SANITIZER_SYMBOLIZER_MARKUP - -void RenderSourceLocation(InternalScopedString *buffer, const char *file, - int line, int column, bool vs_style, - const char *strip_path_prefix) { - if (vs_style && line > 0) { - buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line); - if (column > 0) - buffer->append(",%d", column); - buffer->append(")"); - return; - } - - buffer->append("%s", StripPathPrefix(file, strip_path_prefix)); - if (line > 0) { - buffer->append(":%d", line); - if (column > 0) - buffer->append(":%d", column); - } -} - -void RenderModuleLocation(InternalScopedString *buffer, const char *module, - uptr offset, ModuleArch arch, - const char *strip_path_prefix) { - buffer->append("(%s", StripPathPrefix(module, strip_path_prefix)); - if (arch != kModuleArchUnknown) { - buffer->append(":%s", ModuleArchToString(arch)); - } - buffer->append("+0x%zx)", offset); -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp b/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp new file mode 100644 index 000000000000..150ff475316b --- /dev/null +++ b/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp @@ -0,0 +1,263 @@ +//===-- sanitizer_common.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizers' run-time libraries. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_stacktrace_printer.h" +#include "sanitizer_file.h" +#include "sanitizer_fuchsia.h" + +namespace __sanitizer { + +// sanitizer_symbolizer_markup.cpp implements these differently. +#if !SANITIZER_SYMBOLIZER_MARKUP + +static const char *StripFunctionName(const char *function, const char *prefix) { + if (!function) return nullptr; + if (!prefix) return function; + uptr prefix_len = internal_strlen(prefix); + if (0 == internal_strncmp(function, prefix, prefix_len)) + return function + prefix_len; + return function; +} + +static const char *DemangleFunctionName(const char *function) { + if (!function) return nullptr; + + // NetBSD uses indirection for old threading functions for historical reasons + // The mangled names are internal implementation detail and should not be + // exposed even in backtraces. +#if SANITIZER_NETBSD + if (!internal_strcmp(function, "__libc_mutex_init")) + return "pthread_mutex_init"; + if (!internal_strcmp(function, "__libc_mutex_lock")) + return "pthread_mutex_lock"; + if (!internal_strcmp(function, "__libc_mutex_trylock")) + return "pthread_mutex_trylock"; + if (!internal_strcmp(function, "__libc_mutex_unlock")) + return "pthread_mutex_unlock"; + if (!internal_strcmp(function, "__libc_mutex_destroy")) + return "pthread_mutex_destroy"; + if (!internal_strcmp(function, "__libc_mutexattr_init")) + return "pthread_mutexattr_init"; + if (!internal_strcmp(function, "__libc_mutexattr_settype")) + return "pthread_mutexattr_settype"; + if (!internal_strcmp(function, "__libc_mutexattr_destroy")) + return "pthread_mutexattr_destroy"; + if (!internal_strcmp(function, "__libc_cond_init")) + return "pthread_cond_init"; + if (!internal_strcmp(function, "__libc_cond_signal")) + return "pthread_cond_signal"; + if (!internal_strcmp(function, "__libc_cond_broadcast")) + return "pthread_cond_broadcast"; + if (!internal_strcmp(function, "__libc_cond_wait")) + return "pthread_cond_wait"; + if (!internal_strcmp(function, "__libc_cond_timedwait")) + return "pthread_cond_timedwait"; + if (!internal_strcmp(function, "__libc_cond_destroy")) + return "pthread_cond_destroy"; + if (!internal_strcmp(function, "__libc_rwlock_init")) + return "pthread_rwlock_init"; + if (!internal_strcmp(function, "__libc_rwlock_rdlock")) + return "pthread_rwlock_rdlock"; + if (!internal_strcmp(function, "__libc_rwlock_wrlock")) + return "pthread_rwlock_wrlock"; + if (!internal_strcmp(function, "__libc_rwlock_tryrdlock")) + return "pthread_rwlock_tryrdlock"; + if (!internal_strcmp(function, "__libc_rwlock_trywrlock")) + return "pthread_rwlock_trywrlock"; + if (!internal_strcmp(function, "__libc_rwlock_unlock")) + return "pthread_rwlock_unlock"; + if (!internal_strcmp(function, "__libc_rwlock_destroy")) + return "pthread_rwlock_destroy"; + if (!internal_strcmp(function, "__libc_thr_keycreate")) + return "pthread_key_create"; + if (!internal_strcmp(function, "__libc_thr_setspecific")) + return "pthread_setspecific"; + if (!internal_strcmp(function, "__libc_thr_getspecific")) + return "pthread_getspecific"; + if (!internal_strcmp(function, "__libc_thr_keydelete")) + return "pthread_key_delete"; + if (!internal_strcmp(function, "__libc_thr_once")) + return "pthread_once"; + if (!internal_strcmp(function, "__libc_thr_self")) + return "pthread_self"; + if (!internal_strcmp(function, "__libc_thr_exit")) + return "pthread_exit"; + if (!internal_strcmp(function, "__libc_thr_setcancelstate")) + return "pthread_setcancelstate"; + if (!internal_strcmp(function, "__libc_thr_equal")) + return "pthread_equal"; + if (!internal_strcmp(function, "__libc_thr_curcpu")) + return "pthread_curcpu_np"; + if (!internal_strcmp(function, "__libc_thr_sigsetmask")) + return "pthread_sigmask"; +#endif + + return function; +} + +static const char kDefaultFormat[] = " #%n %p %F %L"; + +void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, + const AddressInfo &info, bool vs_style, + const char *strip_path_prefix, const char *strip_func_prefix) { + if (0 == internal_strcmp(format, "DEFAULT")) + format = kDefaultFormat; + for (const char *p = format; *p != '\0'; p++) { + if (*p != '%') { + buffer->append("%c", *p); + continue; + } + p++; + switch (*p) { + case '%': + buffer->append("%%"); + break; + // Frame number and all fields of AddressInfo structure. + case 'n': + buffer->append("%zu", frame_no); + break; + case 'p': + buffer->append("0x%zx", info.address); + break; + case 'm': + buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix)); + break; + case 'o': + buffer->append("0x%zx", info.module_offset); + break; + case 'f': + buffer->append("%s", + DemangleFunctionName( + StripFunctionName(info.function, strip_func_prefix))); + break; + case 'q': + buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown + ? info.function_offset + : 0x0); + break; + case 's': + buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix)); + break; + case 'l': + buffer->append("%d", info.line); + break; + case 'c': + buffer->append("%d", info.column); + break; + // Smarter special cases. + case 'F': + // Function name and offset, if file is unknown. + if (info.function) { + buffer->append("in %s", + DemangleFunctionName( + StripFunctionName(info.function, strip_func_prefix))); + if (!info.file && info.function_offset != AddressInfo::kUnknown) + buffer->append("+0x%zx", info.function_offset); + } + break; + case 'S': + // File/line information. + RenderSourceLocation(buffer, info.file, info.line, info.column, vs_style, + strip_path_prefix); + break; + case 'L': + // Source location, or module location. + if (info.file) { + RenderSourceLocation(buffer, info.file, info.line, info.column, + vs_style, strip_path_prefix); + } else if (info.module) { + RenderModuleLocation(buffer, info.module, info.module_offset, + info.module_arch, strip_path_prefix); + } else { + buffer->append("()"); + } + break; + case 'M': + // Module basename and offset, or PC. + if (info.address & kExternalPCBit) + {} // There PCs are not meaningful. + else if (info.module) + // Always strip the module name for %M. + RenderModuleLocation(buffer, StripModuleName(info.module), + info.module_offset, info.module_arch, ""); + else + buffer->append("(%p)", (void *)info.address); + break; + default: + Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p, + *p); + Die(); + } + } +} + +void RenderData(InternalScopedString *buffer, const char *format, + const DataInfo *DI, const char *strip_path_prefix) { + for (const char *p = format; *p != '\0'; p++) { + if (*p != '%') { + buffer->append("%c", *p); + continue; + } + p++; + switch (*p) { + case '%': + buffer->append("%%"); + break; + case 's': + buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix)); + break; + case 'l': + buffer->append("%d", DI->line); + break; + case 'g': + buffer->append("%s", DI->name); + break; + default: + Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p, + *p); + Die(); + } + } +} + +#endif // !SANITIZER_SYMBOLIZER_MARKUP + +void RenderSourceLocation(InternalScopedString *buffer, const char *file, + int line, int column, bool vs_style, + const char *strip_path_prefix) { + if (vs_style && line > 0) { + buffer->append("%s(%d", StripPathPrefix(file, strip_path_prefix), line); + if (column > 0) + buffer->append(",%d", column); + buffer->append(")"); + return; + } + + buffer->append("%s", StripPathPrefix(file, strip_path_prefix)); + if (line > 0) { + buffer->append(":%d", line); + if (column > 0) + buffer->append(":%d", column); + } +} + +void RenderModuleLocation(InternalScopedString *buffer, const char *module, + uptr offset, ModuleArch arch, + const char *strip_path_prefix) { + buffer->append("(%s", StripPathPrefix(module, strip_path_prefix)); + if (arch != kModuleArchUnknown) { + buffer->append(":%s", ModuleArchToString(arch)); + } + buffer->append("+0x%zx)", offset); +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_stacktrace_sparc.cc b/lib/sanitizer_common/sanitizer_stacktrace_sparc.cc deleted file mode 100644 index b238cfbc26a3..000000000000 --- a/lib/sanitizer_common/sanitizer_stacktrace_sparc.cc +++ /dev/null @@ -1,85 +0,0 @@ -//===-- sanitizer_stacktrace_sparc.cc -------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. -// -// Implemention of fast stack unwinding for Sparc. -//===----------------------------------------------------------------------===// - -#if defined(__sparc__) - -#if defined(__arch64__) || defined(__sparcv9) -#define STACK_BIAS 2047 -#else -#define STACK_BIAS 0 -#endif - -#include "sanitizer_common.h" -#include "sanitizer_stacktrace.h" - -namespace __sanitizer { - -void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top, - uptr stack_bottom, u32 max_depth) { - // TODO(yln): add arg sanity check for stack_top/stack_bottom - CHECK_GE(max_depth, 2); - const uptr kPageSize = GetPageSizeCached(); -#if defined(__GNUC__) - // __builtin_return_address returns the address of the call instruction - // on the SPARC and not the return address, so we need to compensate. - trace_buffer[0] = GetNextInstructionPc(pc); -#else - trace_buffer[0] = pc; -#endif - size = 1; - if (stack_top < 4096) return; // Sanity check for stack top. - // Flush register windows to memory -#if defined(__sparc_v9__) || defined(__sparcv9__) || defined(__sparcv9) - asm volatile("flushw" ::: "memory"); -#else - asm volatile("ta 3" ::: "memory"); -#endif - // On the SPARC, the return address is not in the frame, it is in a - // register. There is no way to access it off of the current frame - // pointer, but it can be accessed off the previous frame pointer by - // reading the value from the register window save area. - uptr prev_bp = GET_CURRENT_FRAME(); - uptr next_bp = prev_bp; - unsigned int i = 0; - while (next_bp != bp && IsAligned(next_bp, sizeof(uhwptr)) && i++ < 8) { - prev_bp = next_bp; - next_bp = (uptr)((uhwptr *)next_bp)[14] + STACK_BIAS; - } - if (next_bp == bp) - bp = prev_bp; - // Lowest possible address that makes sense as the next frame pointer. - // Goes up as we walk the stack. - uptr bottom = stack_bottom; - // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. - while (IsValidFrame(bp, stack_top, bottom) && IsAligned(bp, sizeof(uhwptr)) && - size < max_depth) { - uhwptr pc1 = ((uhwptr *)bp)[15]; - // Let's assume that any pointer in the 0th page is invalid and - // stop unwinding here. If we're adding support for a platform - // where this isn't true, we need to reconsider this check. - if (pc1 < kPageSize) - break; - if (pc1 != pc) { - // %o7 contains the address of the call instruction and not the - // return address, so we need to compensate. - trace_buffer[size++] = GetNextInstructionPc((uptr)pc1); - } - bottom = bp; - bp = (uptr)((uhwptr *)bp)[14] + STACK_BIAS; - } -} - -} // namespace __sanitizer - -#endif // !defined(__sparc__) diff --git a/lib/sanitizer_common/sanitizer_stacktrace_sparc.cpp b/lib/sanitizer_common/sanitizer_stacktrace_sparc.cpp new file mode 100644 index 000000000000..34190fb1bbb2 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_stacktrace_sparc.cpp @@ -0,0 +1,85 @@ +//===-- sanitizer_stacktrace_sparc.cpp ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +// +// Implemention of fast stack unwinding for Sparc. +//===----------------------------------------------------------------------===// + +#if defined(__sparc__) + +#if defined(__arch64__) || defined(__sparcv9) +#define STACK_BIAS 2047 +#else +#define STACK_BIAS 0 +#endif + +#include "sanitizer_common.h" +#include "sanitizer_stacktrace.h" + +namespace __sanitizer { + +void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top, + uptr stack_bottom, u32 max_depth) { + // TODO(yln): add arg sanity check for stack_top/stack_bottom + CHECK_GE(max_depth, 2); + const uptr kPageSize = GetPageSizeCached(); +#if defined(__GNUC__) + // __builtin_return_address returns the address of the call instruction + // on the SPARC and not the return address, so we need to compensate. + trace_buffer[0] = GetNextInstructionPc(pc); +#else + trace_buffer[0] = pc; +#endif + size = 1; + if (stack_top < 4096) return; // Sanity check for stack top. + // Flush register windows to memory +#if defined(__sparc_v9__) || defined(__sparcv9__) || defined(__sparcv9) + asm volatile("flushw" ::: "memory"); +#else + asm volatile("ta 3" ::: "memory"); +#endif + // On the SPARC, the return address is not in the frame, it is in a + // register. There is no way to access it off of the current frame + // pointer, but it can be accessed off the previous frame pointer by + // reading the value from the register window save area. + uptr prev_bp = GET_CURRENT_FRAME(); + uptr next_bp = prev_bp; + unsigned int i = 0; + while (next_bp != bp && IsAligned(next_bp, sizeof(uhwptr)) && i++ < 8) { + prev_bp = next_bp; + next_bp = (uptr)((uhwptr *)next_bp)[14] + STACK_BIAS; + } + if (next_bp == bp) + bp = prev_bp; + // Lowest possible address that makes sense as the next frame pointer. + // Goes up as we walk the stack. + uptr bottom = stack_bottom; + // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. + while (IsValidFrame(bp, stack_top, bottom) && IsAligned(bp, sizeof(uhwptr)) && + size < max_depth) { + uhwptr pc1 = ((uhwptr *)bp)[15]; + // Let's assume that any pointer in the 0th page is invalid and + // stop unwinding here. If we're adding support for a platform + // where this isn't true, we need to reconsider this check. + if (pc1 < kPageSize) + break; + if (pc1 != pc) { + // %o7 contains the address of the call instruction and not the + // return address, so we need to compensate. + trace_buffer[size++] = GetNextInstructionPc((uptr)pc1); + } + bottom = bp; + bp = (uptr)((uhwptr *)bp)[14] + STACK_BIAS; + } +} + +} // namespace __sanitizer + +#endif // !defined(__sparc__) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc deleted file mode 100644 index 716f0d226954..000000000000 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ /dev/null @@ -1,572 +0,0 @@ -//===-- sanitizer_stoptheworld_linux_libcdep.cc ---------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// See sanitizer_stoptheworld.h for details. -// This implementation was inspired by Markus Gutschke's linuxthreads.cc. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || \ - defined(__aarch64__) || defined(__powerpc64__) || \ - defined(__s390__) || defined(__i386__) || \ - defined(__arm__)) - -#include "sanitizer_stoptheworld.h" - -#include "sanitizer_platform_limits_posix.h" -#include "sanitizer_atomic.h" - -#include -#include // for CLONE_* definitions -#include -#include // for PR_* definitions -#include // for PTRACE_* definitions -#include // for pid_t -#include // for iovec -#include // for NT_PRSTATUS -#if defined(__aarch64__) && !SANITIZER_ANDROID -// GLIBC 2.20+ sys/user does not include asm/ptrace.h -# include -#endif -#include // for user_regs_struct -#if SANITIZER_ANDROID && SANITIZER_MIPS -# include // for mips SP register in sys/user.h -#endif -#include // for signal-related stuff - -#ifdef sa_handler -# undef sa_handler -#endif - -#ifdef sa_sigaction -# undef sa_sigaction -#endif - -#include "sanitizer_common.h" -#include "sanitizer_flags.h" -#include "sanitizer_libc.h" -#include "sanitizer_linux.h" -#include "sanitizer_mutex.h" -#include "sanitizer_placement_new.h" - -// Sufficiently old kernel headers don't provide this value, but we can still -// call prctl with it. If the runtime kernel is new enough, the prctl call will -// have the desired effect; if the kernel is too old, the call will error and we -// can ignore said error. -#ifndef PR_SET_PTRACER -#define PR_SET_PTRACER 0x59616d61 -#endif - -// This module works by spawning a Linux task which then attaches to every -// thread in the caller process with ptrace. This suspends the threads, and -// PTRACE_GETREGS can then be used to obtain their register state. The callback -// supplied to StopTheWorld() is run in the tracer task while the threads are -// suspended. -// The tracer task must be placed in a different thread group for ptrace to -// work, so it cannot be spawned as a pthread. Instead, we use the low-level -// clone() interface (we want to share the address space with the caller -// process, so we prefer clone() over fork()). -// -// We don't use any libc functions, relying instead on direct syscalls. There -// are two reasons for this: -// 1. calling a library function while threads are suspended could cause a -// deadlock, if one of the treads happens to be holding a libc lock; -// 2. it's generally not safe to call libc functions from the tracer task, -// because clone() does not set up a thread-local storage for it. Any -// thread-local variables used by libc will be shared between the tracer task -// and the thread which spawned it. - -namespace __sanitizer { - -class SuspendedThreadsListLinux : public SuspendedThreadsList { - public: - SuspendedThreadsListLinux() { thread_ids_.reserve(1024); } - - tid_t GetThreadID(uptr index) const; - uptr ThreadCount() const; - bool ContainsTid(tid_t thread_id) const; - void Append(tid_t tid); - - PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, - uptr *sp) const; - uptr RegisterCount() const; - - private: - InternalMmapVector thread_ids_; -}; - -// Structure for passing arguments into the tracer thread. -struct TracerThreadArgument { - StopTheWorldCallback callback; - void *callback_argument; - // The tracer thread waits on this mutex while the parent finishes its - // preparations. - BlockingMutex mutex; - // Tracer thread signals its completion by setting done. - atomic_uintptr_t done; - uptr parent_pid; -}; - -// This class handles thread suspending/unsuspending in the tracer thread. -class ThreadSuspender { - public: - explicit ThreadSuspender(pid_t pid, TracerThreadArgument *arg) - : arg(arg) - , pid_(pid) { - CHECK_GE(pid, 0); - } - bool SuspendAllThreads(); - void ResumeAllThreads(); - void KillAllThreads(); - SuspendedThreadsListLinux &suspended_threads_list() { - return suspended_threads_list_; - } - TracerThreadArgument *arg; - private: - SuspendedThreadsListLinux suspended_threads_list_; - pid_t pid_; - bool SuspendThread(tid_t thread_id); -}; - -bool ThreadSuspender::SuspendThread(tid_t tid) { - // Are we already attached to this thread? - // Currently this check takes linear time, however the number of threads is - // usually small. - if (suspended_threads_list_.ContainsTid(tid)) return false; - int pterrno; - if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, nullptr, nullptr), - &pterrno)) { - // Either the thread is dead, or something prevented us from attaching. - // Log this event and move on. - VReport(1, "Could not attach to thread %zu (errno %d).\n", (uptr)tid, - pterrno); - return false; - } else { - VReport(2, "Attached to thread %zu.\n", (uptr)tid); - // The thread is not guaranteed to stop before ptrace returns, so we must - // wait on it. Note: if the thread receives a signal concurrently, - // we can get notification about the signal before notification about stop. - // In such case we need to forward the signal to the thread, otherwise - // the signal will be missed (as we do PTRACE_DETACH with arg=0) and - // any logic relying on signals will break. After forwarding we need to - // continue to wait for stopping, because the thread is not stopped yet. - // We do ignore delivery of SIGSTOP, because we want to make stop-the-world - // as invisible as possible. - for (;;) { - int status; - uptr waitpid_status; - HANDLE_EINTR(waitpid_status, internal_waitpid(tid, &status, __WALL)); - int wperrno; - if (internal_iserror(waitpid_status, &wperrno)) { - // Got a ECHILD error. I don't think this situation is possible, but it - // doesn't hurt to report it. - VReport(1, "Waiting on thread %zu failed, detaching (errno %d).\n", - (uptr)tid, wperrno); - internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr); - return false; - } - if (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) { - internal_ptrace(PTRACE_CONT, tid, nullptr, - (void*)(uptr)WSTOPSIG(status)); - continue; - } - break; - } - suspended_threads_list_.Append(tid); - return true; - } -} - -void ThreadSuspender::ResumeAllThreads() { - for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++) { - pid_t tid = suspended_threads_list_.GetThreadID(i); - int pterrno; - if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr), - &pterrno)) { - VReport(2, "Detached from thread %d.\n", tid); - } else { - // Either the thread is dead, or we are already detached. - // The latter case is possible, for instance, if this function was called - // from a signal handler. - VReport(1, "Could not detach from thread %d (errno %d).\n", tid, pterrno); - } - } -} - -void ThreadSuspender::KillAllThreads() { - for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++) - internal_ptrace(PTRACE_KILL, suspended_threads_list_.GetThreadID(i), - nullptr, nullptr); -} - -bool ThreadSuspender::SuspendAllThreads() { - ThreadLister thread_lister(pid_); - bool retry = true; - InternalMmapVector threads; - threads.reserve(128); - for (int i = 0; i < 30 && retry; ++i) { - retry = false; - switch (thread_lister.ListThreads(&threads)) { - case ThreadLister::Error: - ResumeAllThreads(); - return false; - case ThreadLister::Incomplete: - retry = true; - break; - case ThreadLister::Ok: - break; - } - for (tid_t tid : threads) - if (SuspendThread(tid)) - retry = true; - }; - return suspended_threads_list_.ThreadCount(); -} - -// Pointer to the ThreadSuspender instance for use in signal handler. -static ThreadSuspender *thread_suspender_instance = nullptr; - -// Synchronous signals that should not be blocked. -static const int kSyncSignals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV, SIGBUS, - SIGXCPU, SIGXFSZ }; - -static void TracerThreadDieCallback() { - // Generally a call to Die() in the tracer thread should be fatal to the - // parent process as well, because they share the address space. - // This really only works correctly if all the threads are suspended at this - // point. So we correctly handle calls to Die() from within the callback, but - // not those that happen before or after the callback. Hopefully there aren't - // a lot of opportunities for that to happen... - ThreadSuspender *inst = thread_suspender_instance; - if (inst && stoptheworld_tracer_pid == internal_getpid()) { - inst->KillAllThreads(); - thread_suspender_instance = nullptr; - } -} - -// Signal handler to wake up suspended threads when the tracer thread dies. -static void TracerThreadSignalHandler(int signum, __sanitizer_siginfo *siginfo, - void *uctx) { - SignalContext ctx(siginfo, uctx); - Printf("Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n", signum, - ctx.addr, ctx.pc, ctx.sp); - ThreadSuspender *inst = thread_suspender_instance; - if (inst) { - if (signum == SIGABRT) - inst->KillAllThreads(); - else - inst->ResumeAllThreads(); - RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); - thread_suspender_instance = nullptr; - atomic_store(&inst->arg->done, 1, memory_order_relaxed); - } - internal__exit((signum == SIGABRT) ? 1 : 2); -} - -// Size of alternative stack for signal handlers in the tracer thread. -static const int kHandlerStackSize = 8192; - -// This function will be run as a cloned task. -static int TracerThread(void* argument) { - TracerThreadArgument *tracer_thread_argument = - (TracerThreadArgument *)argument; - - internal_prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); - // Check if parent is already dead. - if (internal_getppid() != tracer_thread_argument->parent_pid) - internal__exit(4); - - // Wait for the parent thread to finish preparations. - tracer_thread_argument->mutex.Lock(); - tracer_thread_argument->mutex.Unlock(); - - RAW_CHECK(AddDieCallback(TracerThreadDieCallback)); - - ThreadSuspender thread_suspender(internal_getppid(), tracer_thread_argument); - // Global pointer for the signal handler. - thread_suspender_instance = &thread_suspender; - - // Alternate stack for signal handling. - InternalMmapVector handler_stack_memory(kHandlerStackSize); - stack_t handler_stack; - internal_memset(&handler_stack, 0, sizeof(handler_stack)); - handler_stack.ss_sp = handler_stack_memory.data(); - handler_stack.ss_size = kHandlerStackSize; - internal_sigaltstack(&handler_stack, nullptr); - - // Install our handler for synchronous signals. Other signals should be - // blocked by the mask we inherited from the parent thread. - for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) { - __sanitizer_sigaction act; - internal_memset(&act, 0, sizeof(act)); - act.sigaction = TracerThreadSignalHandler; - act.sa_flags = SA_ONSTACK | SA_SIGINFO; - internal_sigaction_norestorer(kSyncSignals[i], &act, 0); - } - - int exit_code = 0; - if (!thread_suspender.SuspendAllThreads()) { - VReport(1, "Failed suspending threads.\n"); - exit_code = 3; - } else { - tracer_thread_argument->callback(thread_suspender.suspended_threads_list(), - tracer_thread_argument->callback_argument); - thread_suspender.ResumeAllThreads(); - exit_code = 0; - } - RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); - thread_suspender_instance = nullptr; - atomic_store(&tracer_thread_argument->done, 1, memory_order_relaxed); - return exit_code; -} - -class ScopedStackSpaceWithGuard { - public: - explicit ScopedStackSpaceWithGuard(uptr stack_size) { - stack_size_ = stack_size; - guard_size_ = GetPageSizeCached(); - // FIXME: Omitting MAP_STACK here works in current kernels but might break - // in the future. - guard_start_ = (uptr)MmapOrDie(stack_size_ + guard_size_, - "ScopedStackWithGuard"); - CHECK(MprotectNoAccess((uptr)guard_start_, guard_size_)); - } - ~ScopedStackSpaceWithGuard() { - UnmapOrDie((void *)guard_start_, stack_size_ + guard_size_); - } - void *Bottom() const { - return (void *)(guard_start_ + stack_size_ + guard_size_); - } - - private: - uptr stack_size_; - uptr guard_size_; - uptr guard_start_; -}; - -// We have a limitation on the stack frame size, so some stuff had to be moved -// into globals. -static __sanitizer_sigset_t blocked_sigset; -static __sanitizer_sigset_t old_sigset; - -class StopTheWorldScope { - public: - StopTheWorldScope() { - // Make this process dumpable. Processes that are not dumpable cannot be - // attached to. - process_was_dumpable_ = internal_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0); - if (!process_was_dumpable_) - internal_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); - } - - ~StopTheWorldScope() { - // Restore the dumpable flag. - if (!process_was_dumpable_) - internal_prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); - } - - private: - int process_was_dumpable_; -}; - -// When sanitizer output is being redirected to file (i.e. by using log_path), -// the tracer should write to the parent's log instead of trying to open a new -// file. Alert the logging code to the fact that we have a tracer. -struct ScopedSetTracerPID { - explicit ScopedSetTracerPID(uptr tracer_pid) { - stoptheworld_tracer_pid = tracer_pid; - stoptheworld_tracer_ppid = internal_getpid(); - } - ~ScopedSetTracerPID() { - stoptheworld_tracer_pid = 0; - stoptheworld_tracer_ppid = 0; - } -}; - -void StopTheWorld(StopTheWorldCallback callback, void *argument) { - StopTheWorldScope in_stoptheworld; - // Prepare the arguments for TracerThread. - struct TracerThreadArgument tracer_thread_argument; - tracer_thread_argument.callback = callback; - tracer_thread_argument.callback_argument = argument; - tracer_thread_argument.parent_pid = internal_getpid(); - atomic_store(&tracer_thread_argument.done, 0, memory_order_relaxed); - const uptr kTracerStackSize = 2 * 1024 * 1024; - ScopedStackSpaceWithGuard tracer_stack(kTracerStackSize); - // Block the execution of TracerThread until after we have set ptrace - // permissions. - tracer_thread_argument.mutex.Lock(); - // Signal handling story. - // We don't want async signals to be delivered to the tracer thread, - // so we block all async signals before creating the thread. An async signal - // handler can temporary modify errno, which is shared with this thread. - // We ought to use pthread_sigmask here, because sigprocmask has undefined - // behavior in multithreaded programs. However, on linux sigprocmask is - // equivalent to pthread_sigmask with the exception that pthread_sigmask - // does not allow to block some signals used internally in pthread - // implementation. We are fine with blocking them here, we are really not - // going to pthread_cancel the thread. - // The tracer thread should not raise any synchronous signals. But in case it - // does, we setup a special handler for sync signals that properly kills the - // parent as well. Note: we don't pass CLONE_SIGHAND to clone, so handlers - // in the tracer thread won't interfere with user program. Double note: if a - // user does something along the lines of 'kill -11 pid', that can kill the - // process even if user setup own handler for SEGV. - // Thing to watch out for: this code should not change behavior of user code - // in any observable way. In particular it should not override user signal - // handlers. - internal_sigfillset(&blocked_sigset); - for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) - internal_sigdelset(&blocked_sigset, kSyncSignals[i]); - int rv = internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset); - CHECK_EQ(rv, 0); - uptr tracer_pid = internal_clone( - TracerThread, tracer_stack.Bottom(), - CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED, - &tracer_thread_argument, nullptr /* parent_tidptr */, - nullptr /* newtls */, nullptr /* child_tidptr */); - internal_sigprocmask(SIG_SETMASK, &old_sigset, 0); - int local_errno = 0; - if (internal_iserror(tracer_pid, &local_errno)) { - VReport(1, "Failed spawning a tracer thread (errno %d).\n", local_errno); - tracer_thread_argument.mutex.Unlock(); - } else { - ScopedSetTracerPID scoped_set_tracer_pid(tracer_pid); - // On some systems we have to explicitly declare that we want to be traced - // by the tracer thread. - internal_prctl(PR_SET_PTRACER, tracer_pid, 0, 0, 0); - // Allow the tracer thread to start. - tracer_thread_argument.mutex.Unlock(); - // NOTE: errno is shared between this thread and the tracer thread. - // internal_waitpid() may call syscall() which can access/spoil errno, - // so we can't call it now. Instead we for the tracer thread to finish using - // the spin loop below. Man page for sched_yield() says "In the Linux - // implementation, sched_yield() always succeeds", so let's hope it does not - // spoil errno. Note that this spin loop runs only for brief periods before - // the tracer thread has suspended us and when it starts unblocking threads. - while (atomic_load(&tracer_thread_argument.done, memory_order_relaxed) == 0) - sched_yield(); - // Now the tracer thread is about to exit and does not touch errno, - // wait for it. - for (;;) { - uptr waitpid_status = internal_waitpid(tracer_pid, nullptr, __WALL); - if (!internal_iserror(waitpid_status, &local_errno)) - break; - if (local_errno == EINTR) - continue; - VReport(1, "Waiting on the tracer thread failed (errno %d).\n", - local_errno); - break; - } - } -} - -// Platform-specific methods from SuspendedThreadsList. -#if SANITIZER_ANDROID && defined(__arm__) -typedef pt_regs regs_struct; -#define REG_SP ARM_sp - -#elif SANITIZER_LINUX && defined(__arm__) -typedef user_regs regs_struct; -#define REG_SP uregs[13] - -#elif defined(__i386__) || defined(__x86_64__) -typedef user_regs_struct regs_struct; -#if defined(__i386__) -#define REG_SP esp -#else -#define REG_SP rsp -#endif - -#elif defined(__powerpc__) || defined(__powerpc64__) -typedef pt_regs regs_struct; -#define REG_SP gpr[PT_R1] - -#elif defined(__mips__) -typedef struct user regs_struct; -# if SANITIZER_ANDROID -# define REG_SP regs[EF_R29] -# else -# define REG_SP regs[EF_REG29] -# endif - -#elif defined(__aarch64__) -typedef struct user_pt_regs regs_struct; -#define REG_SP sp -#define ARCH_IOVEC_FOR_GETREGSET - -#elif defined(__s390__) -typedef _user_regs_struct regs_struct; -#define REG_SP gprs[15] -#define ARCH_IOVEC_FOR_GETREGSET - -#else -#error "Unsupported architecture" -#endif // SANITIZER_ANDROID && defined(__arm__) - -tid_t SuspendedThreadsListLinux::GetThreadID(uptr index) const { - CHECK_LT(index, thread_ids_.size()); - return thread_ids_[index]; -} - -uptr SuspendedThreadsListLinux::ThreadCount() const { - return thread_ids_.size(); -} - -bool SuspendedThreadsListLinux::ContainsTid(tid_t thread_id) const { - for (uptr i = 0; i < thread_ids_.size(); i++) { - if (thread_ids_[i] == thread_id) return true; - } - return false; -} - -void SuspendedThreadsListLinux::Append(tid_t tid) { - thread_ids_.push_back(tid); -} - -PtraceRegistersStatus SuspendedThreadsListLinux::GetRegistersAndSP( - uptr index, uptr *buffer, uptr *sp) const { - pid_t tid = GetThreadID(index); - regs_struct regs; - int pterrno; -#ifdef ARCH_IOVEC_FOR_GETREGSET - struct iovec regset_io; - regset_io.iov_base = ®s; - regset_io.iov_len = sizeof(regs_struct); - bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid, - (void*)NT_PRSTATUS, (void*)®set_io), - &pterrno); -#else - bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, nullptr, - ®s), &pterrno); -#endif - if (isErr) { - VReport(1, "Could not get registers from thread %d (errno %d).\n", tid, - pterrno); - // ESRCH means that the given thread is not suspended or already dead. - // Therefore it's unsafe to inspect its data (e.g. walk through stack) and - // we should notify caller about this. - return pterrno == ESRCH ? REGISTERS_UNAVAILABLE_FATAL - : REGISTERS_UNAVAILABLE; - } - - *sp = regs.REG_SP; - internal_memcpy(buffer, ®s, sizeof(regs)); - return REGISTERS_AVAILABLE; -} - -uptr SuspendedThreadsListLinux::RegisterCount() const { - return sizeof(regs_struct) / sizeof(uptr); -} -} // namespace __sanitizer - -#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) - // || defined(__aarch64__) || defined(__powerpc64__) - // || defined(__s390__) || defined(__i386__) || defined(__arm__) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp new file mode 100644 index 000000000000..651d5056dd9d --- /dev/null +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp @@ -0,0 +1,573 @@ +//===-- sanitizer_stoptheworld_linux_libcdep.cpp --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// See sanitizer_stoptheworld.h for details. +// This implementation was inspired by Markus Gutschke's linuxthreads.cc. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || \ + defined(__aarch64__) || defined(__powerpc64__) || \ + defined(__s390__) || defined(__i386__) || \ + defined(__arm__)) + +#include "sanitizer_stoptheworld.h" + +#include "sanitizer_platform_limits_posix.h" +#include "sanitizer_atomic.h" + +#include +#include // for CLONE_* definitions +#include +#include // for PR_* definitions +#include // for PTRACE_* definitions +#include // for pid_t +#include // for iovec +#include // for NT_PRSTATUS +#if defined(__aarch64__) && !SANITIZER_ANDROID +// GLIBC 2.20+ sys/user does not include asm/ptrace.h +# include +#endif +#include // for user_regs_struct +#if SANITIZER_ANDROID && SANITIZER_MIPS +# include // for mips SP register in sys/user.h +#endif +#include // for signal-related stuff + +#ifdef sa_handler +# undef sa_handler +#endif + +#ifdef sa_sigaction +# undef sa_sigaction +#endif + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_libc.h" +#include "sanitizer_linux.h" +#include "sanitizer_mutex.h" +#include "sanitizer_placement_new.h" + +// Sufficiently old kernel headers don't provide this value, but we can still +// call prctl with it. If the runtime kernel is new enough, the prctl call will +// have the desired effect; if the kernel is too old, the call will error and we +// can ignore said error. +#ifndef PR_SET_PTRACER +#define PR_SET_PTRACER 0x59616d61 +#endif + +// This module works by spawning a Linux task which then attaches to every +// thread in the caller process with ptrace. This suspends the threads, and +// PTRACE_GETREGS can then be used to obtain their register state. The callback +// supplied to StopTheWorld() is run in the tracer task while the threads are +// suspended. +// The tracer task must be placed in a different thread group for ptrace to +// work, so it cannot be spawned as a pthread. Instead, we use the low-level +// clone() interface (we want to share the address space with the caller +// process, so we prefer clone() over fork()). +// +// We don't use any libc functions, relying instead on direct syscalls. There +// are two reasons for this: +// 1. calling a library function while threads are suspended could cause a +// deadlock, if one of the treads happens to be holding a libc lock; +// 2. it's generally not safe to call libc functions from the tracer task, +// because clone() does not set up a thread-local storage for it. Any +// thread-local variables used by libc will be shared between the tracer task +// and the thread which spawned it. + +namespace __sanitizer { + +class SuspendedThreadsListLinux : public SuspendedThreadsList { + public: + SuspendedThreadsListLinux() { thread_ids_.reserve(1024); } + + tid_t GetThreadID(uptr index) const; + uptr ThreadCount() const; + bool ContainsTid(tid_t thread_id) const; + void Append(tid_t tid); + + PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, + uptr *sp) const; + uptr RegisterCount() const; + + private: + InternalMmapVector thread_ids_; +}; + +// Structure for passing arguments into the tracer thread. +struct TracerThreadArgument { + StopTheWorldCallback callback; + void *callback_argument; + // The tracer thread waits on this mutex while the parent finishes its + // preparations. + BlockingMutex mutex; + // Tracer thread signals its completion by setting done. + atomic_uintptr_t done; + uptr parent_pid; +}; + +// This class handles thread suspending/unsuspending in the tracer thread. +class ThreadSuspender { + public: + explicit ThreadSuspender(pid_t pid, TracerThreadArgument *arg) + : arg(arg) + , pid_(pid) { + CHECK_GE(pid, 0); + } + bool SuspendAllThreads(); + void ResumeAllThreads(); + void KillAllThreads(); + SuspendedThreadsListLinux &suspended_threads_list() { + return suspended_threads_list_; + } + TracerThreadArgument *arg; + private: + SuspendedThreadsListLinux suspended_threads_list_; + pid_t pid_; + bool SuspendThread(tid_t thread_id); +}; + +bool ThreadSuspender::SuspendThread(tid_t tid) { + // Are we already attached to this thread? + // Currently this check takes linear time, however the number of threads is + // usually small. + if (suspended_threads_list_.ContainsTid(tid)) return false; + int pterrno; + if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, nullptr, nullptr), + &pterrno)) { + // Either the thread is dead, or something prevented us from attaching. + // Log this event and move on. + VReport(1, "Could not attach to thread %zu (errno %d).\n", (uptr)tid, + pterrno); + return false; + } else { + VReport(2, "Attached to thread %zu.\n", (uptr)tid); + // The thread is not guaranteed to stop before ptrace returns, so we must + // wait on it. Note: if the thread receives a signal concurrently, + // we can get notification about the signal before notification about stop. + // In such case we need to forward the signal to the thread, otherwise + // the signal will be missed (as we do PTRACE_DETACH with arg=0) and + // any logic relying on signals will break. After forwarding we need to + // continue to wait for stopping, because the thread is not stopped yet. + // We do ignore delivery of SIGSTOP, because we want to make stop-the-world + // as invisible as possible. + for (;;) { + int status; + uptr waitpid_status; + HANDLE_EINTR(waitpid_status, internal_waitpid(tid, &status, __WALL)); + int wperrno; + if (internal_iserror(waitpid_status, &wperrno)) { + // Got a ECHILD error. I don't think this situation is possible, but it + // doesn't hurt to report it. + VReport(1, "Waiting on thread %zu failed, detaching (errno %d).\n", + (uptr)tid, wperrno); + internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr); + return false; + } + if (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) { + internal_ptrace(PTRACE_CONT, tid, nullptr, + (void*)(uptr)WSTOPSIG(status)); + continue; + } + break; + } + suspended_threads_list_.Append(tid); + return true; + } +} + +void ThreadSuspender::ResumeAllThreads() { + for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++) { + pid_t tid = suspended_threads_list_.GetThreadID(i); + int pterrno; + if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr), + &pterrno)) { + VReport(2, "Detached from thread %d.\n", tid); + } else { + // Either the thread is dead, or we are already detached. + // The latter case is possible, for instance, if this function was called + // from a signal handler. + VReport(1, "Could not detach from thread %d (errno %d).\n", tid, pterrno); + } + } +} + +void ThreadSuspender::KillAllThreads() { + for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++) + internal_ptrace(PTRACE_KILL, suspended_threads_list_.GetThreadID(i), + nullptr, nullptr); +} + +bool ThreadSuspender::SuspendAllThreads() { + ThreadLister thread_lister(pid_); + bool retry = true; + InternalMmapVector threads; + threads.reserve(128); + for (int i = 0; i < 30 && retry; ++i) { + retry = false; + switch (thread_lister.ListThreads(&threads)) { + case ThreadLister::Error: + ResumeAllThreads(); + return false; + case ThreadLister::Incomplete: + retry = true; + break; + case ThreadLister::Ok: + break; + } + for (tid_t tid : threads) { + if (SuspendThread(tid)) + retry = true; + } + } + return suspended_threads_list_.ThreadCount(); +} + +// Pointer to the ThreadSuspender instance for use in signal handler. +static ThreadSuspender *thread_suspender_instance = nullptr; + +// Synchronous signals that should not be blocked. +static const int kSyncSignals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV, SIGBUS, + SIGXCPU, SIGXFSZ }; + +static void TracerThreadDieCallback() { + // Generally a call to Die() in the tracer thread should be fatal to the + // parent process as well, because they share the address space. + // This really only works correctly if all the threads are suspended at this + // point. So we correctly handle calls to Die() from within the callback, but + // not those that happen before or after the callback. Hopefully there aren't + // a lot of opportunities for that to happen... + ThreadSuspender *inst = thread_suspender_instance; + if (inst && stoptheworld_tracer_pid == internal_getpid()) { + inst->KillAllThreads(); + thread_suspender_instance = nullptr; + } +} + +// Signal handler to wake up suspended threads when the tracer thread dies. +static void TracerThreadSignalHandler(int signum, __sanitizer_siginfo *siginfo, + void *uctx) { + SignalContext ctx(siginfo, uctx); + Printf("Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n", signum, + ctx.addr, ctx.pc, ctx.sp); + ThreadSuspender *inst = thread_suspender_instance; + if (inst) { + if (signum == SIGABRT) + inst->KillAllThreads(); + else + inst->ResumeAllThreads(); + RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); + thread_suspender_instance = nullptr; + atomic_store(&inst->arg->done, 1, memory_order_relaxed); + } + internal__exit((signum == SIGABRT) ? 1 : 2); +} + +// Size of alternative stack for signal handlers in the tracer thread. +static const int kHandlerStackSize = 8192; + +// This function will be run as a cloned task. +static int TracerThread(void* argument) { + TracerThreadArgument *tracer_thread_argument = + (TracerThreadArgument *)argument; + + internal_prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); + // Check if parent is already dead. + if (internal_getppid() != tracer_thread_argument->parent_pid) + internal__exit(4); + + // Wait for the parent thread to finish preparations. + tracer_thread_argument->mutex.Lock(); + tracer_thread_argument->mutex.Unlock(); + + RAW_CHECK(AddDieCallback(TracerThreadDieCallback)); + + ThreadSuspender thread_suspender(internal_getppid(), tracer_thread_argument); + // Global pointer for the signal handler. + thread_suspender_instance = &thread_suspender; + + // Alternate stack for signal handling. + InternalMmapVector handler_stack_memory(kHandlerStackSize); + stack_t handler_stack; + internal_memset(&handler_stack, 0, sizeof(handler_stack)); + handler_stack.ss_sp = handler_stack_memory.data(); + handler_stack.ss_size = kHandlerStackSize; + internal_sigaltstack(&handler_stack, nullptr); + + // Install our handler for synchronous signals. Other signals should be + // blocked by the mask we inherited from the parent thread. + for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) { + __sanitizer_sigaction act; + internal_memset(&act, 0, sizeof(act)); + act.sigaction = TracerThreadSignalHandler; + act.sa_flags = SA_ONSTACK | SA_SIGINFO; + internal_sigaction_norestorer(kSyncSignals[i], &act, 0); + } + + int exit_code = 0; + if (!thread_suspender.SuspendAllThreads()) { + VReport(1, "Failed suspending threads.\n"); + exit_code = 3; + } else { + tracer_thread_argument->callback(thread_suspender.suspended_threads_list(), + tracer_thread_argument->callback_argument); + thread_suspender.ResumeAllThreads(); + exit_code = 0; + } + RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); + thread_suspender_instance = nullptr; + atomic_store(&tracer_thread_argument->done, 1, memory_order_relaxed); + return exit_code; +} + +class ScopedStackSpaceWithGuard { + public: + explicit ScopedStackSpaceWithGuard(uptr stack_size) { + stack_size_ = stack_size; + guard_size_ = GetPageSizeCached(); + // FIXME: Omitting MAP_STACK here works in current kernels but might break + // in the future. + guard_start_ = (uptr)MmapOrDie(stack_size_ + guard_size_, + "ScopedStackWithGuard"); + CHECK(MprotectNoAccess((uptr)guard_start_, guard_size_)); + } + ~ScopedStackSpaceWithGuard() { + UnmapOrDie((void *)guard_start_, stack_size_ + guard_size_); + } + void *Bottom() const { + return (void *)(guard_start_ + stack_size_ + guard_size_); + } + + private: + uptr stack_size_; + uptr guard_size_; + uptr guard_start_; +}; + +// We have a limitation on the stack frame size, so some stuff had to be moved +// into globals. +static __sanitizer_sigset_t blocked_sigset; +static __sanitizer_sigset_t old_sigset; + +class StopTheWorldScope { + public: + StopTheWorldScope() { + // Make this process dumpable. Processes that are not dumpable cannot be + // attached to. + process_was_dumpable_ = internal_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0); + if (!process_was_dumpable_) + internal_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); + } + + ~StopTheWorldScope() { + // Restore the dumpable flag. + if (!process_was_dumpable_) + internal_prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); + } + + private: + int process_was_dumpable_; +}; + +// When sanitizer output is being redirected to file (i.e. by using log_path), +// the tracer should write to the parent's log instead of trying to open a new +// file. Alert the logging code to the fact that we have a tracer. +struct ScopedSetTracerPID { + explicit ScopedSetTracerPID(uptr tracer_pid) { + stoptheworld_tracer_pid = tracer_pid; + stoptheworld_tracer_ppid = internal_getpid(); + } + ~ScopedSetTracerPID() { + stoptheworld_tracer_pid = 0; + stoptheworld_tracer_ppid = 0; + } +}; + +void StopTheWorld(StopTheWorldCallback callback, void *argument) { + StopTheWorldScope in_stoptheworld; + // Prepare the arguments for TracerThread. + struct TracerThreadArgument tracer_thread_argument; + tracer_thread_argument.callback = callback; + tracer_thread_argument.callback_argument = argument; + tracer_thread_argument.parent_pid = internal_getpid(); + atomic_store(&tracer_thread_argument.done, 0, memory_order_relaxed); + const uptr kTracerStackSize = 2 * 1024 * 1024; + ScopedStackSpaceWithGuard tracer_stack(kTracerStackSize); + // Block the execution of TracerThread until after we have set ptrace + // permissions. + tracer_thread_argument.mutex.Lock(); + // Signal handling story. + // We don't want async signals to be delivered to the tracer thread, + // so we block all async signals before creating the thread. An async signal + // handler can temporary modify errno, which is shared with this thread. + // We ought to use pthread_sigmask here, because sigprocmask has undefined + // behavior in multithreaded programs. However, on linux sigprocmask is + // equivalent to pthread_sigmask with the exception that pthread_sigmask + // does not allow to block some signals used internally in pthread + // implementation. We are fine with blocking them here, we are really not + // going to pthread_cancel the thread. + // The tracer thread should not raise any synchronous signals. But in case it + // does, we setup a special handler for sync signals that properly kills the + // parent as well. Note: we don't pass CLONE_SIGHAND to clone, so handlers + // in the tracer thread won't interfere with user program. Double note: if a + // user does something along the lines of 'kill -11 pid', that can kill the + // process even if user setup own handler for SEGV. + // Thing to watch out for: this code should not change behavior of user code + // in any observable way. In particular it should not override user signal + // handlers. + internal_sigfillset(&blocked_sigset); + for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) + internal_sigdelset(&blocked_sigset, kSyncSignals[i]); + int rv = internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset); + CHECK_EQ(rv, 0); + uptr tracer_pid = internal_clone( + TracerThread, tracer_stack.Bottom(), + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED, + &tracer_thread_argument, nullptr /* parent_tidptr */, + nullptr /* newtls */, nullptr /* child_tidptr */); + internal_sigprocmask(SIG_SETMASK, &old_sigset, 0); + int local_errno = 0; + if (internal_iserror(tracer_pid, &local_errno)) { + VReport(1, "Failed spawning a tracer thread (errno %d).\n", local_errno); + tracer_thread_argument.mutex.Unlock(); + } else { + ScopedSetTracerPID scoped_set_tracer_pid(tracer_pid); + // On some systems we have to explicitly declare that we want to be traced + // by the tracer thread. + internal_prctl(PR_SET_PTRACER, tracer_pid, 0, 0, 0); + // Allow the tracer thread to start. + tracer_thread_argument.mutex.Unlock(); + // NOTE: errno is shared between this thread and the tracer thread. + // internal_waitpid() may call syscall() which can access/spoil errno, + // so we can't call it now. Instead we for the tracer thread to finish using + // the spin loop below. Man page for sched_yield() says "In the Linux + // implementation, sched_yield() always succeeds", so let's hope it does not + // spoil errno. Note that this spin loop runs only for brief periods before + // the tracer thread has suspended us and when it starts unblocking threads. + while (atomic_load(&tracer_thread_argument.done, memory_order_relaxed) == 0) + sched_yield(); + // Now the tracer thread is about to exit and does not touch errno, + // wait for it. + for (;;) { + uptr waitpid_status = internal_waitpid(tracer_pid, nullptr, __WALL); + if (!internal_iserror(waitpid_status, &local_errno)) + break; + if (local_errno == EINTR) + continue; + VReport(1, "Waiting on the tracer thread failed (errno %d).\n", + local_errno); + break; + } + } +} + +// Platform-specific methods from SuspendedThreadsList. +#if SANITIZER_ANDROID && defined(__arm__) +typedef pt_regs regs_struct; +#define REG_SP ARM_sp + +#elif SANITIZER_LINUX && defined(__arm__) +typedef user_regs regs_struct; +#define REG_SP uregs[13] + +#elif defined(__i386__) || defined(__x86_64__) +typedef user_regs_struct regs_struct; +#if defined(__i386__) +#define REG_SP esp +#else +#define REG_SP rsp +#endif + +#elif defined(__powerpc__) || defined(__powerpc64__) +typedef pt_regs regs_struct; +#define REG_SP gpr[PT_R1] + +#elif defined(__mips__) +typedef struct user regs_struct; +# if SANITIZER_ANDROID +# define REG_SP regs[EF_R29] +# else +# define REG_SP regs[EF_REG29] +# endif + +#elif defined(__aarch64__) +typedef struct user_pt_regs regs_struct; +#define REG_SP sp +#define ARCH_IOVEC_FOR_GETREGSET + +#elif defined(__s390__) +typedef _user_regs_struct regs_struct; +#define REG_SP gprs[15] +#define ARCH_IOVEC_FOR_GETREGSET + +#else +#error "Unsupported architecture" +#endif // SANITIZER_ANDROID && defined(__arm__) + +tid_t SuspendedThreadsListLinux::GetThreadID(uptr index) const { + CHECK_LT(index, thread_ids_.size()); + return thread_ids_[index]; +} + +uptr SuspendedThreadsListLinux::ThreadCount() const { + return thread_ids_.size(); +} + +bool SuspendedThreadsListLinux::ContainsTid(tid_t thread_id) const { + for (uptr i = 0; i < thread_ids_.size(); i++) { + if (thread_ids_[i] == thread_id) return true; + } + return false; +} + +void SuspendedThreadsListLinux::Append(tid_t tid) { + thread_ids_.push_back(tid); +} + +PtraceRegistersStatus SuspendedThreadsListLinux::GetRegistersAndSP( + uptr index, uptr *buffer, uptr *sp) const { + pid_t tid = GetThreadID(index); + regs_struct regs; + int pterrno; +#ifdef ARCH_IOVEC_FOR_GETREGSET + struct iovec regset_io; + regset_io.iov_base = ®s; + regset_io.iov_len = sizeof(regs_struct); + bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid, + (void*)NT_PRSTATUS, (void*)®set_io), + &pterrno); +#else + bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, nullptr, + ®s), &pterrno); +#endif + if (isErr) { + VReport(1, "Could not get registers from thread %d (errno %d).\n", tid, + pterrno); + // ESRCH means that the given thread is not suspended or already dead. + // Therefore it's unsafe to inspect its data (e.g. walk through stack) and + // we should notify caller about this. + return pterrno == ESRCH ? REGISTERS_UNAVAILABLE_FATAL + : REGISTERS_UNAVAILABLE; + } + + *sp = regs.REG_SP; + internal_memcpy(buffer, ®s, sizeof(regs)); + return REGISTERS_AVAILABLE; +} + +uptr SuspendedThreadsListLinux::RegisterCount() const { + return sizeof(regs_struct) / sizeof(uptr); +} +} // namespace __sanitizer + +#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) + // || defined(__aarch64__) || defined(__powerpc64__) + // || defined(__s390__) || defined(__i386__) || defined(__arm__) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc deleted file mode 100644 index e79edc40f98f..000000000000 --- a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cc +++ /dev/null @@ -1,177 +0,0 @@ -//===-- sanitizer_stoptheworld_mac.cc -------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// See sanitizer_stoptheworld.h for details. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__) || \ - defined(__i386)) - -#include -#include -#include - -#include "sanitizer_stoptheworld.h" - -namespace __sanitizer { -typedef struct { - tid_t tid; - thread_t thread; -} SuspendedThreadInfo; - -class SuspendedThreadsListMac : public SuspendedThreadsList { - public: - SuspendedThreadsListMac() : threads_(1024) {} - - tid_t GetThreadID(uptr index) const; - thread_t GetThread(uptr index) const; - uptr ThreadCount() const; - bool ContainsThread(thread_t thread) const; - void Append(thread_t thread); - - PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, - uptr *sp) const; - uptr RegisterCount() const; - - private: - InternalMmapVector threads_; -}; - -struct RunThreadArgs { - StopTheWorldCallback callback; - void *argument; -}; - -void RunThread(void *arg) { - struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg; - SuspendedThreadsListMac suspended_threads_list; - - thread_array_t threads; - mach_msg_type_number_t num_threads; - kern_return_t err = task_threads(mach_task_self(), &threads, &num_threads); - if (err != KERN_SUCCESS) { - VReport(1, "Failed to get threads for task (errno %d).\n", err); - return; - } - - thread_t thread_self = mach_thread_self(); - for (unsigned int i = 0; i < num_threads; ++i) { - if (threads[i] == thread_self) continue; - - thread_suspend(threads[i]); - suspended_threads_list.Append(threads[i]); - } - - run_args->callback(suspended_threads_list, run_args->argument); - - uptr num_suspended = suspended_threads_list.ThreadCount(); - for (unsigned int i = 0; i < num_suspended; ++i) { - thread_resume(suspended_threads_list.GetThread(i)); - } -} - -void StopTheWorld(StopTheWorldCallback callback, void *argument) { - struct RunThreadArgs arg = {callback, argument}; - pthread_t run_thread = (pthread_t)internal_start_thread(RunThread, &arg); - internal_join_thread(run_thread); -} - -#if defined(__x86_64__) -typedef x86_thread_state64_t regs_struct; - -#define SP_REG __rsp - -#elif defined(__aarch64__) -typedef arm_thread_state64_t regs_struct; - -# if __DARWIN_UNIX03 -# define SP_REG __sp -# else -# define SP_REG sp -# endif - -#elif defined(__i386) -typedef x86_thread_state32_t regs_struct; - -#define SP_REG __esp - -#else -#error "Unsupported architecture" -#endif - -tid_t SuspendedThreadsListMac::GetThreadID(uptr index) const { - CHECK_LT(index, threads_.size()); - return threads_[index].tid; -} - -thread_t SuspendedThreadsListMac::GetThread(uptr index) const { - CHECK_LT(index, threads_.size()); - return threads_[index].thread; -} - -uptr SuspendedThreadsListMac::ThreadCount() const { - return threads_.size(); -} - -bool SuspendedThreadsListMac::ContainsThread(thread_t thread) const { - for (uptr i = 0; i < threads_.size(); i++) { - if (threads_[i].thread == thread) return true; - } - return false; -} - -void SuspendedThreadsListMac::Append(thread_t thread) { - thread_identifier_info_data_t info; - mach_msg_type_number_t info_count = THREAD_IDENTIFIER_INFO_COUNT; - kern_return_t err = thread_info(thread, THREAD_IDENTIFIER_INFO, - (thread_info_t)&info, &info_count); - if (err != KERN_SUCCESS) { - VReport(1, "Error - unable to get thread ident for a thread\n"); - return; - } - threads_.push_back({info.thread_id, thread}); -} - -PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( - uptr index, uptr *buffer, uptr *sp) const { - thread_t thread = GetThread(index); - regs_struct regs; - int err; - mach_msg_type_number_t reg_count = MACHINE_THREAD_STATE_COUNT; - err = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)®s, - ®_count); - if (err != KERN_SUCCESS) { - VReport(1, "Error - unable to get registers for a thread\n"); - // KERN_INVALID_ARGUMENT indicates that either the flavor is invalid, - // or the thread does not exist. The other possible error case, - // MIG_ARRAY_TOO_LARGE, means that the state is too large, but it's - // still safe to proceed. - return err == KERN_INVALID_ARGUMENT ? REGISTERS_UNAVAILABLE_FATAL - : REGISTERS_UNAVAILABLE; - } - - internal_memcpy(buffer, ®s, sizeof(regs)); - *sp = regs.SP_REG; - - // On x86_64 and aarch64, we must account for the stack redzone, which is 128 - // bytes. - if (SANITIZER_WORDSIZE == 64) *sp -= 128; - - return REGISTERS_AVAILABLE; -} - -uptr SuspendedThreadsListMac::RegisterCount() const { - return MACHINE_THREAD_STATE_COUNT; -} -} // namespace __sanitizer - -#endif // SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__)) || - // defined(__i386)) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp new file mode 100644 index 000000000000..9dffd21ecb7c --- /dev/null +++ b/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp @@ -0,0 +1,177 @@ +//===-- sanitizer_stoptheworld_mac.cpp ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// See sanitizer_stoptheworld.h for details. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__) || \ + defined(__i386)) + +#include +#include +#include + +#include "sanitizer_stoptheworld.h" + +namespace __sanitizer { +typedef struct { + tid_t tid; + thread_t thread; +} SuspendedThreadInfo; + +class SuspendedThreadsListMac : public SuspendedThreadsList { + public: + SuspendedThreadsListMac() : threads_(1024) {} + + tid_t GetThreadID(uptr index) const; + thread_t GetThread(uptr index) const; + uptr ThreadCount() const; + bool ContainsThread(thread_t thread) const; + void Append(thread_t thread); + + PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, + uptr *sp) const; + uptr RegisterCount() const; + + private: + InternalMmapVector threads_; +}; + +struct RunThreadArgs { + StopTheWorldCallback callback; + void *argument; +}; + +void RunThread(void *arg) { + struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg; + SuspendedThreadsListMac suspended_threads_list; + + thread_array_t threads; + mach_msg_type_number_t num_threads; + kern_return_t err = task_threads(mach_task_self(), &threads, &num_threads); + if (err != KERN_SUCCESS) { + VReport(1, "Failed to get threads for task (errno %d).\n", err); + return; + } + + thread_t thread_self = mach_thread_self(); + for (unsigned int i = 0; i < num_threads; ++i) { + if (threads[i] == thread_self) continue; + + thread_suspend(threads[i]); + suspended_threads_list.Append(threads[i]); + } + + run_args->callback(suspended_threads_list, run_args->argument); + + uptr num_suspended = suspended_threads_list.ThreadCount(); + for (unsigned int i = 0; i < num_suspended; ++i) { + thread_resume(suspended_threads_list.GetThread(i)); + } +} + +void StopTheWorld(StopTheWorldCallback callback, void *argument) { + struct RunThreadArgs arg = {callback, argument}; + pthread_t run_thread = (pthread_t)internal_start_thread(RunThread, &arg); + internal_join_thread(run_thread); +} + +#if defined(__x86_64__) +typedef x86_thread_state64_t regs_struct; + +#define SP_REG __rsp + +#elif defined(__aarch64__) +typedef arm_thread_state64_t regs_struct; + +# if __DARWIN_UNIX03 +# define SP_REG __sp +# else +# define SP_REG sp +# endif + +#elif defined(__i386) +typedef x86_thread_state32_t regs_struct; + +#define SP_REG __esp + +#else +#error "Unsupported architecture" +#endif + +tid_t SuspendedThreadsListMac::GetThreadID(uptr index) const { + CHECK_LT(index, threads_.size()); + return threads_[index].tid; +} + +thread_t SuspendedThreadsListMac::GetThread(uptr index) const { + CHECK_LT(index, threads_.size()); + return threads_[index].thread; +} + +uptr SuspendedThreadsListMac::ThreadCount() const { + return threads_.size(); +} + +bool SuspendedThreadsListMac::ContainsThread(thread_t thread) const { + for (uptr i = 0; i < threads_.size(); i++) { + if (threads_[i].thread == thread) return true; + } + return false; +} + +void SuspendedThreadsListMac::Append(thread_t thread) { + thread_identifier_info_data_t info; + mach_msg_type_number_t info_count = THREAD_IDENTIFIER_INFO_COUNT; + kern_return_t err = thread_info(thread, THREAD_IDENTIFIER_INFO, + (thread_info_t)&info, &info_count); + if (err != KERN_SUCCESS) { + VReport(1, "Error - unable to get thread ident for a thread\n"); + return; + } + threads_.push_back({info.thread_id, thread}); +} + +PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( + uptr index, uptr *buffer, uptr *sp) const { + thread_t thread = GetThread(index); + regs_struct regs; + int err; + mach_msg_type_number_t reg_count = MACHINE_THREAD_STATE_COUNT; + err = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)®s, + ®_count); + if (err != KERN_SUCCESS) { + VReport(1, "Error - unable to get registers for a thread\n"); + // KERN_INVALID_ARGUMENT indicates that either the flavor is invalid, + // or the thread does not exist. The other possible error case, + // MIG_ARRAY_TOO_LARGE, means that the state is too large, but it's + // still safe to proceed. + return err == KERN_INVALID_ARGUMENT ? REGISTERS_UNAVAILABLE_FATAL + : REGISTERS_UNAVAILABLE; + } + + internal_memcpy(buffer, ®s, sizeof(regs)); + *sp = regs.SP_REG; + + // On x86_64 and aarch64, we must account for the stack redzone, which is 128 + // bytes. + if (SANITIZER_WORDSIZE == 64) *sp -= 128; + + return REGISTERS_AVAILABLE; +} + +uptr SuspendedThreadsListMac::RegisterCount() const { + return MACHINE_THREAD_STATE_COUNT; +} +} // namespace __sanitizer + +#endif // SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__)) || + // defined(__i386)) diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cc deleted file mode 100644 index 7a8d14ae741e..000000000000 --- a/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cc +++ /dev/null @@ -1,356 +0,0 @@ -//===-- sanitizer_stoptheworld_netbsd_libcdep.cc --------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// See sanitizer_stoptheworld.h for details. -// This implementation was inspired by Markus Gutschke's linuxthreads.cc. -// -// This is a NetBSD variation of Linux stoptheworld implementation -// See sanitizer_stoptheworld_linux_libcdep.cc for code comments. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_NETBSD - -#include "sanitizer_stoptheworld.h" - -#include "sanitizer_atomic.h" -#include "sanitizer_platform_limits_posix.h" - -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#define internal_sigaction_norestorer internal_sigaction - -#include "sanitizer_common.h" -#include "sanitizer_flags.h" -#include "sanitizer_libc.h" -#include "sanitizer_linux.h" -#include "sanitizer_mutex.h" -#include "sanitizer_placement_new.h" - -namespace __sanitizer { - -class SuspendedThreadsListNetBSD : public SuspendedThreadsList { - public: - SuspendedThreadsListNetBSD() { thread_ids_.reserve(1024); } - - tid_t GetThreadID(uptr index) const; - uptr ThreadCount() const; - bool ContainsTid(tid_t thread_id) const; - void Append(tid_t tid); - - PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, - uptr *sp) const; - uptr RegisterCount() const; - - private: - InternalMmapVector thread_ids_; -}; - -struct TracerThreadArgument { - StopTheWorldCallback callback; - void *callback_argument; - BlockingMutex mutex; - atomic_uintptr_t done; - uptr parent_pid; -}; - -class ThreadSuspender { - public: - explicit ThreadSuspender(pid_t pid, TracerThreadArgument *arg) - : arg(arg), pid_(pid) { - CHECK_GE(pid, 0); - } - bool SuspendAllThreads(); - void ResumeAllThreads(); - void KillAllThreads(); - SuspendedThreadsListNetBSD &suspended_threads_list() { - return suspended_threads_list_; - } - TracerThreadArgument *arg; - - private: - SuspendedThreadsListNetBSD suspended_threads_list_; - pid_t pid_; -}; - -void ThreadSuspender::ResumeAllThreads() { - int pterrno; - if (!internal_iserror(internal_ptrace(PT_DETACH, pid_, (void *)(uptr)1, 0), - &pterrno)) { - VReport(2, "Detached from process %d.\n", pid_); - } else { - VReport(1, "Could not detach from process %d (errno %d).\n", pid_, pterrno); - } -} - -void ThreadSuspender::KillAllThreads() { - internal_ptrace(PT_KILL, pid_, nullptr, 0); -} - -bool ThreadSuspender::SuspendAllThreads() { - int pterrno; - if (internal_iserror(internal_ptrace(PT_ATTACH, pid_, nullptr, 0), - &pterrno)) { - Printf("Could not attach to process %d (errno %d).\n", pid_, pterrno); - return false; - } - - int status; - uptr waitpid_status; - HANDLE_EINTR(waitpid_status, internal_waitpid(pid_, &status, 0)); - - VReport(2, "Attached to process %d.\n", pid_); - - struct ptrace_lwpinfo pl; - int val; - pl.pl_lwpid = 0; - while ((val = ptrace(PT_LWPINFO, pid_, (void *)&pl, sizeof(pl))) != -1 && - pl.pl_lwpid != 0) { - suspended_threads_list_.Append(pl.pl_lwpid); - VReport(2, "Appended thread %d in process %d.\n", pl.pl_lwpid, pid_); - } - return true; -} - -// Pointer to the ThreadSuspender instance for use in signal handler. -static ThreadSuspender *thread_suspender_instance = nullptr; - -// Synchronous signals that should not be blocked. -static const int kSyncSignals[] = {SIGABRT, SIGILL, SIGFPE, SIGSEGV, - SIGBUS, SIGXCPU, SIGXFSZ}; - -static void TracerThreadDieCallback() { - ThreadSuspender *inst = thread_suspender_instance; - if (inst && stoptheworld_tracer_pid == internal_getpid()) { - inst->KillAllThreads(); - thread_suspender_instance = nullptr; - } -} - -// Signal handler to wake up suspended threads when the tracer thread dies. -static void TracerThreadSignalHandler(int signum, __sanitizer_siginfo *siginfo, - void *uctx) { - SignalContext ctx(siginfo, uctx); - Printf("Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n", signum, - ctx.addr, ctx.pc, ctx.sp); - ThreadSuspender *inst = thread_suspender_instance; - if (inst) { - if (signum == SIGABRT) - inst->KillAllThreads(); - else - inst->ResumeAllThreads(); - RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); - thread_suspender_instance = nullptr; - atomic_store(&inst->arg->done, 1, memory_order_relaxed); - } - internal__exit((signum == SIGABRT) ? 1 : 2); -} - -// Size of alternative stack for signal handlers in the tracer thread. -static const int kHandlerStackSize = 8192; - -// This function will be run as a cloned task. -static int TracerThread(void *argument) { - TracerThreadArgument *tracer_thread_argument = - (TracerThreadArgument *)argument; - - // Check if parent is already dead. - if (internal_getppid() != tracer_thread_argument->parent_pid) - internal__exit(4); - - // Wait for the parent thread to finish preparations. - tracer_thread_argument->mutex.Lock(); - tracer_thread_argument->mutex.Unlock(); - - RAW_CHECK(AddDieCallback(TracerThreadDieCallback)); - - ThreadSuspender thread_suspender(internal_getppid(), tracer_thread_argument); - // Global pointer for the signal handler. - thread_suspender_instance = &thread_suspender; - - // Alternate stack for signal handling. - InternalMmapVector handler_stack_memory(kHandlerStackSize); - stack_t handler_stack; - internal_memset(&handler_stack, 0, sizeof(handler_stack)); - handler_stack.ss_sp = handler_stack_memory.data(); - handler_stack.ss_size = kHandlerStackSize; - internal_sigaltstack(&handler_stack, nullptr); - - // Install our handler for synchronous signals. Other signals should be - // blocked by the mask we inherited from the parent thread. - for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) { - __sanitizer_sigaction act; - internal_memset(&act, 0, sizeof(act)); - act.sigaction = TracerThreadSignalHandler; - act.sa_flags = SA_ONSTACK | SA_SIGINFO; - internal_sigaction_norestorer(kSyncSignals[i], &act, 0); - } - - int exit_code = 0; - if (!thread_suspender.SuspendAllThreads()) { - VReport(1, "Failed suspending threads.\n"); - exit_code = 3; - } else { - tracer_thread_argument->callback(thread_suspender.suspended_threads_list(), - tracer_thread_argument->callback_argument); - thread_suspender.ResumeAllThreads(); - exit_code = 0; - } - RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); - thread_suspender_instance = nullptr; - atomic_store(&tracer_thread_argument->done, 1, memory_order_relaxed); - return exit_code; -} - -class ScopedStackSpaceWithGuard { - public: - explicit ScopedStackSpaceWithGuard(uptr stack_size) { - stack_size_ = stack_size; - guard_size_ = GetPageSizeCached(); - // FIXME: Omitting MAP_STACK here works in current kernels but might break - // in the future. - guard_start_ = - (uptr)MmapOrDie(stack_size_ + guard_size_, "ScopedStackWithGuard"); - CHECK(MprotectNoAccess((uptr)guard_start_, guard_size_)); - } - ~ScopedStackSpaceWithGuard() { - UnmapOrDie((void *)guard_start_, stack_size_ + guard_size_); - } - void *Bottom() const { - return (void *)(guard_start_ + stack_size_ + guard_size_); - } - - private: - uptr stack_size_; - uptr guard_size_; - uptr guard_start_; -}; - -static __sanitizer_sigset_t blocked_sigset; -static __sanitizer_sigset_t old_sigset; - -struct ScopedSetTracerPID { - explicit ScopedSetTracerPID(uptr tracer_pid) { - stoptheworld_tracer_pid = tracer_pid; - stoptheworld_tracer_ppid = internal_getpid(); - } - ~ScopedSetTracerPID() { - stoptheworld_tracer_pid = 0; - stoptheworld_tracer_ppid = 0; - } -}; - -void StopTheWorld(StopTheWorldCallback callback, void *argument) { - // Prepare the arguments for TracerThread. - struct TracerThreadArgument tracer_thread_argument; - tracer_thread_argument.callback = callback; - tracer_thread_argument.callback_argument = argument; - tracer_thread_argument.parent_pid = internal_getpid(); - atomic_store(&tracer_thread_argument.done, 0, memory_order_relaxed); - const uptr kTracerStackSize = 2 * 1024 * 1024; - ScopedStackSpaceWithGuard tracer_stack(kTracerStackSize); - - tracer_thread_argument.mutex.Lock(); - - internal_sigfillset(&blocked_sigset); - for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) - internal_sigdelset(&blocked_sigset, kSyncSignals[i]); - int rv = internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset); - CHECK_EQ(rv, 0); - uptr tracer_pid = internal_clone(TracerThread, tracer_stack.Bottom(), - CLONE_VM | CLONE_FS | CLONE_FILES, - &tracer_thread_argument); - internal_sigprocmask(SIG_SETMASK, &old_sigset, 0); - int local_errno = 0; - if (internal_iserror(tracer_pid, &local_errno)) { - VReport(1, "Failed spawning a tracer thread (errno %d).\n", local_errno); - tracer_thread_argument.mutex.Unlock(); - } else { - ScopedSetTracerPID scoped_set_tracer_pid(tracer_pid); - - tracer_thread_argument.mutex.Unlock(); - - while (atomic_load(&tracer_thread_argument.done, memory_order_relaxed) == 0) - sched_yield(); - - for (;;) { - uptr waitpid_status = internal_waitpid(tracer_pid, nullptr, __WALL); - if (!internal_iserror(waitpid_status, &local_errno)) - break; - if (local_errno == EINTR) - continue; - VReport(1, "Waiting on the tracer thread failed (errno %d).\n", - local_errno); - break; - } - } -} - -tid_t SuspendedThreadsListNetBSD::GetThreadID(uptr index) const { - CHECK_LT(index, thread_ids_.size()); - return thread_ids_[index]; -} - -uptr SuspendedThreadsListNetBSD::ThreadCount() const { - return thread_ids_.size(); -} - -bool SuspendedThreadsListNetBSD::ContainsTid(tid_t thread_id) const { - for (uptr i = 0; i < thread_ids_.size(); i++) { - if (thread_ids_[i] == thread_id) - return true; - } - return false; -} - -void SuspendedThreadsListNetBSD::Append(tid_t tid) { - thread_ids_.push_back(tid); -} - -PtraceRegistersStatus SuspendedThreadsListNetBSD::GetRegistersAndSP( - uptr index, uptr *buffer, uptr *sp) const { - lwpid_t tid = GetThreadID(index); - pid_t ppid = internal_getppid(); - struct reg regs; - int pterrno; - bool isErr = - internal_iserror(internal_ptrace(PT_GETREGS, ppid, ®s, tid), &pterrno); - if (isErr) { - VReport(1, - "Could not get registers from process %d thread %d (errno %d).\n", - ppid, tid, pterrno); - return pterrno == ESRCH ? REGISTERS_UNAVAILABLE_FATAL - : REGISTERS_UNAVAILABLE; - } - - *sp = PTRACE_REG_SP(®s); - internal_memcpy(buffer, ®s, sizeof(regs)); - - return REGISTERS_AVAILABLE; -} - -uptr SuspendedThreadsListNetBSD::RegisterCount() const { - return sizeof(struct reg) / sizeof(uptr); -} -} // namespace __sanitizer - -#endif diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp b/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp new file mode 100644 index 000000000000..5690d75097f9 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp @@ -0,0 +1,356 @@ +//===-- sanitizer_stoptheworld_netbsd_libcdep.cpp -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// See sanitizer_stoptheworld.h for details. +// This implementation was inspired by Markus Gutschke's linuxthreads.cc. +// +// This is a NetBSD variation of Linux stoptheworld implementation +// See sanitizer_stoptheworld_linux_libcdep.cpp for code comments. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_NETBSD + +#include "sanitizer_stoptheworld.h" + +#include "sanitizer_atomic.h" +#include "sanitizer_platform_limits_posix.h" + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#define internal_sigaction_norestorer internal_sigaction + +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_libc.h" +#include "sanitizer_linux.h" +#include "sanitizer_mutex.h" +#include "sanitizer_placement_new.h" + +namespace __sanitizer { + +class SuspendedThreadsListNetBSD : public SuspendedThreadsList { + public: + SuspendedThreadsListNetBSD() { thread_ids_.reserve(1024); } + + tid_t GetThreadID(uptr index) const; + uptr ThreadCount() const; + bool ContainsTid(tid_t thread_id) const; + void Append(tid_t tid); + + PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, + uptr *sp) const; + uptr RegisterCount() const; + + private: + InternalMmapVector thread_ids_; +}; + +struct TracerThreadArgument { + StopTheWorldCallback callback; + void *callback_argument; + BlockingMutex mutex; + atomic_uintptr_t done; + uptr parent_pid; +}; + +class ThreadSuspender { + public: + explicit ThreadSuspender(pid_t pid, TracerThreadArgument *arg) + : arg(arg), pid_(pid) { + CHECK_GE(pid, 0); + } + bool SuspendAllThreads(); + void ResumeAllThreads(); + void KillAllThreads(); + SuspendedThreadsListNetBSD &suspended_threads_list() { + return suspended_threads_list_; + } + TracerThreadArgument *arg; + + private: + SuspendedThreadsListNetBSD suspended_threads_list_; + pid_t pid_; +}; + +void ThreadSuspender::ResumeAllThreads() { + int pterrno; + if (!internal_iserror(internal_ptrace(PT_DETACH, pid_, (void *)(uptr)1, 0), + &pterrno)) { + VReport(2, "Detached from process %d.\n", pid_); + } else { + VReport(1, "Could not detach from process %d (errno %d).\n", pid_, pterrno); + } +} + +void ThreadSuspender::KillAllThreads() { + internal_ptrace(PT_KILL, pid_, nullptr, 0); +} + +bool ThreadSuspender::SuspendAllThreads() { + int pterrno; + if (internal_iserror(internal_ptrace(PT_ATTACH, pid_, nullptr, 0), + &pterrno)) { + Printf("Could not attach to process %d (errno %d).\n", pid_, pterrno); + return false; + } + + int status; + uptr waitpid_status; + HANDLE_EINTR(waitpid_status, internal_waitpid(pid_, &status, 0)); + + VReport(2, "Attached to process %d.\n", pid_); + + struct ptrace_lwpinfo pl; + int val; + pl.pl_lwpid = 0; + while ((val = ptrace(PT_LWPINFO, pid_, (void *)&pl, sizeof(pl))) != -1 && + pl.pl_lwpid != 0) { + suspended_threads_list_.Append(pl.pl_lwpid); + VReport(2, "Appended thread %d in process %d.\n", pl.pl_lwpid, pid_); + } + return true; +} + +// Pointer to the ThreadSuspender instance for use in signal handler. +static ThreadSuspender *thread_suspender_instance = nullptr; + +// Synchronous signals that should not be blocked. +static const int kSyncSignals[] = {SIGABRT, SIGILL, SIGFPE, SIGSEGV, + SIGBUS, SIGXCPU, SIGXFSZ}; + +static void TracerThreadDieCallback() { + ThreadSuspender *inst = thread_suspender_instance; + if (inst && stoptheworld_tracer_pid == internal_getpid()) { + inst->KillAllThreads(); + thread_suspender_instance = nullptr; + } +} + +// Signal handler to wake up suspended threads when the tracer thread dies. +static void TracerThreadSignalHandler(int signum, __sanitizer_siginfo *siginfo, + void *uctx) { + SignalContext ctx(siginfo, uctx); + Printf("Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n", signum, + ctx.addr, ctx.pc, ctx.sp); + ThreadSuspender *inst = thread_suspender_instance; + if (inst) { + if (signum == SIGABRT) + inst->KillAllThreads(); + else + inst->ResumeAllThreads(); + RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); + thread_suspender_instance = nullptr; + atomic_store(&inst->arg->done, 1, memory_order_relaxed); + } + internal__exit((signum == SIGABRT) ? 1 : 2); +} + +// Size of alternative stack for signal handlers in the tracer thread. +static const int kHandlerStackSize = 8192; + +// This function will be run as a cloned task. +static int TracerThread(void *argument) { + TracerThreadArgument *tracer_thread_argument = + (TracerThreadArgument *)argument; + + // Check if parent is already dead. + if (internal_getppid() != tracer_thread_argument->parent_pid) + internal__exit(4); + + // Wait for the parent thread to finish preparations. + tracer_thread_argument->mutex.Lock(); + tracer_thread_argument->mutex.Unlock(); + + RAW_CHECK(AddDieCallback(TracerThreadDieCallback)); + + ThreadSuspender thread_suspender(internal_getppid(), tracer_thread_argument); + // Global pointer for the signal handler. + thread_suspender_instance = &thread_suspender; + + // Alternate stack for signal handling. + InternalMmapVector handler_stack_memory(kHandlerStackSize); + stack_t handler_stack; + internal_memset(&handler_stack, 0, sizeof(handler_stack)); + handler_stack.ss_sp = handler_stack_memory.data(); + handler_stack.ss_size = kHandlerStackSize; + internal_sigaltstack(&handler_stack, nullptr); + + // Install our handler for synchronous signals. Other signals should be + // blocked by the mask we inherited from the parent thread. + for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) { + __sanitizer_sigaction act; + internal_memset(&act, 0, sizeof(act)); + act.sigaction = TracerThreadSignalHandler; + act.sa_flags = SA_ONSTACK | SA_SIGINFO; + internal_sigaction_norestorer(kSyncSignals[i], &act, 0); + } + + int exit_code = 0; + if (!thread_suspender.SuspendAllThreads()) { + VReport(1, "Failed suspending threads.\n"); + exit_code = 3; + } else { + tracer_thread_argument->callback(thread_suspender.suspended_threads_list(), + tracer_thread_argument->callback_argument); + thread_suspender.ResumeAllThreads(); + exit_code = 0; + } + RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); + thread_suspender_instance = nullptr; + atomic_store(&tracer_thread_argument->done, 1, memory_order_relaxed); + return exit_code; +} + +class ScopedStackSpaceWithGuard { + public: + explicit ScopedStackSpaceWithGuard(uptr stack_size) { + stack_size_ = stack_size; + guard_size_ = GetPageSizeCached(); + // FIXME: Omitting MAP_STACK here works in current kernels but might break + // in the future. + guard_start_ = + (uptr)MmapOrDie(stack_size_ + guard_size_, "ScopedStackWithGuard"); + CHECK(MprotectNoAccess((uptr)guard_start_, guard_size_)); + } + ~ScopedStackSpaceWithGuard() { + UnmapOrDie((void *)guard_start_, stack_size_ + guard_size_); + } + void *Bottom() const { + return (void *)(guard_start_ + stack_size_ + guard_size_); + } + + private: + uptr stack_size_; + uptr guard_size_; + uptr guard_start_; +}; + +static __sanitizer_sigset_t blocked_sigset; +static __sanitizer_sigset_t old_sigset; + +struct ScopedSetTracerPID { + explicit ScopedSetTracerPID(uptr tracer_pid) { + stoptheworld_tracer_pid = tracer_pid; + stoptheworld_tracer_ppid = internal_getpid(); + } + ~ScopedSetTracerPID() { + stoptheworld_tracer_pid = 0; + stoptheworld_tracer_ppid = 0; + } +}; + +void StopTheWorld(StopTheWorldCallback callback, void *argument) { + // Prepare the arguments for TracerThread. + struct TracerThreadArgument tracer_thread_argument; + tracer_thread_argument.callback = callback; + tracer_thread_argument.callback_argument = argument; + tracer_thread_argument.parent_pid = internal_getpid(); + atomic_store(&tracer_thread_argument.done, 0, memory_order_relaxed); + const uptr kTracerStackSize = 2 * 1024 * 1024; + ScopedStackSpaceWithGuard tracer_stack(kTracerStackSize); + + tracer_thread_argument.mutex.Lock(); + + internal_sigfillset(&blocked_sigset); + for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) + internal_sigdelset(&blocked_sigset, kSyncSignals[i]); + int rv = internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset); + CHECK_EQ(rv, 0); + uptr tracer_pid = internal_clone(TracerThread, tracer_stack.Bottom(), + CLONE_VM | CLONE_FS | CLONE_FILES, + &tracer_thread_argument); + internal_sigprocmask(SIG_SETMASK, &old_sigset, 0); + int local_errno = 0; + if (internal_iserror(tracer_pid, &local_errno)) { + VReport(1, "Failed spawning a tracer thread (errno %d).\n", local_errno); + tracer_thread_argument.mutex.Unlock(); + } else { + ScopedSetTracerPID scoped_set_tracer_pid(tracer_pid); + + tracer_thread_argument.mutex.Unlock(); + + while (atomic_load(&tracer_thread_argument.done, memory_order_relaxed) == 0) + sched_yield(); + + for (;;) { + uptr waitpid_status = internal_waitpid(tracer_pid, nullptr, __WALL); + if (!internal_iserror(waitpid_status, &local_errno)) + break; + if (local_errno == EINTR) + continue; + VReport(1, "Waiting on the tracer thread failed (errno %d).\n", + local_errno); + break; + } + } +} + +tid_t SuspendedThreadsListNetBSD::GetThreadID(uptr index) const { + CHECK_LT(index, thread_ids_.size()); + return thread_ids_[index]; +} + +uptr SuspendedThreadsListNetBSD::ThreadCount() const { + return thread_ids_.size(); +} + +bool SuspendedThreadsListNetBSD::ContainsTid(tid_t thread_id) const { + for (uptr i = 0; i < thread_ids_.size(); i++) { + if (thread_ids_[i] == thread_id) + return true; + } + return false; +} + +void SuspendedThreadsListNetBSD::Append(tid_t tid) { + thread_ids_.push_back(tid); +} + +PtraceRegistersStatus SuspendedThreadsListNetBSD::GetRegistersAndSP( + uptr index, uptr *buffer, uptr *sp) const { + lwpid_t tid = GetThreadID(index); + pid_t ppid = internal_getppid(); + struct reg regs; + int pterrno; + bool isErr = + internal_iserror(internal_ptrace(PT_GETREGS, ppid, ®s, tid), &pterrno); + if (isErr) { + VReport(1, + "Could not get registers from process %d thread %d (errno %d).\n", + ppid, tid, pterrno); + return pterrno == ESRCH ? REGISTERS_UNAVAILABLE_FATAL + : REGISTERS_UNAVAILABLE; + } + + *sp = PTRACE_REG_SP(®s); + internal_memcpy(buffer, ®s, sizeof(regs)); + + return REGISTERS_AVAILABLE; +} + +uptr SuspendedThreadsListNetBSD::RegisterCount() const { + return sizeof(struct reg) / sizeof(uptr); +} +} // namespace __sanitizer + +#endif diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc deleted file mode 100644 index 12ecd9a2e368..000000000000 --- a/lib/sanitizer_common/sanitizer_suppressions.cc +++ /dev/null @@ -1,181 +0,0 @@ -//===-- sanitizer_suppressions.cc -----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Suppression parsing/matching code. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_suppressions.h" - -#include "sanitizer_allocator_internal.h" -#include "sanitizer_common.h" -#include "sanitizer_flags.h" -#include "sanitizer_file.h" -#include "sanitizer_libc.h" -#include "sanitizer_placement_new.h" - -namespace __sanitizer { - -SuppressionContext::SuppressionContext(const char *suppression_types[], - int suppression_types_num) - : suppression_types_(suppression_types), - suppression_types_num_(suppression_types_num), - can_parse_(true) { - CHECK_LE(suppression_types_num_, kMaxSuppressionTypes); - internal_memset(has_suppression_type_, 0, suppression_types_num_); -} - -#if !SANITIZER_FUCHSIA -static bool GetPathAssumingFileIsRelativeToExec(const char *file_path, - /*out*/char *new_file_path, - uptr new_file_path_size) { - InternalScopedString exec(kMaxPathLength); - if (ReadBinaryNameCached(exec.data(), exec.size())) { - const char *file_name_pos = StripModuleName(exec.data()); - uptr path_to_exec_len = file_name_pos - exec.data(); - internal_strncat(new_file_path, exec.data(), - Min(path_to_exec_len, new_file_path_size - 1)); - internal_strncat(new_file_path, file_path, - new_file_path_size - internal_strlen(new_file_path) - 1); - return true; - } - return false; -} - -static const char *FindFile(const char *file_path, - /*out*/char *new_file_path, - uptr new_file_path_size) { - // If we cannot find the file, check if its location is relative to - // the location of the executable. - if (!FileExists(file_path) && !IsAbsolutePath(file_path) && - GetPathAssumingFileIsRelativeToExec(file_path, new_file_path, - new_file_path_size)) { - return new_file_path; - } - return file_path; -} -#else -static const char *FindFile(const char *file_path, char *, uptr) { - return file_path; -} -#endif - -void SuppressionContext::ParseFromFile(const char *filename) { - if (filename[0] == '\0') - return; - - InternalScopedString new_file_path(kMaxPathLength); - filename = FindFile(filename, new_file_path.data(), new_file_path.size()); - - // Read the file. - VPrintf(1, "%s: reading suppressions file at %s\n", - SanitizerToolName, filename); - char *file_contents; - uptr buffer_size; - uptr contents_size; - if (!ReadFileToBuffer(filename, &file_contents, &buffer_size, - &contents_size)) { - Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName, - filename); - Die(); - } - - Parse(file_contents); -} - -bool SuppressionContext::Match(const char *str, const char *type, - Suppression **s) { - can_parse_ = false; - if (!HasSuppressionType(type)) - return false; - for (uptr i = 0; i < suppressions_.size(); i++) { - Suppression &cur = suppressions_[i]; - if (0 == internal_strcmp(cur.type, type) && TemplateMatch(cur.templ, str)) { - *s = &cur; - return true; - } - } - return false; -} - -static const char *StripPrefix(const char *str, const char *prefix) { - while (*str && *str == *prefix) { - str++; - prefix++; - } - if (!*prefix) - return str; - return 0; -} - -void SuppressionContext::Parse(const char *str) { - // Context must not mutate once Match has been called. - CHECK(can_parse_); - const char *line = str; - while (line) { - while (line[0] == ' ' || line[0] == '\t') - line++; - const char *end = internal_strchr(line, '\n'); - if (end == 0) - end = line + internal_strlen(line); - if (line != end && line[0] != '#') { - const char *end2 = end; - while (line != end2 && - (end2[-1] == ' ' || end2[-1] == '\t' || end2[-1] == '\r')) - end2--; - int type; - for (type = 0; type < suppression_types_num_; type++) { - const char *next_char = StripPrefix(line, suppression_types_[type]); - if (next_char && *next_char == ':') { - line = ++next_char; - break; - } - } - if (type == suppression_types_num_) { - Printf("%s: failed to parse suppressions\n", SanitizerToolName); - Die(); - } - Suppression s; - s.type = suppression_types_[type]; - s.templ = (char*)InternalAlloc(end2 - line + 1); - internal_memcpy(s.templ, line, end2 - line); - s.templ[end2 - line] = 0; - suppressions_.push_back(s); - has_suppression_type_[type] = true; - } - if (end[0] == 0) - break; - line = end + 1; - } -} - -uptr SuppressionContext::SuppressionCount() const { - return suppressions_.size(); -} - -bool SuppressionContext::HasSuppressionType(const char *type) const { - for (int i = 0; i < suppression_types_num_; i++) { - if (0 == internal_strcmp(type, suppression_types_[i])) - return has_suppression_type_[i]; - } - return false; -} - -const Suppression *SuppressionContext::SuppressionAt(uptr i) const { - CHECK_LT(i, suppressions_.size()); - return &suppressions_[i]; -} - -void SuppressionContext::GetMatched( - InternalMmapVector *matched) { - for (uptr i = 0; i < suppressions_.size(); i++) - if (atomic_load_relaxed(&suppressions_[i].hit_count)) - matched->push_back(&suppressions_[i]); -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_suppressions.cpp b/lib/sanitizer_common/sanitizer_suppressions.cpp new file mode 100644 index 000000000000..44c83a66c5fe --- /dev/null +++ b/lib/sanitizer_common/sanitizer_suppressions.cpp @@ -0,0 +1,181 @@ +//===-- sanitizer_suppressions.cpp ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Suppression parsing/matching code. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_suppressions.h" + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_common.h" +#include "sanitizer_flags.h" +#include "sanitizer_file.h" +#include "sanitizer_libc.h" +#include "sanitizer_placement_new.h" + +namespace __sanitizer { + +SuppressionContext::SuppressionContext(const char *suppression_types[], + int suppression_types_num) + : suppression_types_(suppression_types), + suppression_types_num_(suppression_types_num), + can_parse_(true) { + CHECK_LE(suppression_types_num_, kMaxSuppressionTypes); + internal_memset(has_suppression_type_, 0, suppression_types_num_); +} + +#if !SANITIZER_FUCHSIA +static bool GetPathAssumingFileIsRelativeToExec(const char *file_path, + /*out*/char *new_file_path, + uptr new_file_path_size) { + InternalScopedString exec(kMaxPathLength); + if (ReadBinaryNameCached(exec.data(), exec.size())) { + const char *file_name_pos = StripModuleName(exec.data()); + uptr path_to_exec_len = file_name_pos - exec.data(); + internal_strncat(new_file_path, exec.data(), + Min(path_to_exec_len, new_file_path_size - 1)); + internal_strncat(new_file_path, file_path, + new_file_path_size - internal_strlen(new_file_path) - 1); + return true; + } + return false; +} + +static const char *FindFile(const char *file_path, + /*out*/char *new_file_path, + uptr new_file_path_size) { + // If we cannot find the file, check if its location is relative to + // the location of the executable. + if (!FileExists(file_path) && !IsAbsolutePath(file_path) && + GetPathAssumingFileIsRelativeToExec(file_path, new_file_path, + new_file_path_size)) { + return new_file_path; + } + return file_path; +} +#else +static const char *FindFile(const char *file_path, char *, uptr) { + return file_path; +} +#endif + +void SuppressionContext::ParseFromFile(const char *filename) { + if (filename[0] == '\0') + return; + + InternalScopedString new_file_path(kMaxPathLength); + filename = FindFile(filename, new_file_path.data(), new_file_path.size()); + + // Read the file. + VPrintf(1, "%s: reading suppressions file at %s\n", + SanitizerToolName, filename); + char *file_contents; + uptr buffer_size; + uptr contents_size; + if (!ReadFileToBuffer(filename, &file_contents, &buffer_size, + &contents_size)) { + Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName, + filename); + Die(); + } + + Parse(file_contents); +} + +bool SuppressionContext::Match(const char *str, const char *type, + Suppression **s) { + can_parse_ = false; + if (!HasSuppressionType(type)) + return false; + for (uptr i = 0; i < suppressions_.size(); i++) { + Suppression &cur = suppressions_[i]; + if (0 == internal_strcmp(cur.type, type) && TemplateMatch(cur.templ, str)) { + *s = &cur; + return true; + } + } + return false; +} + +static const char *StripPrefix(const char *str, const char *prefix) { + while (*str && *str == *prefix) { + str++; + prefix++; + } + if (!*prefix) + return str; + return 0; +} + +void SuppressionContext::Parse(const char *str) { + // Context must not mutate once Match has been called. + CHECK(can_parse_); + const char *line = str; + while (line) { + while (line[0] == ' ' || line[0] == '\t') + line++; + const char *end = internal_strchr(line, '\n'); + if (end == 0) + end = line + internal_strlen(line); + if (line != end && line[0] != '#') { + const char *end2 = end; + while (line != end2 && + (end2[-1] == ' ' || end2[-1] == '\t' || end2[-1] == '\r')) + end2--; + int type; + for (type = 0; type < suppression_types_num_; type++) { + const char *next_char = StripPrefix(line, suppression_types_[type]); + if (next_char && *next_char == ':') { + line = ++next_char; + break; + } + } + if (type == suppression_types_num_) { + Printf("%s: failed to parse suppressions\n", SanitizerToolName); + Die(); + } + Suppression s; + s.type = suppression_types_[type]; + s.templ = (char*)InternalAlloc(end2 - line + 1); + internal_memcpy(s.templ, line, end2 - line); + s.templ[end2 - line] = 0; + suppressions_.push_back(s); + has_suppression_type_[type] = true; + } + if (end[0] == 0) + break; + line = end + 1; + } +} + +uptr SuppressionContext::SuppressionCount() const { + return suppressions_.size(); +} + +bool SuppressionContext::HasSuppressionType(const char *type) const { + for (int i = 0; i < suppression_types_num_; i++) { + if (0 == internal_strcmp(type, suppression_types_[i])) + return has_suppression_type_[i]; + } + return false; +} + +const Suppression *SuppressionContext::SuppressionAt(uptr i) const { + CHECK_LT(i, suppressions_.size()); + return &suppressions_[i]; +} + +void SuppressionContext::GetMatched( + InternalMmapVector *matched) { + for (uptr i = 0; i < suppressions_.size(); i++) + if (atomic_load_relaxed(&suppressions_[i].hit_count)) + matched->push_back(&suppressions_[i]); +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_suppressions.h b/lib/sanitizer_common/sanitizer_suppressions.h index f9da7af7e6ab..2d88b1f72fa6 100644 --- a/lib/sanitizer_common/sanitizer_suppressions.h +++ b/lib/sanitizer_common/sanitizer_suppressions.h @@ -42,7 +42,7 @@ class SuppressionContext { void GetMatched(InternalMmapVector *matched); private: - static const int kMaxSuppressionTypes = 32; + static const int kMaxSuppressionTypes = 64; const char **const suppression_types_; const int suppression_types_num_; diff --git a/lib/sanitizer_common/sanitizer_symbolizer.cc b/lib/sanitizer_common/sanitizer_symbolizer.cc deleted file mode 100644 index 216ce585a0c6..000000000000 --- a/lib/sanitizer_common/sanitizer_symbolizer.cc +++ /dev/null @@ -1,129 +0,0 @@ -//===-- sanitizer_symbolizer.cc -------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. -//===----------------------------------------------------------------------===// - -#include "sanitizer_allocator_internal.h" -#include "sanitizer_platform.h" -#include "sanitizer_internal_defs.h" -#include "sanitizer_libc.h" -#include "sanitizer_placement_new.h" -#include "sanitizer_symbolizer_internal.h" - -namespace __sanitizer { - -AddressInfo::AddressInfo() { - internal_memset(this, 0, sizeof(AddressInfo)); - function_offset = kUnknown; -} - -void AddressInfo::Clear() { - InternalFree(module); - InternalFree(function); - InternalFree(file); - internal_memset(this, 0, sizeof(AddressInfo)); - function_offset = kUnknown; -} - -void AddressInfo::FillModuleInfo(const char *mod_name, uptr mod_offset, - ModuleArch mod_arch) { - module = internal_strdup(mod_name); - module_offset = mod_offset; - module_arch = mod_arch; -} - -SymbolizedStack::SymbolizedStack() : next(nullptr), info() {} - -SymbolizedStack *SymbolizedStack::New(uptr addr) { - void *mem = InternalAlloc(sizeof(SymbolizedStack)); - SymbolizedStack *res = new(mem) SymbolizedStack(); - res->info.address = addr; - return res; -} - -void SymbolizedStack::ClearAll() { - info.Clear(); - if (next) - next->ClearAll(); - InternalFree(this); -} - -DataInfo::DataInfo() { - internal_memset(this, 0, sizeof(DataInfo)); -} - -void DataInfo::Clear() { - InternalFree(module); - InternalFree(file); - InternalFree(name); - internal_memset(this, 0, sizeof(DataInfo)); -} - -void FrameInfo::Clear() { - InternalFree(module); - for (LocalInfo &local : locals) { - InternalFree(local.function_name); - InternalFree(local.name); - InternalFree(local.decl_file); - } - locals.clear(); -} - -Symbolizer *Symbolizer::symbolizer_; -StaticSpinMutex Symbolizer::init_mu_; -LowLevelAllocator Symbolizer::symbolizer_allocator_; - -void Symbolizer::InvalidateModuleList() { - modules_fresh_ = false; -} - -void Symbolizer::AddHooks(Symbolizer::StartSymbolizationHook start_hook, - Symbolizer::EndSymbolizationHook end_hook) { - CHECK(start_hook_ == 0 && end_hook_ == 0); - start_hook_ = start_hook; - end_hook_ = end_hook; -} - -const char *Symbolizer::ModuleNameOwner::GetOwnedCopy(const char *str) { - mu_->CheckLocked(); - - // 'str' will be the same string multiple times in a row, optimize this case. - if (last_match_ && !internal_strcmp(last_match_, str)) - return last_match_; - - // FIXME: this is linear search. - // We should optimize this further if this turns out to be a bottleneck later. - for (uptr i = 0; i < storage_.size(); ++i) { - if (!internal_strcmp(storage_[i], str)) { - last_match_ = storage_[i]; - return last_match_; - } - } - last_match_ = internal_strdup(str); - storage_.push_back(last_match_); - return last_match_; -} - -Symbolizer::Symbolizer(IntrusiveList tools) - : module_names_(&mu_), modules_(), modules_fresh_(false), tools_(tools), - start_hook_(0), end_hook_(0) {} - -Symbolizer::SymbolizerScope::SymbolizerScope(const Symbolizer *sym) - : sym_(sym) { - if (sym_->start_hook_) - sym_->start_hook_(); -} - -Symbolizer::SymbolizerScope::~SymbolizerScope() { - if (sym_->end_hook_) - sym_->end_hook_(); -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer.cpp b/lib/sanitizer_common/sanitizer_symbolizer.cpp new file mode 100644 index 000000000000..ce2ece5f4d51 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer.cpp @@ -0,0 +1,129 @@ +//===-- sanitizer_symbolizer.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_platform.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_symbolizer_internal.h" + +namespace __sanitizer { + +AddressInfo::AddressInfo() { + internal_memset(this, 0, sizeof(AddressInfo)); + function_offset = kUnknown; +} + +void AddressInfo::Clear() { + InternalFree(module); + InternalFree(function); + InternalFree(file); + internal_memset(this, 0, sizeof(AddressInfo)); + function_offset = kUnknown; +} + +void AddressInfo::FillModuleInfo(const char *mod_name, uptr mod_offset, + ModuleArch mod_arch) { + module = internal_strdup(mod_name); + module_offset = mod_offset; + module_arch = mod_arch; +} + +SymbolizedStack::SymbolizedStack() : next(nullptr), info() {} + +SymbolizedStack *SymbolizedStack::New(uptr addr) { + void *mem = InternalAlloc(sizeof(SymbolizedStack)); + SymbolizedStack *res = new(mem) SymbolizedStack(); + res->info.address = addr; + return res; +} + +void SymbolizedStack::ClearAll() { + info.Clear(); + if (next) + next->ClearAll(); + InternalFree(this); +} + +DataInfo::DataInfo() { + internal_memset(this, 0, sizeof(DataInfo)); +} + +void DataInfo::Clear() { + InternalFree(module); + InternalFree(file); + InternalFree(name); + internal_memset(this, 0, sizeof(DataInfo)); +} + +void FrameInfo::Clear() { + InternalFree(module); + for (LocalInfo &local : locals) { + InternalFree(local.function_name); + InternalFree(local.name); + InternalFree(local.decl_file); + } + locals.clear(); +} + +Symbolizer *Symbolizer::symbolizer_; +StaticSpinMutex Symbolizer::init_mu_; +LowLevelAllocator Symbolizer::symbolizer_allocator_; + +void Symbolizer::InvalidateModuleList() { + modules_fresh_ = false; +} + +void Symbolizer::AddHooks(Symbolizer::StartSymbolizationHook start_hook, + Symbolizer::EndSymbolizationHook end_hook) { + CHECK(start_hook_ == 0 && end_hook_ == 0); + start_hook_ = start_hook; + end_hook_ = end_hook; +} + +const char *Symbolizer::ModuleNameOwner::GetOwnedCopy(const char *str) { + mu_->CheckLocked(); + + // 'str' will be the same string multiple times in a row, optimize this case. + if (last_match_ && !internal_strcmp(last_match_, str)) + return last_match_; + + // FIXME: this is linear search. + // We should optimize this further if this turns out to be a bottleneck later. + for (uptr i = 0; i < storage_.size(); ++i) { + if (!internal_strcmp(storage_[i], str)) { + last_match_ = storage_[i]; + return last_match_; + } + } + last_match_ = internal_strdup(str); + storage_.push_back(last_match_); + return last_match_; +} + +Symbolizer::Symbolizer(IntrusiveList tools) + : module_names_(&mu_), modules_(), modules_fresh_(false), tools_(tools), + start_hook_(0), end_hook_(0) {} + +Symbolizer::SymbolizerScope::SymbolizerScope(const Symbolizer *sym) + : sym_(sym) { + if (sym_->start_hook_) + sym_->start_hook_(); +} + +Symbolizer::SymbolizerScope::~SymbolizerScope() { + if (sym_->end_hook_) + sym_->end_hook_(); +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/lib/sanitizer_common/sanitizer_symbolizer_internal.h index 4611b7dfe1e5..c04797dd61b8 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_internal.h +++ b/lib/sanitizer_common/sanitizer_symbolizer_internal.h @@ -76,30 +76,31 @@ class SymbolizerTool { // SymbolizerProcess may not be used from two threads simultaneously. class SymbolizerProcess { public: - explicit SymbolizerProcess(const char *path, bool use_forkpty = false); + explicit SymbolizerProcess(const char *path, bool use_posix_spawn = false); const char *SendCommand(const char *command); protected: + /// The maximum number of arguments required to invoke a tool process. + static const unsigned kArgVMax = 6; + + // Customizable by subclasses. + virtual bool StartSymbolizerSubprocess(); + virtual bool ReadFromSymbolizer(char *buffer, uptr max_length); + + private: virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const { UNIMPLEMENTED(); } - /// The maximum number of arguments required to invoke a tool process. - enum { kArgVMax = 6 }; - /// Fill in an argv array to invoke the child process. virtual void GetArgV(const char *path_to_binary, const char *(&argv)[kArgVMax]) const { UNIMPLEMENTED(); } - virtual bool ReadFromSymbolizer(char *buffer, uptr max_length); - - private: bool Restart(); const char *SendCommandImpl(const char *command); bool WriteToSymbolizer(const char *buffer, uptr length); - bool StartSymbolizerSubprocess(); const char *path_; fd_t input_fd_; @@ -113,7 +114,7 @@ class SymbolizerProcess { uptr times_restarted_; bool failed_to_start_; bool reported_invalid_path_; - bool use_forkpty_; + bool use_posix_spawn_; }; class LLVMSymbolizerProcess; diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc deleted file mode 100644 index 8a20e062cf47..000000000000 --- a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc +++ /dev/null @@ -1,209 +0,0 @@ -//===-- sanitizer_symbolizer_libbacktrace.cc ------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. -// Libbacktrace implementation of symbolizer parts. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#include "sanitizer_internal_defs.h" -#include "sanitizer_symbolizer.h" -#include "sanitizer_symbolizer_libbacktrace.h" - -#if SANITIZER_LIBBACKTRACE -# include "backtrace-supported.h" -# if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC -# include "backtrace.h" -# if SANITIZER_CP_DEMANGLE -# undef ARRAY_SIZE -# include "demangle.h" -# endif -# else -# define SANITIZER_LIBBACKTRACE 0 -# endif -#endif - -namespace __sanitizer { - -static char *DemangleAlloc(const char *name, bool always_alloc); - -#if SANITIZER_LIBBACKTRACE - -namespace { - -# if SANITIZER_CP_DEMANGLE -struct CplusV3DemangleData { - char *buf; - uptr size, allocated; -}; - -extern "C" { -static void CplusV3DemangleCallback(const char *s, size_t l, void *vdata) { - CplusV3DemangleData *data = (CplusV3DemangleData *)vdata; - uptr needed = data->size + l + 1; - if (needed > data->allocated) { - data->allocated *= 2; - if (needed > data->allocated) - data->allocated = needed; - char *buf = (char *)InternalAlloc(data->allocated); - if (data->buf) { - internal_memcpy(buf, data->buf, data->size); - InternalFree(data->buf); - } - data->buf = buf; - } - internal_memcpy(data->buf + data->size, s, l); - data->buf[data->size + l] = '\0'; - data->size += l; -} -} // extern "C" - -char *CplusV3Demangle(const char *name) { - CplusV3DemangleData data; - data.buf = 0; - data.size = 0; - data.allocated = 0; - if (cplus_demangle_v3_callback(name, DMGL_PARAMS | DMGL_ANSI, - CplusV3DemangleCallback, &data)) { - if (data.size + 64 > data.allocated) - return data.buf; - char *buf = internal_strdup(data.buf); - InternalFree(data.buf); - return buf; - } - if (data.buf) - InternalFree(data.buf); - return 0; -} -# endif // SANITIZER_CP_DEMANGLE - -struct SymbolizeCodeCallbackArg { - SymbolizedStack *first; - SymbolizedStack *last; - uptr frames_symbolized; - - AddressInfo *get_new_frame(uintptr_t addr) { - CHECK(last); - if (frames_symbolized > 0) { - SymbolizedStack *cur = SymbolizedStack::New(addr); - AddressInfo *info = &cur->info; - info->FillModuleInfo(first->info.module, first->info.module_offset, - first->info.module_arch); - last->next = cur; - last = cur; - } - CHECK_EQ(addr, first->info.address); - CHECK_EQ(addr, last->info.address); - return &last->info; - } -}; - -extern "C" { -static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr, - const char *filename, int lineno, - const char *function) { - SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata; - if (function) { - AddressInfo *info = cdata->get_new_frame(addr); - info->function = DemangleAlloc(function, /*always_alloc*/ true); - if (filename) - info->file = internal_strdup(filename); - info->line = lineno; - cdata->frames_symbolized++; - } - return 0; -} - -static void SymbolizeCodeCallback(void *vdata, uintptr_t addr, - const char *symname, uintptr_t, uintptr_t) { - SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata; - if (symname) { - AddressInfo *info = cdata->get_new_frame(addr); - info->function = DemangleAlloc(symname, /*always_alloc*/ true); - cdata->frames_symbolized++; - } -} - -static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname, - uintptr_t symval, uintptr_t symsize) { - DataInfo *info = (DataInfo *)vdata; - if (symname && symval) { - info->name = DemangleAlloc(symname, /*always_alloc*/ true); - info->start = symval; - info->size = symsize; - } -} - -static void ErrorCallback(void *, const char *, int) {} -} // extern "C" - -} // namespace - -LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { - // State created in backtrace_create_state is leaked. - void *state = (void *)(backtrace_create_state("/proc/self/exe", 0, - ErrorCallback, NULL)); - if (!state) - return 0; - return new(*alloc) LibbacktraceSymbolizer(state); -} - -bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { - SymbolizeCodeCallbackArg data; - data.first = stack; - data.last = stack; - data.frames_symbolized = 0; - backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback, - ErrorCallback, &data); - if (data.frames_symbolized > 0) - return true; - backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback, - ErrorCallback, &data); - return (data.frames_symbolized > 0); -} - -bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { - backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeDataCallback, - ErrorCallback, info); - return true; -} - -#else // SANITIZER_LIBBACKTRACE - -LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { - return 0; -} - -bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { - (void)state_; - return false; -} - -bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { - return false; -} - -#endif // SANITIZER_LIBBACKTRACE - -static char *DemangleAlloc(const char *name, bool always_alloc) { -#if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE - if (char *demangled = CplusV3Demangle(name)) - return demangled; -#endif - if (always_alloc) - return internal_strdup(name); - return 0; -} - -const char *LibbacktraceSymbolizer::Demangle(const char *name) { - return DemangleAlloc(name, /*always_alloc*/ false); -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cpp b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cpp new file mode 100644 index 000000000000..27ed222745ec --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cpp @@ -0,0 +1,209 @@ +//===-- sanitizer_symbolizer_libbacktrace.cpp -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +// Libbacktrace implementation of symbolizer parts. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#include "sanitizer_internal_defs.h" +#include "sanitizer_symbolizer.h" +#include "sanitizer_symbolizer_libbacktrace.h" + +#if SANITIZER_LIBBACKTRACE +# include "backtrace-supported.h" +# if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC +# include "backtrace.h" +# if SANITIZER_CP_DEMANGLE +# undef ARRAY_SIZE +# include "demangle.h" +# endif +# else +# define SANITIZER_LIBBACKTRACE 0 +# endif +#endif + +namespace __sanitizer { + +static char *DemangleAlloc(const char *name, bool always_alloc); + +#if SANITIZER_LIBBACKTRACE + +namespace { + +# if SANITIZER_CP_DEMANGLE +struct CplusV3DemangleData { + char *buf; + uptr size, allocated; +}; + +extern "C" { +static void CplusV3DemangleCallback(const char *s, size_t l, void *vdata) { + CplusV3DemangleData *data = (CplusV3DemangleData *)vdata; + uptr needed = data->size + l + 1; + if (needed > data->allocated) { + data->allocated *= 2; + if (needed > data->allocated) + data->allocated = needed; + char *buf = (char *)InternalAlloc(data->allocated); + if (data->buf) { + internal_memcpy(buf, data->buf, data->size); + InternalFree(data->buf); + } + data->buf = buf; + } + internal_memcpy(data->buf + data->size, s, l); + data->buf[data->size + l] = '\0'; + data->size += l; +} +} // extern "C" + +char *CplusV3Demangle(const char *name) { + CplusV3DemangleData data; + data.buf = 0; + data.size = 0; + data.allocated = 0; + if (cplus_demangle_v3_callback(name, DMGL_PARAMS | DMGL_ANSI, + CplusV3DemangleCallback, &data)) { + if (data.size + 64 > data.allocated) + return data.buf; + char *buf = internal_strdup(data.buf); + InternalFree(data.buf); + return buf; + } + if (data.buf) + InternalFree(data.buf); + return 0; +} +# endif // SANITIZER_CP_DEMANGLE + +struct SymbolizeCodeCallbackArg { + SymbolizedStack *first; + SymbolizedStack *last; + uptr frames_symbolized; + + AddressInfo *get_new_frame(uintptr_t addr) { + CHECK(last); + if (frames_symbolized > 0) { + SymbolizedStack *cur = SymbolizedStack::New(addr); + AddressInfo *info = &cur->info; + info->FillModuleInfo(first->info.module, first->info.module_offset, + first->info.module_arch); + last->next = cur; + last = cur; + } + CHECK_EQ(addr, first->info.address); + CHECK_EQ(addr, last->info.address); + return &last->info; + } +}; + +extern "C" { +static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr, + const char *filename, int lineno, + const char *function) { + SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata; + if (function) { + AddressInfo *info = cdata->get_new_frame(addr); + info->function = DemangleAlloc(function, /*always_alloc*/ true); + if (filename) + info->file = internal_strdup(filename); + info->line = lineno; + cdata->frames_symbolized++; + } + return 0; +} + +static void SymbolizeCodeCallback(void *vdata, uintptr_t addr, + const char *symname, uintptr_t, uintptr_t) { + SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata; + if (symname) { + AddressInfo *info = cdata->get_new_frame(addr); + info->function = DemangleAlloc(symname, /*always_alloc*/ true); + cdata->frames_symbolized++; + } +} + +static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname, + uintptr_t symval, uintptr_t symsize) { + DataInfo *info = (DataInfo *)vdata; + if (symname && symval) { + info->name = DemangleAlloc(symname, /*always_alloc*/ true); + info->start = symval; + info->size = symsize; + } +} + +static void ErrorCallback(void *, const char *, int) {} +} // extern "C" + +} // namespace + +LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { + // State created in backtrace_create_state is leaked. + void *state = (void *)(backtrace_create_state("/proc/self/exe", 0, + ErrorCallback, NULL)); + if (!state) + return 0; + return new(*alloc) LibbacktraceSymbolizer(state); +} + +bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { + SymbolizeCodeCallbackArg data; + data.first = stack; + data.last = stack; + data.frames_symbolized = 0; + backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback, + ErrorCallback, &data); + if (data.frames_symbolized > 0) + return true; + backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback, + ErrorCallback, &data); + return (data.frames_symbolized > 0); +} + +bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { + backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeDataCallback, + ErrorCallback, info); + return true; +} + +#else // SANITIZER_LIBBACKTRACE + +LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { + return 0; +} + +bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { + (void)state_; + return false; +} + +bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { + return false; +} + +#endif // SANITIZER_LIBBACKTRACE + +static char *DemangleAlloc(const char *name, bool always_alloc) { +#if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE + if (char *demangled = CplusV3Demangle(name)) + return demangled; +#endif + if (always_alloc) + return internal_strdup(name); + return 0; +} + +const char *LibbacktraceSymbolizer::Demangle(const char *name) { + return DemangleAlloc(name, /*always_alloc*/ false); +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc deleted file mode 100644 index 7f5bc55bd865..000000000000 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ /dev/null @@ -1,556 +0,0 @@ -//===-- sanitizer_symbolizer_libcdep.cc -----------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. -//===----------------------------------------------------------------------===// - -#include "sanitizer_allocator_internal.h" -#include "sanitizer_internal_defs.h" -#include "sanitizer_symbolizer_internal.h" - -namespace __sanitizer { - -Symbolizer *Symbolizer::GetOrInit() { - SpinMutexLock l(&init_mu_); - if (symbolizer_) - return symbolizer_; - symbolizer_ = PlatformInit(); - CHECK(symbolizer_); - return symbolizer_; -} - -// See sanitizer_symbolizer_markup.cc. -#if !SANITIZER_SYMBOLIZER_MARKUP - -const char *ExtractToken(const char *str, const char *delims, char **result) { - uptr prefix_len = internal_strcspn(str, delims); - *result = (char*)InternalAlloc(prefix_len + 1); - internal_memcpy(*result, str, prefix_len); - (*result)[prefix_len] = '\0'; - const char *prefix_end = str + prefix_len; - if (*prefix_end != '\0') prefix_end++; - return prefix_end; -} - -const char *ExtractInt(const char *str, const char *delims, int *result) { - char *buff; - const char *ret = ExtractToken(str, delims, &buff); - if (buff != 0) { - *result = (int)internal_atoll(buff); - } - InternalFree(buff); - return ret; -} - -const char *ExtractUptr(const char *str, const char *delims, uptr *result) { - char *buff; - const char *ret = ExtractToken(str, delims, &buff); - if (buff != 0) { - *result = (uptr)internal_atoll(buff); - } - InternalFree(buff); - return ret; -} - -const char *ExtractSptr(const char *str, const char *delims, sptr *result) { - char *buff; - const char *ret = ExtractToken(str, delims, &buff); - if (buff != 0) { - *result = (sptr)internal_atoll(buff); - } - InternalFree(buff); - return ret; -} - -const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter, - char **result) { - const char *found_delimiter = internal_strstr(str, delimiter); - uptr prefix_len = - found_delimiter ? found_delimiter - str : internal_strlen(str); - *result = (char *)InternalAlloc(prefix_len + 1); - internal_memcpy(*result, str, prefix_len); - (*result)[prefix_len] = '\0'; - const char *prefix_end = str + prefix_len; - if (*prefix_end != '\0') prefix_end += internal_strlen(delimiter); - return prefix_end; -} - -SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { - BlockingMutexLock l(&mu_); - const char *module_name; - uptr module_offset; - ModuleArch arch; - SymbolizedStack *res = SymbolizedStack::New(addr); - if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset, - &arch)) - return res; - // Always fill data about module name and offset. - res->info.FillModuleInfo(module_name, module_offset, arch); - for (auto &tool : tools_) { - SymbolizerScope sym_scope(this); - if (tool.SymbolizePC(addr, res)) { - return res; - } - } - return res; -} - -bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { - BlockingMutexLock l(&mu_); - const char *module_name; - uptr module_offset; - ModuleArch arch; - if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset, - &arch)) - return false; - info->Clear(); - info->module = internal_strdup(module_name); - info->module_offset = module_offset; - info->module_arch = arch; - for (auto &tool : tools_) { - SymbolizerScope sym_scope(this); - if (tool.SymbolizeData(addr, info)) { - return true; - } - } - return true; -} - -bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { - BlockingMutexLock l(&mu_); - const char *module_name; - if (!FindModuleNameAndOffsetForAddress( - addr, &module_name, &info->module_offset, &info->module_arch)) - return false; - info->module = internal_strdup(module_name); - for (auto &tool : tools_) { - SymbolizerScope sym_scope(this); - if (tool.SymbolizeFrame(addr, info)) { - return true; - } - } - return true; -} - -bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, - uptr *module_address) { - BlockingMutexLock l(&mu_); - const char *internal_module_name = nullptr; - ModuleArch arch; - if (!FindModuleNameAndOffsetForAddress(pc, &internal_module_name, - module_address, &arch)) - return false; - - if (module_name) - *module_name = module_names_.GetOwnedCopy(internal_module_name); - return true; -} - -void Symbolizer::Flush() { - BlockingMutexLock l(&mu_); - for (auto &tool : tools_) { - SymbolizerScope sym_scope(this); - tool.Flush(); - } -} - -const char *Symbolizer::Demangle(const char *name) { - BlockingMutexLock l(&mu_); - for (auto &tool : tools_) { - SymbolizerScope sym_scope(this); - if (const char *demangled = tool.Demangle(name)) - return demangled; - } - return PlatformDemangle(name); -} - -bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, - const char **module_name, - uptr *module_offset, - ModuleArch *module_arch) { - const LoadedModule *module = FindModuleForAddress(address); - if (module == nullptr) - return false; - *module_name = module->full_name(); - *module_offset = address - module->base_address(); - *module_arch = module->arch(); - return true; -} - -void Symbolizer::RefreshModules() { - modules_.init(); - fallback_modules_.fallbackInit(); - RAW_CHECK(modules_.size() > 0); - modules_fresh_ = true; -} - -static const LoadedModule *SearchForModule(const ListOfModules &modules, - uptr address) { - for (uptr i = 0; i < modules.size(); i++) { - if (modules[i].containsAddress(address)) { - return &modules[i]; - } - } - return nullptr; -} - -const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { - bool modules_were_reloaded = false; - if (!modules_fresh_) { - RefreshModules(); - modules_were_reloaded = true; - } - const LoadedModule *module = SearchForModule(modules_, address); - if (module) return module; - - // dlopen/dlclose interceptors invalidate the module list, but when - // interception is disabled, we need to retry if the lookup fails in - // case the module list changed. -#if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE - if (!modules_were_reloaded) { - RefreshModules(); - module = SearchForModule(modules_, address); - if (module) return module; - } -#endif - - if (fallback_modules_.size()) { - module = SearchForModule(fallback_modules_, address); - } - return module; -} - -// For now we assume the following protocol: -// For each request of the form -// -// passed to STDIN, external symbolizer prints to STDOUT response: -// -// :: -// -// :: -// ... -// -class LLVMSymbolizerProcess : public SymbolizerProcess { - public: - explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {} - - private: - bool ReachedEndOfOutput(const char *buffer, uptr length) const override { - // Empty line marks the end of llvm-symbolizer output. - return length >= 2 && buffer[length - 1] == '\n' && - buffer[length - 2] == '\n'; - } - - // When adding a new architecture, don't forget to also update - // script/asan_symbolize.py and sanitizer_common.h. - void GetArgV(const char *path_to_binary, - const char *(&argv)[kArgVMax]) const override { -#if defined(__x86_64h__) - const char* const kSymbolizerArch = "--default-arch=x86_64h"; -#elif defined(__x86_64__) - const char* const kSymbolizerArch = "--default-arch=x86_64"; -#elif defined(__i386__) - const char* const kSymbolizerArch = "--default-arch=i386"; -#elif defined(__aarch64__) - const char* const kSymbolizerArch = "--default-arch=arm64"; -#elif defined(__arm__) - const char* const kSymbolizerArch = "--default-arch=arm"; -#elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - const char* const kSymbolizerArch = "--default-arch=powerpc64"; -#elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - const char* const kSymbolizerArch = "--default-arch=powerpc64le"; -#elif defined(__s390x__) - const char* const kSymbolizerArch = "--default-arch=s390x"; -#elif defined(__s390__) - const char* const kSymbolizerArch = "--default-arch=s390"; -#else - const char* const kSymbolizerArch = "--default-arch=unknown"; -#endif - - const char *const inline_flag = common_flags()->symbolize_inline_frames - ? "--inlining=true" - : "--inlining=false"; - int i = 0; - argv[i++] = path_to_binary; - argv[i++] = inline_flag; - argv[i++] = kSymbolizerArch; - argv[i++] = nullptr; - } -}; - -LLVMSymbolizer::LLVMSymbolizer(const char *path, LowLevelAllocator *allocator) - : symbolizer_process_(new(*allocator) LLVMSymbolizerProcess(path)) {} - -// Parse a :[:] buffer. The file path may contain colons on -// Windows, so extract tokens from the right hand side first. The column info is -// also optional. -static const char *ParseFileLineInfo(AddressInfo *info, const char *str) { - char *file_line_info = 0; - str = ExtractToken(str, "\n", &file_line_info); - CHECK(file_line_info); - - if (uptr size = internal_strlen(file_line_info)) { - char *back = file_line_info + size - 1; - for (int i = 0; i < 2; ++i) { - while (back > file_line_info && IsDigit(*back)) --back; - if (*back != ':' || !IsDigit(back[1])) break; - info->column = info->line; - info->line = internal_atoll(back + 1); - // Truncate the string at the colon to keep only filename. - *back = '\0'; - --back; - } - ExtractToken(file_line_info, "", &info->file); - } - - InternalFree(file_line_info); - return str; -} - -// Parses one or more two-line strings in the following format: -// -// :[:] -// Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of -// them use the same output format. -void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) { - bool top_frame = true; - SymbolizedStack *last = res; - while (true) { - char *function_name = 0; - str = ExtractToken(str, "\n", &function_name); - CHECK(function_name); - if (function_name[0] == '\0') { - // There are no more frames. - InternalFree(function_name); - break; - } - SymbolizedStack *cur; - if (top_frame) { - cur = res; - top_frame = false; - } else { - cur = SymbolizedStack::New(res->info.address); - cur->info.FillModuleInfo(res->info.module, res->info.module_offset, - res->info.module_arch); - last->next = cur; - last = cur; - } - - AddressInfo *info = &cur->info; - info->function = function_name; - str = ParseFileLineInfo(info, str); - - // Functions and filenames can be "??", in which case we write 0 - // to address info to mark that names are unknown. - if (0 == internal_strcmp(info->function, "??")) { - InternalFree(info->function); - info->function = 0; - } - if (0 == internal_strcmp(info->file, "??")) { - InternalFree(info->file); - info->file = 0; - } - } -} - -// Parses a two-line string in the following format: -// -// -// Used by LLVMSymbolizer and InternalSymbolizer. -void ParseSymbolizeDataOutput(const char *str, DataInfo *info) { - str = ExtractToken(str, "\n", &info->name); - str = ExtractUptr(str, " ", &info->start); - str = ExtractUptr(str, "\n", &info->size); -} - -static void ParseSymbolizeFrameOutput(const char *str, - InternalMmapVector *locals) { - if (internal_strncmp(str, "??", 2) == 0) - return; - - while (*str) { - LocalInfo local; - str = ExtractToken(str, "\n", &local.function_name); - str = ExtractToken(str, "\n", &local.name); - - AddressInfo addr; - str = ParseFileLineInfo(&addr, str); - local.decl_file = addr.file; - local.decl_line = addr.line; - - local.has_frame_offset = internal_strncmp(str, "??", 2) != 0; - str = ExtractSptr(str, " ", &local.frame_offset); - - local.has_size = internal_strncmp(str, "??", 2) != 0; - str = ExtractUptr(str, " ", &local.size); - - local.has_tag_offset = internal_strncmp(str, "??", 2) != 0; - str = ExtractUptr(str, "\n", &local.tag_offset); - - locals->push_back(local); - } -} - -bool LLVMSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { - AddressInfo *info = &stack->info; - const char *buf = FormatAndSendCommand( - "CODE", info->module, info->module_offset, info->module_arch); - if (buf) { - ParseSymbolizePCOutput(buf, stack); - return true; - } - return false; -} - -bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { - const char *buf = FormatAndSendCommand( - "DATA", info->module, info->module_offset, info->module_arch); - if (buf) { - ParseSymbolizeDataOutput(buf, info); - info->start += (addr - info->module_offset); // Add the base address. - return true; - } - return false; -} - -bool LLVMSymbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { - const char *buf = FormatAndSendCommand( - "FRAME", info->module, info->module_offset, info->module_arch); - if (buf) { - ParseSymbolizeFrameOutput(buf, &info->locals); - return true; - } - return false; -} - -const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix, - const char *module_name, - uptr module_offset, - ModuleArch arch) { - CHECK(module_name); - if (arch == kModuleArchUnknown) { - if (internal_snprintf(buffer_, kBufferSize, "%s \"%s\" 0x%zx\n", - command_prefix, module_name, - module_offset) >= static_cast(kBufferSize)) { - Report("WARNING: Command buffer too small"); - return nullptr; - } - } else { - if (internal_snprintf(buffer_, kBufferSize, "%s \"%s:%s\" 0x%zx\n", - command_prefix, module_name, ModuleArchToString(arch), - module_offset) >= static_cast(kBufferSize)) { - Report("WARNING: Command buffer too small"); - return nullptr; - } - } - return symbolizer_process_->SendCommand(buffer_); -} - -SymbolizerProcess::SymbolizerProcess(const char *path, bool use_forkpty) - : path_(path), - input_fd_(kInvalidFd), - output_fd_(kInvalidFd), - times_restarted_(0), - failed_to_start_(false), - reported_invalid_path_(false), - use_forkpty_(use_forkpty) { - CHECK(path_); - CHECK_NE(path_[0], '\0'); -} - -static bool IsSameModule(const char* path) { - if (const char* ProcessName = GetProcessName()) { - if (const char* SymbolizerName = StripModuleName(path)) { - return !internal_strcmp(ProcessName, SymbolizerName); - } - } - return false; -} - -const char *SymbolizerProcess::SendCommand(const char *command) { - if (failed_to_start_) - return nullptr; - if (IsSameModule(path_)) { - Report("WARNING: Symbolizer was blocked from starting itself!\n"); - failed_to_start_ = true; - return nullptr; - } - for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) { - // Start or restart symbolizer if we failed to send command to it. - if (const char *res = SendCommandImpl(command)) - return res; - Restart(); - } - if (!failed_to_start_) { - Report("WARNING: Failed to use and restart external symbolizer!\n"); - failed_to_start_ = true; - } - return 0; -} - -const char *SymbolizerProcess::SendCommandImpl(const char *command) { - if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd) - return 0; - if (!WriteToSymbolizer(command, internal_strlen(command))) - return 0; - if (!ReadFromSymbolizer(buffer_, kBufferSize)) - return 0; - return buffer_; -} - -bool SymbolizerProcess::Restart() { - if (input_fd_ != kInvalidFd) - CloseFile(input_fd_); - if (output_fd_ != kInvalidFd) - CloseFile(output_fd_); - return StartSymbolizerSubprocess(); -} - -bool SymbolizerProcess::ReadFromSymbolizer(char *buffer, uptr max_length) { - if (max_length == 0) - return true; - uptr read_len = 0; - while (true) { - uptr just_read = 0; - bool success = ReadFromFile(input_fd_, buffer + read_len, - max_length - read_len - 1, &just_read); - // We can't read 0 bytes, as we don't expect external symbolizer to close - // its stdout. - if (!success || just_read == 0) { - Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_); - return false; - } - read_len += just_read; - if (ReachedEndOfOutput(buffer, read_len)) - break; - if (read_len + 1 == max_length) { - Report("WARNING: Symbolizer buffer too small\n"); - read_len = 0; - break; - } - } - buffer[read_len] = '\0'; - return true; -} - -bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) { - if (length == 0) - return true; - uptr write_len = 0; - bool success = WriteToFile(output_fd_, buffer, length, &write_len); - if (!success || write_len != length) { - Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_); - return false; - } - return true; -} - -#endif // !SANITIZER_SYMBOLIZER_MARKUP - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp new file mode 100644 index 000000000000..3b19a6836ec5 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp @@ -0,0 +1,557 @@ +//===-- sanitizer_symbolizer_libcdep.cpp ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_symbolizer_internal.h" + +namespace __sanitizer { + +Symbolizer *Symbolizer::GetOrInit() { + SpinMutexLock l(&init_mu_); + if (symbolizer_) + return symbolizer_; + symbolizer_ = PlatformInit(); + CHECK(symbolizer_); + return symbolizer_; +} + +// See sanitizer_symbolizer_markup.cpp. +#if !SANITIZER_SYMBOLIZER_MARKUP + +const char *ExtractToken(const char *str, const char *delims, char **result) { + uptr prefix_len = internal_strcspn(str, delims); + *result = (char*)InternalAlloc(prefix_len + 1); + internal_memcpy(*result, str, prefix_len); + (*result)[prefix_len] = '\0'; + const char *prefix_end = str + prefix_len; + if (*prefix_end != '\0') prefix_end++; + return prefix_end; +} + +const char *ExtractInt(const char *str, const char *delims, int *result) { + char *buff; + const char *ret = ExtractToken(str, delims, &buff); + if (buff != 0) { + *result = (int)internal_atoll(buff); + } + InternalFree(buff); + return ret; +} + +const char *ExtractUptr(const char *str, const char *delims, uptr *result) { + char *buff; + const char *ret = ExtractToken(str, delims, &buff); + if (buff != 0) { + *result = (uptr)internal_atoll(buff); + } + InternalFree(buff); + return ret; +} + +const char *ExtractSptr(const char *str, const char *delims, sptr *result) { + char *buff; + const char *ret = ExtractToken(str, delims, &buff); + if (buff != 0) { + *result = (sptr)internal_atoll(buff); + } + InternalFree(buff); + return ret; +} + +const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter, + char **result) { + const char *found_delimiter = internal_strstr(str, delimiter); + uptr prefix_len = + found_delimiter ? found_delimiter - str : internal_strlen(str); + *result = (char *)InternalAlloc(prefix_len + 1); + internal_memcpy(*result, str, prefix_len); + (*result)[prefix_len] = '\0'; + const char *prefix_end = str + prefix_len; + if (*prefix_end != '\0') prefix_end += internal_strlen(delimiter); + return prefix_end; +} + +SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { + BlockingMutexLock l(&mu_); + const char *module_name; + uptr module_offset; + ModuleArch arch; + SymbolizedStack *res = SymbolizedStack::New(addr); + if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset, + &arch)) + return res; + // Always fill data about module name and offset. + res->info.FillModuleInfo(module_name, module_offset, arch); + for (auto &tool : tools_) { + SymbolizerScope sym_scope(this); + if (tool.SymbolizePC(addr, res)) { + return res; + } + } + return res; +} + +bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { + BlockingMutexLock l(&mu_); + const char *module_name; + uptr module_offset; + ModuleArch arch; + if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset, + &arch)) + return false; + info->Clear(); + info->module = internal_strdup(module_name); + info->module_offset = module_offset; + info->module_arch = arch; + for (auto &tool : tools_) { + SymbolizerScope sym_scope(this); + if (tool.SymbolizeData(addr, info)) { + return true; + } + } + return true; +} + +bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { + BlockingMutexLock l(&mu_); + const char *module_name; + if (!FindModuleNameAndOffsetForAddress( + addr, &module_name, &info->module_offset, &info->module_arch)) + return false; + info->module = internal_strdup(module_name); + for (auto &tool : tools_) { + SymbolizerScope sym_scope(this); + if (tool.SymbolizeFrame(addr, info)) { + return true; + } + } + return true; +} + +bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, + uptr *module_address) { + BlockingMutexLock l(&mu_); + const char *internal_module_name = nullptr; + ModuleArch arch; + if (!FindModuleNameAndOffsetForAddress(pc, &internal_module_name, + module_address, &arch)) + return false; + + if (module_name) + *module_name = module_names_.GetOwnedCopy(internal_module_name); + return true; +} + +void Symbolizer::Flush() { + BlockingMutexLock l(&mu_); + for (auto &tool : tools_) { + SymbolizerScope sym_scope(this); + tool.Flush(); + } +} + +const char *Symbolizer::Demangle(const char *name) { + BlockingMutexLock l(&mu_); + for (auto &tool : tools_) { + SymbolizerScope sym_scope(this); + if (const char *demangled = tool.Demangle(name)) + return demangled; + } + return PlatformDemangle(name); +} + +bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, + const char **module_name, + uptr *module_offset, + ModuleArch *module_arch) { + const LoadedModule *module = FindModuleForAddress(address); + if (module == nullptr) + return false; + *module_name = module->full_name(); + *module_offset = address - module->base_address(); + *module_arch = module->arch(); + return true; +} + +void Symbolizer::RefreshModules() { + modules_.init(); + fallback_modules_.fallbackInit(); + RAW_CHECK(modules_.size() > 0); + modules_fresh_ = true; +} + +static const LoadedModule *SearchForModule(const ListOfModules &modules, + uptr address) { + for (uptr i = 0; i < modules.size(); i++) { + if (modules[i].containsAddress(address)) { + return &modules[i]; + } + } + return nullptr; +} + +const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { + bool modules_were_reloaded = false; + if (!modules_fresh_) { + RefreshModules(); + modules_were_reloaded = true; + } + const LoadedModule *module = SearchForModule(modules_, address); + if (module) return module; + + // dlopen/dlclose interceptors invalidate the module list, but when + // interception is disabled, we need to retry if the lookup fails in + // case the module list changed. +#if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE + if (!modules_were_reloaded) { + RefreshModules(); + module = SearchForModule(modules_, address); + if (module) return module; + } +#endif + + if (fallback_modules_.size()) { + module = SearchForModule(fallback_modules_, address); + } + return module; +} + +// For now we assume the following protocol: +// For each request of the form +// +// passed to STDIN, external symbolizer prints to STDOUT response: +// +// :: +// +// :: +// ... +// +class LLVMSymbolizerProcess : public SymbolizerProcess { + public: + explicit LLVMSymbolizerProcess(const char *path) + : SymbolizerProcess(path, /*use_posix_spawn=*/SANITIZER_MAC) {} + + private: + bool ReachedEndOfOutput(const char *buffer, uptr length) const override { + // Empty line marks the end of llvm-symbolizer output. + return length >= 2 && buffer[length - 1] == '\n' && + buffer[length - 2] == '\n'; + } + + // When adding a new architecture, don't forget to also update + // script/asan_symbolize.py and sanitizer_common.h. + void GetArgV(const char *path_to_binary, + const char *(&argv)[kArgVMax]) const override { +#if defined(__x86_64h__) + const char* const kSymbolizerArch = "--default-arch=x86_64h"; +#elif defined(__x86_64__) + const char* const kSymbolizerArch = "--default-arch=x86_64"; +#elif defined(__i386__) + const char* const kSymbolizerArch = "--default-arch=i386"; +#elif defined(__aarch64__) + const char* const kSymbolizerArch = "--default-arch=arm64"; +#elif defined(__arm__) + const char* const kSymbolizerArch = "--default-arch=arm"; +#elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + const char* const kSymbolizerArch = "--default-arch=powerpc64"; +#elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + const char* const kSymbolizerArch = "--default-arch=powerpc64le"; +#elif defined(__s390x__) + const char* const kSymbolizerArch = "--default-arch=s390x"; +#elif defined(__s390__) + const char* const kSymbolizerArch = "--default-arch=s390"; +#else + const char* const kSymbolizerArch = "--default-arch=unknown"; +#endif + + const char *const inline_flag = common_flags()->symbolize_inline_frames + ? "--inlining=true" + : "--inlining=false"; + int i = 0; + argv[i++] = path_to_binary; + argv[i++] = inline_flag; + argv[i++] = kSymbolizerArch; + argv[i++] = nullptr; + } +}; + +LLVMSymbolizer::LLVMSymbolizer(const char *path, LowLevelAllocator *allocator) + : symbolizer_process_(new(*allocator) LLVMSymbolizerProcess(path)) {} + +// Parse a :[:] buffer. The file path may contain colons on +// Windows, so extract tokens from the right hand side first. The column info is +// also optional. +static const char *ParseFileLineInfo(AddressInfo *info, const char *str) { + char *file_line_info = 0; + str = ExtractToken(str, "\n", &file_line_info); + CHECK(file_line_info); + + if (uptr size = internal_strlen(file_line_info)) { + char *back = file_line_info + size - 1; + for (int i = 0; i < 2; ++i) { + while (back > file_line_info && IsDigit(*back)) --back; + if (*back != ':' || !IsDigit(back[1])) break; + info->column = info->line; + info->line = internal_atoll(back + 1); + // Truncate the string at the colon to keep only filename. + *back = '\0'; + --back; + } + ExtractToken(file_line_info, "", &info->file); + } + + InternalFree(file_line_info); + return str; +} + +// Parses one or more two-line strings in the following format: +// +// :[:] +// Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of +// them use the same output format. +void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) { + bool top_frame = true; + SymbolizedStack *last = res; + while (true) { + char *function_name = 0; + str = ExtractToken(str, "\n", &function_name); + CHECK(function_name); + if (function_name[0] == '\0') { + // There are no more frames. + InternalFree(function_name); + break; + } + SymbolizedStack *cur; + if (top_frame) { + cur = res; + top_frame = false; + } else { + cur = SymbolizedStack::New(res->info.address); + cur->info.FillModuleInfo(res->info.module, res->info.module_offset, + res->info.module_arch); + last->next = cur; + last = cur; + } + + AddressInfo *info = &cur->info; + info->function = function_name; + str = ParseFileLineInfo(info, str); + + // Functions and filenames can be "??", in which case we write 0 + // to address info to mark that names are unknown. + if (0 == internal_strcmp(info->function, "??")) { + InternalFree(info->function); + info->function = 0; + } + if (0 == internal_strcmp(info->file, "??")) { + InternalFree(info->file); + info->file = 0; + } + } +} + +// Parses a two-line string in the following format: +// +// +// Used by LLVMSymbolizer and InternalSymbolizer. +void ParseSymbolizeDataOutput(const char *str, DataInfo *info) { + str = ExtractToken(str, "\n", &info->name); + str = ExtractUptr(str, " ", &info->start); + str = ExtractUptr(str, "\n", &info->size); +} + +static void ParseSymbolizeFrameOutput(const char *str, + InternalMmapVector *locals) { + if (internal_strncmp(str, "??", 2) == 0) + return; + + while (*str) { + LocalInfo local; + str = ExtractToken(str, "\n", &local.function_name); + str = ExtractToken(str, "\n", &local.name); + + AddressInfo addr; + str = ParseFileLineInfo(&addr, str); + local.decl_file = addr.file; + local.decl_line = addr.line; + + local.has_frame_offset = internal_strncmp(str, "??", 2) != 0; + str = ExtractSptr(str, " ", &local.frame_offset); + + local.has_size = internal_strncmp(str, "??", 2) != 0; + str = ExtractUptr(str, " ", &local.size); + + local.has_tag_offset = internal_strncmp(str, "??", 2) != 0; + str = ExtractUptr(str, "\n", &local.tag_offset); + + locals->push_back(local); + } +} + +bool LLVMSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { + AddressInfo *info = &stack->info; + const char *buf = FormatAndSendCommand( + "CODE", info->module, info->module_offset, info->module_arch); + if (buf) { + ParseSymbolizePCOutput(buf, stack); + return true; + } + return false; +} + +bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { + const char *buf = FormatAndSendCommand( + "DATA", info->module, info->module_offset, info->module_arch); + if (buf) { + ParseSymbolizeDataOutput(buf, info); + info->start += (addr - info->module_offset); // Add the base address. + return true; + } + return false; +} + +bool LLVMSymbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { + const char *buf = FormatAndSendCommand( + "FRAME", info->module, info->module_offset, info->module_arch); + if (buf) { + ParseSymbolizeFrameOutput(buf, &info->locals); + return true; + } + return false; +} + +const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix, + const char *module_name, + uptr module_offset, + ModuleArch arch) { + CHECK(module_name); + if (arch == kModuleArchUnknown) { + if (internal_snprintf(buffer_, kBufferSize, "%s \"%s\" 0x%zx\n", + command_prefix, module_name, + module_offset) >= static_cast(kBufferSize)) { + Report("WARNING: Command buffer too small"); + return nullptr; + } + } else { + if (internal_snprintf(buffer_, kBufferSize, "%s \"%s:%s\" 0x%zx\n", + command_prefix, module_name, ModuleArchToString(arch), + module_offset) >= static_cast(kBufferSize)) { + Report("WARNING: Command buffer too small"); + return nullptr; + } + } + return symbolizer_process_->SendCommand(buffer_); +} + +SymbolizerProcess::SymbolizerProcess(const char *path, bool use_posix_spawn) + : path_(path), + input_fd_(kInvalidFd), + output_fd_(kInvalidFd), + times_restarted_(0), + failed_to_start_(false), + reported_invalid_path_(false), + use_posix_spawn_(use_posix_spawn) { + CHECK(path_); + CHECK_NE(path_[0], '\0'); +} + +static bool IsSameModule(const char* path) { + if (const char* ProcessName = GetProcessName()) { + if (const char* SymbolizerName = StripModuleName(path)) { + return !internal_strcmp(ProcessName, SymbolizerName); + } + } + return false; +} + +const char *SymbolizerProcess::SendCommand(const char *command) { + if (failed_to_start_) + return nullptr; + if (IsSameModule(path_)) { + Report("WARNING: Symbolizer was blocked from starting itself!\n"); + failed_to_start_ = true; + return nullptr; + } + for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) { + // Start or restart symbolizer if we failed to send command to it. + if (const char *res = SendCommandImpl(command)) + return res; + Restart(); + } + if (!failed_to_start_) { + Report("WARNING: Failed to use and restart external symbolizer!\n"); + failed_to_start_ = true; + } + return 0; +} + +const char *SymbolizerProcess::SendCommandImpl(const char *command) { + if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd) + return 0; + if (!WriteToSymbolizer(command, internal_strlen(command))) + return 0; + if (!ReadFromSymbolizer(buffer_, kBufferSize)) + return 0; + return buffer_; +} + +bool SymbolizerProcess::Restart() { + if (input_fd_ != kInvalidFd) + CloseFile(input_fd_); + if (output_fd_ != kInvalidFd) + CloseFile(output_fd_); + return StartSymbolizerSubprocess(); +} + +bool SymbolizerProcess::ReadFromSymbolizer(char *buffer, uptr max_length) { + if (max_length == 0) + return true; + uptr read_len = 0; + while (true) { + uptr just_read = 0; + bool success = ReadFromFile(input_fd_, buffer + read_len, + max_length - read_len - 1, &just_read); + // We can't read 0 bytes, as we don't expect external symbolizer to close + // its stdout. + if (!success || just_read == 0) { + Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_); + return false; + } + read_len += just_read; + if (ReachedEndOfOutput(buffer, read_len)) + break; + if (read_len + 1 == max_length) { + Report("WARNING: Symbolizer buffer too small\n"); + read_len = 0; + break; + } + } + buffer[read_len] = '\0'; + return true; +} + +bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) { + if (length == 0) + return true; + uptr write_len = 0; + bool success = WriteToFile(output_fd_, buffer, length, &write_len); + if (!success || write_len != length) { + Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_); + return false; + } + return true; +} + +#endif // !SANITIZER_SYMBOLIZER_MARKUP + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_mac.cc b/lib/sanitizer_common/sanitizer_symbolizer_mac.cc deleted file mode 100644 index d3566571948e..000000000000 --- a/lib/sanitizer_common/sanitizer_symbolizer_mac.cc +++ /dev/null @@ -1,168 +0,0 @@ -//===-- sanitizer_symbolizer_mac.cc ---------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between various sanitizers' runtime libraries. -// -// Implementation of Mac-specific "atos" symbolizer. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_MAC - -#include "sanitizer_allocator_internal.h" -#include "sanitizer_mac.h" -#include "sanitizer_symbolizer_mac.h" - -#include -#include -#include -#include -#include -#include - -namespace __sanitizer { - -bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { - Dl_info info; - int result = dladdr((const void *)addr, &info); - if (!result) return false; - const char *demangled = DemangleSwiftAndCXX(info.dli_sname); - if (!demangled) return false; - stack->info.function = internal_strdup(demangled); - return true; -} - -bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) { - Dl_info info; - int result = dladdr((const void *)addr, &info); - if (!result) return false; - const char *demangled = DemangleSwiftAndCXX(info.dli_sname); - datainfo->name = internal_strdup(demangled); - datainfo->start = (uptr)info.dli_saddr; - return true; -} - -class AtosSymbolizerProcess : public SymbolizerProcess { - public: - explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid) - : SymbolizerProcess(path, /*use_forkpty*/ true) { - // Put the string command line argument in the object so that it outlives - // the call to GetArgV. - internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid); - } - - private: - bool ReachedEndOfOutput(const char *buffer, uptr length) const override { - return (length >= 1 && buffer[length - 1] == '\n'); - } - - void GetArgV(const char *path_to_binary, - const char *(&argv)[kArgVMax]) const override { - int i = 0; - argv[i++] = path_to_binary; - argv[i++] = "-p"; - argv[i++] = &pid_str_[0]; - if (GetMacosVersion() == MACOS_VERSION_MAVERICKS) { - // On Mavericks atos prints a deprecation warning which we suppress by - // passing -d. The warning isn't present on other OSX versions, even the - // newer ones. - argv[i++] = "-d"; - } - argv[i++] = nullptr; - } - - char pid_str_[16]; -}; - -static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, - char **out_module, char **out_file, uptr *line, - uptr *start_address) { - // Trim ending newlines. - char *trim; - ExtractTokenUpToDelimiter(str, "\n", &trim); - - // The line from `atos` is in one of these formats: - // myfunction (in library.dylib) (sourcefile.c:17) - // myfunction (in library.dylib) + 0x1fe - // myfunction (in library.dylib) + 15 - // 0xdeadbeef (in library.dylib) + 0x1fe - // 0xdeadbeef (in library.dylib) + 15 - // 0xdeadbeef (in library.dylib) - // 0xdeadbeef - - const char *rest = trim; - char *symbol_name; - rest = ExtractTokenUpToDelimiter(rest, " (in ", &symbol_name); - if (rest[0] == '\0') { - InternalFree(symbol_name); - InternalFree(trim); - return false; - } - - if (internal_strncmp(symbol_name, "0x", 2) != 0) - *out_name = symbol_name; - else - InternalFree(symbol_name); - rest = ExtractTokenUpToDelimiter(rest, ") ", out_module); - - if (rest[0] == '(') { - if (out_file) { - rest++; - rest = ExtractTokenUpToDelimiter(rest, ":", out_file); - char *extracted_line_number; - rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number); - if (line) *line = (uptr)internal_atoll(extracted_line_number); - InternalFree(extracted_line_number); - } - } else if (rest[0] == '+') { - rest += 2; - uptr offset = internal_atoll(rest); - if (start_address) *start_address = addr - offset; - } - - InternalFree(trim); - return true; -} - -AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator) - : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {} - -bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { - if (!process_) return false; - if (addr == 0) return false; - char command[32]; - internal_snprintf(command, sizeof(command), "0x%zx\n", addr); - const char *buf = process_->SendCommand(command); - if (!buf) return false; - uptr line; - if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module, - &stack->info.file, &line, nullptr)) { - process_ = nullptr; - return false; - } - stack->info.line = (int)line; - return true; -} - -bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { - if (!process_) return false; - char command[32]; - internal_snprintf(command, sizeof(command), "0x%zx\n", addr); - const char *buf = process_->SendCommand(command); - if (!buf) return false; - if (!ParseCommandOutput(buf, addr, &info->name, &info->module, nullptr, - nullptr, &info->start)) { - process_ = nullptr; - return false; - } - return true; -} - -} // namespace __sanitizer - -#endif // SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp b/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp new file mode 100644 index 000000000000..a619ed092f0b --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp @@ -0,0 +1,173 @@ +//===-- sanitizer_symbolizer_mac.cpp --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries. +// +// Implementation of Mac-specific "atos" symbolizer. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_MAC + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_mac.h" +#include "sanitizer_symbolizer_mac.h" + +#include +#include +#include +#include +#include +#include + +namespace __sanitizer { + +bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { + Dl_info info; + int result = dladdr((const void *)addr, &info); + if (!result) return false; + const char *demangled = DemangleSwiftAndCXX(info.dli_sname); + if (!demangled) return false; + stack->info.function = internal_strdup(demangled); + return true; +} + +bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) { + Dl_info info; + int result = dladdr((const void *)addr, &info); + if (!result) return false; + const char *demangled = DemangleSwiftAndCXX(info.dli_sname); + datainfo->name = internal_strdup(demangled); + datainfo->start = (uptr)info.dli_saddr; + return true; +} + +class AtosSymbolizerProcess : public SymbolizerProcess { + public: + explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid) + : SymbolizerProcess(path, /*use_posix_spawn*/ true) { + // Put the string command line argument in the object so that it outlives + // the call to GetArgV. + internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid); + } + + private: + bool StartSymbolizerSubprocess() override { + // Configure sandbox before starting atos process. + return SymbolizerProcess::StartSymbolizerSubprocess(); + } + + bool ReachedEndOfOutput(const char *buffer, uptr length) const override { + return (length >= 1 && buffer[length - 1] == '\n'); + } + + void GetArgV(const char *path_to_binary, + const char *(&argv)[kArgVMax]) const override { + int i = 0; + argv[i++] = path_to_binary; + argv[i++] = "-p"; + argv[i++] = &pid_str_[0]; + if (GetMacosVersion() == MACOS_VERSION_MAVERICKS) { + // On Mavericks atos prints a deprecation warning which we suppress by + // passing -d. The warning isn't present on other OSX versions, even the + // newer ones. + argv[i++] = "-d"; + } + argv[i++] = nullptr; + } + + char pid_str_[16]; +}; + +static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, + char **out_module, char **out_file, uptr *line, + uptr *start_address) { + // Trim ending newlines. + char *trim; + ExtractTokenUpToDelimiter(str, "\n", &trim); + + // The line from `atos` is in one of these formats: + // myfunction (in library.dylib) (sourcefile.c:17) + // myfunction (in library.dylib) + 0x1fe + // myfunction (in library.dylib) + 15 + // 0xdeadbeef (in library.dylib) + 0x1fe + // 0xdeadbeef (in library.dylib) + 15 + // 0xdeadbeef (in library.dylib) + // 0xdeadbeef + + const char *rest = trim; + char *symbol_name; + rest = ExtractTokenUpToDelimiter(rest, " (in ", &symbol_name); + if (rest[0] == '\0') { + InternalFree(symbol_name); + InternalFree(trim); + return false; + } + + if (internal_strncmp(symbol_name, "0x", 2) != 0) + *out_name = symbol_name; + else + InternalFree(symbol_name); + rest = ExtractTokenUpToDelimiter(rest, ") ", out_module); + + if (rest[0] == '(') { + if (out_file) { + rest++; + rest = ExtractTokenUpToDelimiter(rest, ":", out_file); + char *extracted_line_number; + rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number); + if (line) *line = (uptr)internal_atoll(extracted_line_number); + InternalFree(extracted_line_number); + } + } else if (rest[0] == '+') { + rest += 2; + uptr offset = internal_atoll(rest); + if (start_address) *start_address = addr - offset; + } + + InternalFree(trim); + return true; +} + +AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator) + : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {} + +bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { + if (!process_) return false; + if (addr == 0) return false; + char command[32]; + internal_snprintf(command, sizeof(command), "0x%zx\n", addr); + const char *buf = process_->SendCommand(command); + if (!buf) return false; + uptr line; + if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module, + &stack->info.file, &line, nullptr)) { + process_ = nullptr; + return false; + } + stack->info.line = (int)line; + return true; +} + +bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { + if (!process_) return false; + char command[32]; + internal_snprintf(command, sizeof(command), "0x%zx\n", addr); + const char *buf = process_->SendCommand(command); + if (!buf) return false; + if (!ParseCommandOutput(buf, addr, &info->name, &info->module, nullptr, + nullptr, &info->start)) { + process_ = nullptr; + return false; + } + return true; +} + +} // namespace __sanitizer + +#endif // SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_symbolizer_markup.cc b/lib/sanitizer_common/sanitizer_symbolizer_markup.cc deleted file mode 100644 index aee49b4c4567..000000000000 --- a/lib/sanitizer_common/sanitizer_symbolizer_markup.cc +++ /dev/null @@ -1,144 +0,0 @@ -//===-- sanitizer_symbolizer_markup.cc ------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between various sanitizers' runtime libraries. -// -// Implementation of offline markup symbolizer. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_SYMBOLIZER_MARKUP - -#if SANITIZER_FUCHSIA -#include "sanitizer_symbolizer_fuchsia.h" -#elif SANITIZER_RTEMS -#include "sanitizer_symbolizer_rtems.h" -#endif -#include "sanitizer_stacktrace.h" -#include "sanitizer_symbolizer.h" - -#include -#include - -namespace __sanitizer { - -// This generic support for offline symbolizing is based on the -// Fuchsia port. We don't do any actual symbolization per se. -// Instead, we emit text containing raw addresses and raw linkage -// symbol names, embedded in Fuchsia's symbolization markup format. -// Fuchsia's logging infrastructure emits enough information about -// process memory layout that a post-processing filter can do the -// symbolization and pretty-print the markup. See the spec at: -// https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md - -// This is used by UBSan for type names, and by ASan for global variable names. -// It's expected to return a static buffer that will be reused on each call. -const char *Symbolizer::Demangle(const char *name) { - static char buffer[kFormatDemangleMax]; - internal_snprintf(buffer, sizeof(buffer), kFormatDemangle, name); - return buffer; -} - -// This is used mostly for suppression matching. Making it work -// would enable "interceptor_via_lib" suppressions. It's also used -// once in UBSan to say "in module ..." in a message that also -// includes an address in the module, so post-processing can already -// pretty-print that so as to indicate the module. -bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, - uptr *module_address) { - return false; -} - -// This is used in some places for suppression checking, which we -// don't really support for Fuchsia. It's also used in UBSan to -// identify a PC location to a function name, so we always fill in -// the function member with a string containing markup around the PC -// value. -// TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan -// to render stack frames, but that should be changed to use -// RenderStackFrame. -SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { - SymbolizedStack *s = SymbolizedStack::New(addr); - char buffer[kFormatFunctionMax]; - internal_snprintf(buffer, sizeof(buffer), kFormatFunction, addr); - s->info.function = internal_strdup(buffer); - return s; -} - -// Always claim we succeeded, so that RenderDataInfo will be called. -bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { - info->Clear(); - info->start = addr; - return true; -} - -// We ignore the format argument to __sanitizer_symbolize_global. -void RenderData(InternalScopedString *buffer, const char *format, - const DataInfo *DI, const char *strip_path_prefix) { - buffer->append(kFormatData, DI->start); -} - -// We don't support the stack_trace_format flag at all. -void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, - const AddressInfo &info, bool vs_style, - const char *strip_path_prefix, const char *strip_func_prefix) { - buffer->append(kFormatFrame, frame_no, info.address); -} - -Symbolizer *Symbolizer::PlatformInit() { - return new (symbolizer_allocator_) Symbolizer({}); -} - -void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); } - -void StartReportDeadlySignal() {} -void ReportDeadlySignal(const SignalContext &sig, u32 tid, - UnwindSignalStackCallbackType unwind, - const void *unwind_context) {} - -#if SANITIZER_CAN_SLOW_UNWIND -struct UnwindTraceArg { - BufferedStackTrace *stack; - u32 max_depth; -}; - -_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { - UnwindTraceArg *arg = static_cast(param); - CHECK_LT(arg->stack->size, arg->max_depth); - uptr pc = _Unwind_GetIP(ctx); - if (pc < PAGE_SIZE) return _URC_NORMAL_STOP; - arg->stack->trace_buffer[arg->stack->size++] = pc; - return (arg->stack->size == arg->max_depth ? _URC_NORMAL_STOP - : _URC_NO_REASON); -} - -void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) { - CHECK_GE(max_depth, 2); - size = 0; - UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; - _Unwind_Backtrace(Unwind_Trace, &arg); - CHECK_GT(size, 0); - // We need to pop a few frames so that pc is on top. - uptr to_pop = LocatePcInTrace(pc); - // trace_buffer[0] belongs to the current function so we always pop it, - // unless there is only 1 frame in the stack trace (1 frame is always better - // than 0!). - PopStackFrames(Min(to_pop, static_cast(1))); - trace_buffer[0] = pc; -} - -void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) { - CHECK(context); - CHECK_GE(max_depth, 2); - UNREACHABLE("signal context doesn't exist"); -} -#endif // SANITIZER_CAN_SLOW_UNWIND - -} // namespace __sanitizer - -#endif // SANITIZER_SYMBOLIZER_MARKUP diff --git a/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp b/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp new file mode 100644 index 000000000000..57b4d0c9d961 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp @@ -0,0 +1,144 @@ +//===-- sanitizer_symbolizer_markup.cpp -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries. +// +// Implementation of offline markup symbolizer. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_SYMBOLIZER_MARKUP + +#if SANITIZER_FUCHSIA +#include "sanitizer_symbolizer_fuchsia.h" +#elif SANITIZER_RTEMS +#include "sanitizer_symbolizer_rtems.h" +#endif +#include "sanitizer_stacktrace.h" +#include "sanitizer_symbolizer.h" + +#include +#include + +namespace __sanitizer { + +// This generic support for offline symbolizing is based on the +// Fuchsia port. We don't do any actual symbolization per se. +// Instead, we emit text containing raw addresses and raw linkage +// symbol names, embedded in Fuchsia's symbolization markup format. +// Fuchsia's logging infrastructure emits enough information about +// process memory layout that a post-processing filter can do the +// symbolization and pretty-print the markup. See the spec at: +// https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md + +// This is used by UBSan for type names, and by ASan for global variable names. +// It's expected to return a static buffer that will be reused on each call. +const char *Symbolizer::Demangle(const char *name) { + static char buffer[kFormatDemangleMax]; + internal_snprintf(buffer, sizeof(buffer), kFormatDemangle, name); + return buffer; +} + +// This is used mostly for suppression matching. Making it work +// would enable "interceptor_via_lib" suppressions. It's also used +// once in UBSan to say "in module ..." in a message that also +// includes an address in the module, so post-processing can already +// pretty-print that so as to indicate the module. +bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, + uptr *module_address) { + return false; +} + +// This is used in some places for suppression checking, which we +// don't really support for Fuchsia. It's also used in UBSan to +// identify a PC location to a function name, so we always fill in +// the function member with a string containing markup around the PC +// value. +// TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan +// to render stack frames, but that should be changed to use +// RenderStackFrame. +SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { + SymbolizedStack *s = SymbolizedStack::New(addr); + char buffer[kFormatFunctionMax]; + internal_snprintf(buffer, sizeof(buffer), kFormatFunction, addr); + s->info.function = internal_strdup(buffer); + return s; +} + +// Always claim we succeeded, so that RenderDataInfo will be called. +bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { + info->Clear(); + info->start = addr; + return true; +} + +// We ignore the format argument to __sanitizer_symbolize_global. +void RenderData(InternalScopedString *buffer, const char *format, + const DataInfo *DI, const char *strip_path_prefix) { + buffer->append(kFormatData, DI->start); +} + +// We don't support the stack_trace_format flag at all. +void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, + const AddressInfo &info, bool vs_style, + const char *strip_path_prefix, const char *strip_func_prefix) { + buffer->append(kFormatFrame, frame_no, info.address); +} + +Symbolizer *Symbolizer::PlatformInit() { + return new (symbolizer_allocator_) Symbolizer({}); +} + +void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); } + +void StartReportDeadlySignal() {} +void ReportDeadlySignal(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) {} + +#if SANITIZER_CAN_SLOW_UNWIND +struct UnwindTraceArg { + BufferedStackTrace *stack; + u32 max_depth; +}; + +_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { + UnwindTraceArg *arg = static_cast(param); + CHECK_LT(arg->stack->size, arg->max_depth); + uptr pc = _Unwind_GetIP(ctx); + if (pc < PAGE_SIZE) return _URC_NORMAL_STOP; + arg->stack->trace_buffer[arg->stack->size++] = pc; + return (arg->stack->size == arg->max_depth ? _URC_NORMAL_STOP + : _URC_NO_REASON); +} + +void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) { + CHECK_GE(max_depth, 2); + size = 0; + UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; + _Unwind_Backtrace(Unwind_Trace, &arg); + CHECK_GT(size, 0); + // We need to pop a few frames so that pc is on top. + uptr to_pop = LocatePcInTrace(pc); + // trace_buffer[0] belongs to the current function so we always pop it, + // unless there is only 1 frame in the stack trace (1 frame is always better + // than 0!). + PopStackFrames(Min(to_pop, static_cast(1))); + trace_buffer[0] = pc; +} + +void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) { + CHECK(context); + CHECK_GE(max_depth, 2); + UNREACHABLE("signal context doesn't exist"); +} +#endif // SANITIZER_CAN_SLOW_UNWIND + +} // namespace __sanitizer + +#endif // SANITIZER_SYMBOLIZER_MARKUP diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc deleted file mode 100644 index 2df3a90bafaa..000000000000 --- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ /dev/null @@ -1,539 +0,0 @@ -//===-- sanitizer_symbolizer_posix_libcdep.cc -----------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. -// POSIX-specific implementation of symbolizer parts. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_POSIX -#include "sanitizer_allocator_internal.h" -#include "sanitizer_common.h" -#include "sanitizer_file.h" -#include "sanitizer_flags.h" -#include "sanitizer_internal_defs.h" -#include "sanitizer_linux.h" -#include "sanitizer_placement_new.h" -#include "sanitizer_posix.h" -#include "sanitizer_procmaps.h" -#include "sanitizer_symbolizer_internal.h" -#include "sanitizer_symbolizer_libbacktrace.h" -#include "sanitizer_symbolizer_mac.h" - -#include // for dlsym() -#include -#include -#include -#include -#include - -#if SANITIZER_MAC -#include // for forkpty() -#endif // SANITIZER_MAC - -// C++ demangling function, as required by Itanium C++ ABI. This is weak, -// because we do not require a C++ ABI library to be linked to a program -// using sanitizers; if it's not present, we'll just use the mangled name. -namespace __cxxabiv1 { - extern "C" SANITIZER_WEAK_ATTRIBUTE - char *__cxa_demangle(const char *mangled, char *buffer, - size_t *length, int *status); -} - -namespace __sanitizer { - -// Attempts to demangle the name via __cxa_demangle from __cxxabiv1. -const char *DemangleCXXABI(const char *name) { - // FIXME: __cxa_demangle aggressively insists on allocating memory. - // There's not much we can do about that, short of providing our - // own demangler (libc++abi's implementation could be adapted so that - // it does not allocate). For now, we just call it anyway, and we leak - // the returned value. - if (&__cxxabiv1::__cxa_demangle) - if (const char *demangled_name = - __cxxabiv1::__cxa_demangle(name, 0, 0, 0)) - return demangled_name; - - return name; -} - -// As of now, there are no headers for the Swift runtime. Once they are -// present, we will weakly link since we do not require Swift runtime to be -// linked. -typedef char *(*swift_demangle_ft)(const char *mangledName, - size_t mangledNameLength, char *outputBuffer, - size_t *outputBufferSize, uint32_t flags); -static swift_demangle_ft swift_demangle_f; - -// This must not happen lazily at symbolication time, because dlsym uses -// malloc and thread-local storage, which is not a good thing to do during -// symbolication. -static void InitializeSwiftDemangler() { - swift_demangle_f = (swift_demangle_ft)dlsym(RTLD_DEFAULT, "swift_demangle"); - (void)dlerror(); // Cleanup error message in case of failure -} - -// Attempts to demangle a Swift name. The demangler will return nullptr if a -// non-Swift name is passed in. -const char *DemangleSwift(const char *name) { - if (!name) return nullptr; - - // Check if we are dealing with a Swift mangled name first. - if (name[0] != '_' || name[1] != 'T') { - return nullptr; - } - - if (swift_demangle_f) - return swift_demangle_f(name, internal_strlen(name), 0, 0, 0); - - return nullptr; -} - -const char *DemangleSwiftAndCXX(const char *name) { - if (!name) return nullptr; - if (const char *swift_demangled_name = DemangleSwift(name)) - return swift_demangled_name; - return DemangleCXXABI(name); -} - -static bool CreateTwoHighNumberedPipes(int *infd_, int *outfd_) { - int *infd = NULL; - int *outfd = NULL; - // The client program may close its stdin and/or stdout and/or stderr - // thus allowing socketpair to reuse file descriptors 0, 1 or 2. - // In this case the communication between the forked processes may be - // broken if either the parent or the child tries to close or duplicate - // these descriptors. The loop below produces two pairs of file - // descriptors, each greater than 2 (stderr). - int sock_pair[5][2]; - for (int i = 0; i < 5; i++) { - if (pipe(sock_pair[i]) == -1) { - for (int j = 0; j < i; j++) { - internal_close(sock_pair[j][0]); - internal_close(sock_pair[j][1]); - } - return false; - } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) { - if (infd == NULL) { - infd = sock_pair[i]; - } else { - outfd = sock_pair[i]; - for (int j = 0; j < i; j++) { - if (sock_pair[j] == infd) continue; - internal_close(sock_pair[j][0]); - internal_close(sock_pair[j][1]); - } - break; - } - } - } - CHECK(infd); - CHECK(outfd); - infd_[0] = infd[0]; - infd_[1] = infd[1]; - outfd_[0] = outfd[0]; - outfd_[1] = outfd[1]; - return true; -} - -bool SymbolizerProcess::StartSymbolizerSubprocess() { - if (!FileExists(path_)) { - if (!reported_invalid_path_) { - Report("WARNING: invalid path to external symbolizer!\n"); - reported_invalid_path_ = true; - } - return false; - } - - int pid = -1; - - int infd[2]; - internal_memset(&infd, 0, sizeof(infd)); - int outfd[2]; - internal_memset(&outfd, 0, sizeof(outfd)); - if (!CreateTwoHighNumberedPipes(infd, outfd)) { - Report("WARNING: Can't create a socket pair to start " - "external symbolizer (errno: %d)\n", errno); - return false; - } - - if (use_forkpty_) { -#if SANITIZER_MAC - fd_t fd = kInvalidFd; - - // forkpty redirects stdout and stderr into a single stream, so we would - // receive error messages as standard replies. To avoid that, let's dup - // stderr and restore it in the child. - int saved_stderr = dup(STDERR_FILENO); - CHECK_GE(saved_stderr, 0); - - // We only need one pipe, for stdin of the child. - close(outfd[0]); - close(outfd[1]); - - // Use forkpty to disable buffering in the new terminal. - pid = internal_forkpty(&fd); - if (pid == -1) { - // forkpty() failed. - Report("WARNING: failed to fork external symbolizer (errno: %d)\n", - errno); - return false; - } else if (pid == 0) { - // Child subprocess. - - // infd[0] is the child's reading end. - close(infd[1]); - - // Set up stdin to read from the pipe. - CHECK_GE(dup2(infd[0], STDIN_FILENO), 0); - close(infd[0]); - - // Restore stderr. - CHECK_GE(dup2(saved_stderr, STDERR_FILENO), 0); - close(saved_stderr); - - const char *argv[kArgVMax]; - GetArgV(path_, argv); - execv(path_, const_cast(&argv[0])); - internal__exit(1); - } - - // Input for the child, infd[1] is our writing end. - output_fd_ = infd[1]; - close(infd[0]); - - // Continue execution in parent process. - input_fd_ = fd; - - close(saved_stderr); - - // Disable echo in the new terminal, disable CR. - struct termios termflags; - tcgetattr(fd, &termflags); - termflags.c_oflag &= ~ONLCR; - termflags.c_lflag &= ~ECHO; - tcsetattr(fd, TCSANOW, &termflags); -#else // SANITIZER_MAC - UNIMPLEMENTED(); -#endif // SANITIZER_MAC - } else { - const char *argv[kArgVMax]; - GetArgV(path_, argv); - pid = StartSubprocess(path_, argv, /* stdin */ outfd[0], - /* stdout */ infd[1]); - if (pid < 0) { - internal_close(infd[0]); - internal_close(outfd[1]); - return false; - } - - input_fd_ = infd[0]; - output_fd_ = outfd[1]; - } - - CHECK_GT(pid, 0); - - // Check that symbolizer subprocess started successfully. - SleepForMillis(kSymbolizerStartupTimeMillis); - if (!IsProcessRunning(pid)) { - // Either waitpid failed, or child has already exited. - Report("WARNING: external symbolizer didn't start up correctly!\n"); - return false; - } - - return true; -} - -class Addr2LineProcess : public SymbolizerProcess { - public: - Addr2LineProcess(const char *path, const char *module_name) - : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {} - - const char *module_name() const { return module_name_; } - - private: - void GetArgV(const char *path_to_binary, - const char *(&argv)[kArgVMax]) const override { - int i = 0; - argv[i++] = path_to_binary; - argv[i++] = "-iCfe"; - argv[i++] = module_name_; - argv[i++] = nullptr; - } - - bool ReachedEndOfOutput(const char *buffer, uptr length) const override; - - bool ReadFromSymbolizer(char *buffer, uptr max_length) override { - if (!SymbolizerProcess::ReadFromSymbolizer(buffer, max_length)) - return false; - // The returned buffer is empty when output is valid, but exceeds - // max_length. - if (*buffer == '\0') - return true; - // We should cut out output_terminator_ at the end of given buffer, - // appended by addr2line to mark the end of its meaningful output. - // We cannot scan buffer from it's beginning, because it is legal for it - // to start with output_terminator_ in case given offset is invalid. So, - // scanning from second character. - char *garbage = internal_strstr(buffer + 1, output_terminator_); - // This should never be NULL since buffer must end up with - // output_terminator_. - CHECK(garbage); - // Trim the buffer. - garbage[0] = '\0'; - return true; - } - - const char *module_name_; // Owned, leaked. - static const char output_terminator_[]; -}; - -const char Addr2LineProcess::output_terminator_[] = "??\n??:0\n"; - -bool Addr2LineProcess::ReachedEndOfOutput(const char *buffer, - uptr length) const { - const size_t kTerminatorLen = sizeof(output_terminator_) - 1; - // Skip, if we read just kTerminatorLen bytes, because Addr2Line output - // should consist at least of two pairs of lines: - // 1. First one, corresponding to given offset to be symbolized - // (may be equal to output_terminator_, if offset is not valid). - // 2. Second one for output_terminator_, itself to mark the end of output. - if (length <= kTerminatorLen) return false; - // Addr2Line output should end up with output_terminator_. - return !internal_memcmp(buffer + length - kTerminatorLen, - output_terminator_, kTerminatorLen); -} - -class Addr2LinePool : public SymbolizerTool { - public: - explicit Addr2LinePool(const char *addr2line_path, - LowLevelAllocator *allocator) - : addr2line_path_(addr2line_path), allocator_(allocator) { - addr2line_pool_.reserve(16); - } - - bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { - if (const char *buf = - SendCommand(stack->info.module, stack->info.module_offset)) { - ParseSymbolizePCOutput(buf, stack); - return true; - } - return false; - } - - bool SymbolizeData(uptr addr, DataInfo *info) override { - return false; - } - - private: - const char *SendCommand(const char *module_name, uptr module_offset) { - Addr2LineProcess *addr2line = 0; - for (uptr i = 0; i < addr2line_pool_.size(); ++i) { - if (0 == - internal_strcmp(module_name, addr2line_pool_[i]->module_name())) { - addr2line = addr2line_pool_[i]; - break; - } - } - if (!addr2line) { - addr2line = - new(*allocator_) Addr2LineProcess(addr2line_path_, module_name); - addr2line_pool_.push_back(addr2line); - } - CHECK_EQ(0, internal_strcmp(module_name, addr2line->module_name())); - char buffer[kBufferSize]; - internal_snprintf(buffer, kBufferSize, "0x%zx\n0x%zx\n", - module_offset, dummy_address_); - return addr2line->SendCommand(buffer); - } - - static const uptr kBufferSize = 64; - const char *addr2line_path_; - LowLevelAllocator *allocator_; - InternalMmapVector addr2line_pool_; - static const uptr dummy_address_ = - FIRST_32_SECOND_64(UINT32_MAX, UINT64_MAX); -}; - -#if SANITIZER_SUPPORTS_WEAK_HOOKS -extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE -bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset, - char *Buffer, int MaxLength); -SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE -bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset, - char *Buffer, int MaxLength); -SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE -void __sanitizer_symbolize_flush(); -SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE -int __sanitizer_symbolize_demangle(const char *Name, char *Buffer, - int MaxLength); -} // extern "C" - -class InternalSymbolizer : public SymbolizerTool { - public: - static InternalSymbolizer *get(LowLevelAllocator *alloc) { - if (__sanitizer_symbolize_code != 0 && - __sanitizer_symbolize_data != 0) { - return new(*alloc) InternalSymbolizer(); - } - return 0; - } - - bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { - bool result = __sanitizer_symbolize_code( - stack->info.module, stack->info.module_offset, buffer_, kBufferSize); - if (result) ParseSymbolizePCOutput(buffer_, stack); - return result; - } - - bool SymbolizeData(uptr addr, DataInfo *info) override { - bool result = __sanitizer_symbolize_data(info->module, info->module_offset, - buffer_, kBufferSize); - if (result) { - ParseSymbolizeDataOutput(buffer_, info); - info->start += (addr - info->module_offset); // Add the base address. - } - return result; - } - - void Flush() override { - if (__sanitizer_symbolize_flush) - __sanitizer_symbolize_flush(); - } - - const char *Demangle(const char *name) override { - if (__sanitizer_symbolize_demangle) { - for (uptr res_length = 1024; - res_length <= InternalSizeClassMap::kMaxSize;) { - char *res_buff = static_cast(InternalAlloc(res_length)); - uptr req_length = - __sanitizer_symbolize_demangle(name, res_buff, res_length); - if (req_length > res_length) { - res_length = req_length + 1; - InternalFree(res_buff); - continue; - } - return res_buff; - } - } - return name; - } - - private: - InternalSymbolizer() { } - - static const int kBufferSize = 16 * 1024; - char buffer_[kBufferSize]; -}; -#else // SANITIZER_SUPPORTS_WEAK_HOOKS - -class InternalSymbolizer : public SymbolizerTool { - public: - static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; } -}; - -#endif // SANITIZER_SUPPORTS_WEAK_HOOKS - -const char *Symbolizer::PlatformDemangle(const char *name) { - return DemangleSwiftAndCXX(name); -} - -static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) { - const char *path = common_flags()->external_symbolizer_path; - const char *binary_name = path ? StripModuleName(path) : ""; - if (path && path[0] == '\0') { - VReport(2, "External symbolizer is explicitly disabled.\n"); - return nullptr; - } else if (!internal_strcmp(binary_name, "llvm-symbolizer")) { - VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path); - return new(*allocator) LLVMSymbolizer(path, allocator); - } else if (!internal_strcmp(binary_name, "atos")) { -#if SANITIZER_MAC - VReport(2, "Using atos at user-specified path: %s\n", path); - return new(*allocator) AtosSymbolizer(path, allocator); -#else // SANITIZER_MAC - Report("ERROR: Using `atos` is only supported on Darwin.\n"); - Die(); -#endif // SANITIZER_MAC - } else if (!internal_strcmp(binary_name, "addr2line")) { - VReport(2, "Using addr2line at user-specified path: %s\n", path); - return new(*allocator) Addr2LinePool(path, allocator); - } else if (path) { - Report("ERROR: External symbolizer path is set to '%s' which isn't " - "a known symbolizer. Please set the path to the llvm-symbolizer " - "binary or other known tool.\n", path); - Die(); - } - - // Otherwise symbolizer program is unknown, let's search $PATH - CHECK(path == nullptr); -#if SANITIZER_MAC - if (const char *found_path = FindPathToBinary("atos")) { - VReport(2, "Using atos found at: %s\n", found_path); - return new(*allocator) AtosSymbolizer(found_path, allocator); - } -#endif // SANITIZER_MAC - if (const char *found_path = FindPathToBinary("llvm-symbolizer")) { - VReport(2, "Using llvm-symbolizer found at: %s\n", found_path); - return new(*allocator) LLVMSymbolizer(found_path, allocator); - } - if (common_flags()->allow_addr2line) { - if (const char *found_path = FindPathToBinary("addr2line")) { - VReport(2, "Using addr2line found at: %s\n", found_path); - return new(*allocator) Addr2LinePool(found_path, allocator); - } - } - return nullptr; -} - -static void ChooseSymbolizerTools(IntrusiveList *list, - LowLevelAllocator *allocator) { - if (!common_flags()->symbolize) { - VReport(2, "Symbolizer is disabled.\n"); - return; - } - if (IsAllocatorOutOfMemory()) { - VReport(2, "Cannot use internal symbolizer: out of memory\n"); - } else if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) { - VReport(2, "Using internal symbolizer.\n"); - list->push_back(tool); - return; - } - if (SymbolizerTool *tool = LibbacktraceSymbolizer::get(allocator)) { - VReport(2, "Using libbacktrace symbolizer.\n"); - list->push_back(tool); - return; - } - - if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) { - list->push_back(tool); - } - -#if SANITIZER_MAC - VReport(2, "Using dladdr symbolizer.\n"); - list->push_back(new(*allocator) DlAddrSymbolizer()); -#endif // SANITIZER_MAC -} - -Symbolizer *Symbolizer::PlatformInit() { - IntrusiveList list; - list.clear(); - ChooseSymbolizerTools(&list, &symbolizer_allocator_); - return new(symbolizer_allocator_) Symbolizer(list); -} - -void Symbolizer::LateInitialize() { - Symbolizer::GetOrInit(); - InitializeSwiftDemangler(); -} - -} // namespace __sanitizer - -#endif // SANITIZER_POSIX diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp new file mode 100644 index 000000000000..c123ecb11206 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -0,0 +1,487 @@ +//===-- sanitizer_symbolizer_posix_libcdep.cpp ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +// POSIX-specific implementation of symbolizer parts. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_POSIX +#include "sanitizer_allocator_internal.h" +#include "sanitizer_common.h" +#include "sanitizer_file.h" +#include "sanitizer_flags.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_linux.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_posix.h" +#include "sanitizer_procmaps.h" +#include "sanitizer_symbolizer_internal.h" +#include "sanitizer_symbolizer_libbacktrace.h" +#include "sanitizer_symbolizer_mac.h" + +#include // for dlsym() +#include +#include +#include +#include +#include + +// C++ demangling function, as required by Itanium C++ ABI. This is weak, +// because we do not require a C++ ABI library to be linked to a program +// using sanitizers; if it's not present, we'll just use the mangled name. +namespace __cxxabiv1 { + extern "C" SANITIZER_WEAK_ATTRIBUTE + char *__cxa_demangle(const char *mangled, char *buffer, + size_t *length, int *status); +} + +namespace __sanitizer { + +// Attempts to demangle the name via __cxa_demangle from __cxxabiv1. +const char *DemangleCXXABI(const char *name) { + // FIXME: __cxa_demangle aggressively insists on allocating memory. + // There's not much we can do about that, short of providing our + // own demangler (libc++abi's implementation could be adapted so that + // it does not allocate). For now, we just call it anyway, and we leak + // the returned value. + if (&__cxxabiv1::__cxa_demangle) + if (const char *demangled_name = + __cxxabiv1::__cxa_demangle(name, 0, 0, 0)) + return demangled_name; + + return name; +} + +// As of now, there are no headers for the Swift runtime. Once they are +// present, we will weakly link since we do not require Swift runtime to be +// linked. +typedef char *(*swift_demangle_ft)(const char *mangledName, + size_t mangledNameLength, char *outputBuffer, + size_t *outputBufferSize, uint32_t flags); +static swift_demangle_ft swift_demangle_f; + +// This must not happen lazily at symbolication time, because dlsym uses +// malloc and thread-local storage, which is not a good thing to do during +// symbolication. +static void InitializeSwiftDemangler() { + swift_demangle_f = (swift_demangle_ft)dlsym(RTLD_DEFAULT, "swift_demangle"); + (void)dlerror(); // Cleanup error message in case of failure +} + +// Attempts to demangle a Swift name. The demangler will return nullptr if a +// non-Swift name is passed in. +const char *DemangleSwift(const char *name) { + if (!name) return nullptr; + + // Check if we are dealing with a Swift mangled name first. + if (name[0] != '_' || name[1] != 'T') { + return nullptr; + } + + if (swift_demangle_f) + return swift_demangle_f(name, internal_strlen(name), 0, 0, 0); + + return nullptr; +} + +const char *DemangleSwiftAndCXX(const char *name) { + if (!name) return nullptr; + if (const char *swift_demangled_name = DemangleSwift(name)) + return swift_demangled_name; + return DemangleCXXABI(name); +} + +static bool CreateTwoHighNumberedPipes(int *infd_, int *outfd_) { + int *infd = NULL; + int *outfd = NULL; + // The client program may close its stdin and/or stdout and/or stderr + // thus allowing socketpair to reuse file descriptors 0, 1 or 2. + // In this case the communication between the forked processes may be + // broken if either the parent or the child tries to close or duplicate + // these descriptors. The loop below produces two pairs of file + // descriptors, each greater than 2 (stderr). + int sock_pair[5][2]; + for (int i = 0; i < 5; i++) { + if (pipe(sock_pair[i]) == -1) { + for (int j = 0; j < i; j++) { + internal_close(sock_pair[j][0]); + internal_close(sock_pair[j][1]); + } + return false; + } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) { + if (infd == NULL) { + infd = sock_pair[i]; + } else { + outfd = sock_pair[i]; + for (int j = 0; j < i; j++) { + if (sock_pair[j] == infd) continue; + internal_close(sock_pair[j][0]); + internal_close(sock_pair[j][1]); + } + break; + } + } + } + CHECK(infd); + CHECK(outfd); + infd_[0] = infd[0]; + infd_[1] = infd[1]; + outfd_[0] = outfd[0]; + outfd_[1] = outfd[1]; + return true; +} + +bool SymbolizerProcess::StartSymbolizerSubprocess() { + if (!FileExists(path_)) { + if (!reported_invalid_path_) { + Report("WARNING: invalid path to external symbolizer!\n"); + reported_invalid_path_ = true; + } + return false; + } + + const char *argv[kArgVMax]; + GetArgV(path_, argv); + pid_t pid; + + if (use_posix_spawn_) { +#if SANITIZER_MAC + fd_t fd = internal_spawn(argv, &pid); + if (fd == kInvalidFd) { + Report("WARNING: failed to spawn external symbolizer (errno: %d)\n", + errno); + return false; + } + + input_fd_ = fd; + output_fd_ = fd; +#else // SANITIZER_MAC + UNIMPLEMENTED(); +#endif // SANITIZER_MAC + } else { + fd_t infd[2] = {}, outfd[2] = {}; + if (!CreateTwoHighNumberedPipes(infd, outfd)) { + Report("WARNING: Can't create a socket pair to start " + "external symbolizer (errno: %d)\n", errno); + return false; + } + + pid = StartSubprocess(path_, argv, /* stdin */ outfd[0], + /* stdout */ infd[1]); + if (pid < 0) { + internal_close(infd[0]); + internal_close(outfd[1]); + return false; + } + + input_fd_ = infd[0]; + output_fd_ = outfd[1]; + } + + CHECK_GT(pid, 0); + + // Check that symbolizer subprocess started successfully. + SleepForMillis(kSymbolizerStartupTimeMillis); + if (!IsProcessRunning(pid)) { + // Either waitpid failed, or child has already exited. + Report("WARNING: external symbolizer didn't start up correctly!\n"); + return false; + } + + return true; +} + +class Addr2LineProcess : public SymbolizerProcess { + public: + Addr2LineProcess(const char *path, const char *module_name) + : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {} + + const char *module_name() const { return module_name_; } + + private: + void GetArgV(const char *path_to_binary, + const char *(&argv)[kArgVMax]) const override { + int i = 0; + argv[i++] = path_to_binary; + argv[i++] = "-iCfe"; + argv[i++] = module_name_; + argv[i++] = nullptr; + } + + bool ReachedEndOfOutput(const char *buffer, uptr length) const override; + + bool ReadFromSymbolizer(char *buffer, uptr max_length) override { + if (!SymbolizerProcess::ReadFromSymbolizer(buffer, max_length)) + return false; + // The returned buffer is empty when output is valid, but exceeds + // max_length. + if (*buffer == '\0') + return true; + // We should cut out output_terminator_ at the end of given buffer, + // appended by addr2line to mark the end of its meaningful output. + // We cannot scan buffer from it's beginning, because it is legal for it + // to start with output_terminator_ in case given offset is invalid. So, + // scanning from second character. + char *garbage = internal_strstr(buffer + 1, output_terminator_); + // This should never be NULL since buffer must end up with + // output_terminator_. + CHECK(garbage); + // Trim the buffer. + garbage[0] = '\0'; + return true; + } + + const char *module_name_; // Owned, leaked. + static const char output_terminator_[]; +}; + +const char Addr2LineProcess::output_terminator_[] = "??\n??:0\n"; + +bool Addr2LineProcess::ReachedEndOfOutput(const char *buffer, + uptr length) const { + const size_t kTerminatorLen = sizeof(output_terminator_) - 1; + // Skip, if we read just kTerminatorLen bytes, because Addr2Line output + // should consist at least of two pairs of lines: + // 1. First one, corresponding to given offset to be symbolized + // (may be equal to output_terminator_, if offset is not valid). + // 2. Second one for output_terminator_, itself to mark the end of output. + if (length <= kTerminatorLen) return false; + // Addr2Line output should end up with output_terminator_. + return !internal_memcmp(buffer + length - kTerminatorLen, + output_terminator_, kTerminatorLen); +} + +class Addr2LinePool : public SymbolizerTool { + public: + explicit Addr2LinePool(const char *addr2line_path, + LowLevelAllocator *allocator) + : addr2line_path_(addr2line_path), allocator_(allocator) { + addr2line_pool_.reserve(16); + } + + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { + if (const char *buf = + SendCommand(stack->info.module, stack->info.module_offset)) { + ParseSymbolizePCOutput(buf, stack); + return true; + } + return false; + } + + bool SymbolizeData(uptr addr, DataInfo *info) override { + return false; + } + + private: + const char *SendCommand(const char *module_name, uptr module_offset) { + Addr2LineProcess *addr2line = 0; + for (uptr i = 0; i < addr2line_pool_.size(); ++i) { + if (0 == + internal_strcmp(module_name, addr2line_pool_[i]->module_name())) { + addr2line = addr2line_pool_[i]; + break; + } + } + if (!addr2line) { + addr2line = + new(*allocator_) Addr2LineProcess(addr2line_path_, module_name); + addr2line_pool_.push_back(addr2line); + } + CHECK_EQ(0, internal_strcmp(module_name, addr2line->module_name())); + char buffer[kBufferSize]; + internal_snprintf(buffer, kBufferSize, "0x%zx\n0x%zx\n", + module_offset, dummy_address_); + return addr2line->SendCommand(buffer); + } + + static const uptr kBufferSize = 64; + const char *addr2line_path_; + LowLevelAllocator *allocator_; + InternalMmapVector addr2line_pool_; + static const uptr dummy_address_ = + FIRST_32_SECOND_64(UINT32_MAX, UINT64_MAX); +}; + +#if SANITIZER_SUPPORTS_WEAK_HOOKS +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset, + char *Buffer, int MaxLength); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset, + char *Buffer, int MaxLength); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +void __sanitizer_symbolize_flush(); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +int __sanitizer_symbolize_demangle(const char *Name, char *Buffer, + int MaxLength); +} // extern "C" + +class InternalSymbolizer : public SymbolizerTool { + public: + static InternalSymbolizer *get(LowLevelAllocator *alloc) { + if (__sanitizer_symbolize_code != 0 && + __sanitizer_symbolize_data != 0) { + return new(*alloc) InternalSymbolizer(); + } + return 0; + } + + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { + bool result = __sanitizer_symbolize_code( + stack->info.module, stack->info.module_offset, buffer_, kBufferSize); + if (result) ParseSymbolizePCOutput(buffer_, stack); + return result; + } + + bool SymbolizeData(uptr addr, DataInfo *info) override { + bool result = __sanitizer_symbolize_data(info->module, info->module_offset, + buffer_, kBufferSize); + if (result) { + ParseSymbolizeDataOutput(buffer_, info); + info->start += (addr - info->module_offset); // Add the base address. + } + return result; + } + + void Flush() override { + if (__sanitizer_symbolize_flush) + __sanitizer_symbolize_flush(); + } + + const char *Demangle(const char *name) override { + if (__sanitizer_symbolize_demangle) { + for (uptr res_length = 1024; + res_length <= InternalSizeClassMap::kMaxSize;) { + char *res_buff = static_cast(InternalAlloc(res_length)); + uptr req_length = + __sanitizer_symbolize_demangle(name, res_buff, res_length); + if (req_length > res_length) { + res_length = req_length + 1; + InternalFree(res_buff); + continue; + } + return res_buff; + } + } + return name; + } + + private: + InternalSymbolizer() { } + + static const int kBufferSize = 16 * 1024; + char buffer_[kBufferSize]; +}; +#else // SANITIZER_SUPPORTS_WEAK_HOOKS + +class InternalSymbolizer : public SymbolizerTool { + public: + static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; } +}; + +#endif // SANITIZER_SUPPORTS_WEAK_HOOKS + +const char *Symbolizer::PlatformDemangle(const char *name) { + return DemangleSwiftAndCXX(name); +} + +static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) { + const char *path = common_flags()->external_symbolizer_path; + const char *binary_name = path ? StripModuleName(path) : ""; + if (path && path[0] == '\0') { + VReport(2, "External symbolizer is explicitly disabled.\n"); + return nullptr; + } else if (!internal_strcmp(binary_name, "llvm-symbolizer")) { + VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path); + return new(*allocator) LLVMSymbolizer(path, allocator); + } else if (!internal_strcmp(binary_name, "atos")) { +#if SANITIZER_MAC + VReport(2, "Using atos at user-specified path: %s\n", path); + return new(*allocator) AtosSymbolizer(path, allocator); +#else // SANITIZER_MAC + Report("ERROR: Using `atos` is only supported on Darwin.\n"); + Die(); +#endif // SANITIZER_MAC + } else if (!internal_strcmp(binary_name, "addr2line")) { + VReport(2, "Using addr2line at user-specified path: %s\n", path); + return new(*allocator) Addr2LinePool(path, allocator); + } else if (path) { + Report("ERROR: External symbolizer path is set to '%s' which isn't " + "a known symbolizer. Please set the path to the llvm-symbolizer " + "binary or other known tool.\n", path); + Die(); + } + + // Otherwise symbolizer program is unknown, let's search $PATH + CHECK(path == nullptr); +#if SANITIZER_MAC + if (const char *found_path = FindPathToBinary("atos")) { + VReport(2, "Using atos found at: %s\n", found_path); + return new(*allocator) AtosSymbolizer(found_path, allocator); + } +#endif // SANITIZER_MAC + if (const char *found_path = FindPathToBinary("llvm-symbolizer")) { + VReport(2, "Using llvm-symbolizer found at: %s\n", found_path); + return new(*allocator) LLVMSymbolizer(found_path, allocator); + } + if (common_flags()->allow_addr2line) { + if (const char *found_path = FindPathToBinary("addr2line")) { + VReport(2, "Using addr2line found at: %s\n", found_path); + return new(*allocator) Addr2LinePool(found_path, allocator); + } + } + return nullptr; +} + +static void ChooseSymbolizerTools(IntrusiveList *list, + LowLevelAllocator *allocator) { + if (!common_flags()->symbolize) { + VReport(2, "Symbolizer is disabled.\n"); + return; + } + if (IsAllocatorOutOfMemory()) { + VReport(2, "Cannot use internal symbolizer: out of memory\n"); + } else if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) { + VReport(2, "Using internal symbolizer.\n"); + list->push_back(tool); + return; + } + if (SymbolizerTool *tool = LibbacktraceSymbolizer::get(allocator)) { + VReport(2, "Using libbacktrace symbolizer.\n"); + list->push_back(tool); + return; + } + + if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) { + list->push_back(tool); + } + +#if SANITIZER_MAC + VReport(2, "Using dladdr symbolizer.\n"); + list->push_back(new(*allocator) DlAddrSymbolizer()); +#endif // SANITIZER_MAC +} + +Symbolizer *Symbolizer::PlatformInit() { + IntrusiveList list; + list.clear(); + ChooseSymbolizerTools(&list, &symbolizer_allocator_); + return new(symbolizer_allocator_) Symbolizer(list); +} + +void Symbolizer::LateInitialize() { + Symbolizer::GetOrInit(); + InitializeSwiftDemangler(); +} + +} // namespace __sanitizer + +#endif // SANITIZER_POSIX diff --git a/lib/sanitizer_common/sanitizer_symbolizer_report.cc b/lib/sanitizer_common/sanitizer_symbolizer_report.cc deleted file mode 100644 index f4167d160ae8..000000000000 --- a/lib/sanitizer_common/sanitizer_symbolizer_report.cc +++ /dev/null @@ -1,283 +0,0 @@ -//===-- sanitizer_symbolizer_report.cc ------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// This file is shared between AddressSanitizer and other sanitizer run-time -/// libraries and implements symbolized reports related functions. -/// -//===----------------------------------------------------------------------===// - -#include "sanitizer_common.h" -#include "sanitizer_file.h" -#include "sanitizer_flags.h" -#include "sanitizer_procmaps.h" -#include "sanitizer_report_decorator.h" -#include "sanitizer_stacktrace.h" -#include "sanitizer_stacktrace_printer.h" -#include "sanitizer_symbolizer.h" - -#if SANITIZER_POSIX -# include "sanitizer_posix.h" -# include -#endif - -namespace __sanitizer { - -#if !SANITIZER_GO -void ReportErrorSummary(const char *error_type, const AddressInfo &info, - const char *alt_tool_name) { - if (!common_flags()->print_summary) return; - InternalScopedString buff(kMaxSummaryLength); - buff.append("%s ", error_type); - RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style, - common_flags()->strip_path_prefix); - ReportErrorSummary(buff.data(), alt_tool_name); -} -#endif - -#if !SANITIZER_FUCHSIA - -bool ReportFile::SupportsColors() { - SpinMutexLock l(mu); - ReopenIfNecessary(); - return SupportsColoredOutput(fd); -} - -static INLINE bool ReportSupportsColors() { - return report_file.SupportsColors(); -} - -#else // SANITIZER_FUCHSIA - -// Fuchsia's logs always go through post-processing that handles colorization. -static INLINE bool ReportSupportsColors() { return true; } - -#endif // !SANITIZER_FUCHSIA - -bool ColorizeReports() { - // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color - // printing on Windows. - if (SANITIZER_WINDOWS) - return false; - - const char *flag = common_flags()->color; - return internal_strcmp(flag, "always") == 0 || - (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors()); -} - -void ReportErrorSummary(const char *error_type, const StackTrace *stack, - const char *alt_tool_name) { -#if !SANITIZER_GO - if (!common_flags()->print_summary) - return; - if (stack->size == 0) { - ReportErrorSummary(error_type); - return; - } - // Currently, we include the first stack frame into the report summary. - // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). - uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); - SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); - ReportErrorSummary(error_type, frame->info, alt_tool_name); - frame->ClearAll(); -#endif -} - -void ReportMmapWriteExec(int prot) { -#if SANITIZER_POSIX && (!SANITIZER_GO && !SANITIZER_ANDROID) - if ((prot & (PROT_WRITE | PROT_EXEC)) != (PROT_WRITE | PROT_EXEC)) - return; - - ScopedErrorReportLock l; - SanitizerCommonDecorator d; - - InternalMmapVector stack_buffer(1); - BufferedStackTrace *stack = stack_buffer.data(); - stack->Reset(); - uptr top = 0; - uptr bottom = 0; - GET_CALLER_PC_BP_SP; - (void)sp; - bool fast = common_flags()->fast_unwind_on_fatal; - if (StackTrace::WillUseFastUnwind(fast)) { - GetThreadStackTopAndBottom(false, &top, &bottom); - stack->Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, true); - } else - stack->Unwind(kStackTraceMax, pc, 0, nullptr, 0, 0, false); - - Printf("%s", d.Warning()); - Report("WARNING: %s: writable-executable page usage\n", SanitizerToolName); - Printf("%s", d.Default()); - - stack->Print(); - ReportErrorSummary("w-and-x-usage", stack); -#endif -} - -#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_GO -void StartReportDeadlySignal() { - // Write the first message using fd=2, just in case. - // It may actually fail to write in case stderr is closed. - CatastrophicErrorWrite(SanitizerToolName, internal_strlen(SanitizerToolName)); - static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; - CatastrophicErrorWrite(kDeadlySignal, sizeof(kDeadlySignal) - 1); -} - -static void MaybeReportNonExecRegion(uptr pc) { -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD - MemoryMappingLayout proc_maps(/*cache_enabled*/ true); - MemoryMappedSegment segment; - while (proc_maps.Next(&segment)) { - if (pc >= segment.start && pc < segment.end && !segment.IsExecutable()) - Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n"); - } -#endif -} - -static void PrintMemoryByte(InternalScopedString *str, const char *before, - u8 byte) { - SanitizerCommonDecorator d; - str->append("%s%s%x%x%s ", before, d.MemoryByte(), byte >> 4, byte & 15, - d.Default()); -} - -static void MaybeDumpInstructionBytes(uptr pc) { - if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) - return; - InternalScopedString str(1024); - str.append("First 16 instruction bytes at pc: "); - if (IsAccessibleMemoryRange(pc, 16)) { - for (int i = 0; i < 16; ++i) { - PrintMemoryByte(&str, "", ((u8 *)pc)[i]); - } - str.append("\n"); - } else { - str.append("unaccessible\n"); - } - Report("%s", str.data()); -} - -static void MaybeDumpRegisters(void *context) { - if (!common_flags()->dump_registers) return; - SignalContext::DumpAllRegisters(context); -} - -static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid, - UnwindSignalStackCallbackType unwind, - const void *unwind_context) { - SanitizerCommonDecorator d; - Printf("%s", d.Warning()); - static const char kDescription[] = "stack-overflow"; - Report("ERROR: %s: %s on address %p (pc %p bp %p sp %p T%d)\n", - SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc, - (void *)sig.bp, (void *)sig.sp, tid); - Printf("%s", d.Default()); - InternalMmapVector stack_buffer(1); - BufferedStackTrace *stack = stack_buffer.data(); - stack->Reset(); - unwind(sig, unwind_context, stack); - stack->Print(); - ReportErrorSummary(kDescription, stack); -} - -static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid, - UnwindSignalStackCallbackType unwind, - const void *unwind_context) { - SanitizerCommonDecorator d; - Printf("%s", d.Warning()); - const char *description = sig.Describe(); - Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n", - SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc, - (void *)sig.bp, (void *)sig.sp, tid); - Printf("%s", d.Default()); - if (sig.pc < GetPageSizeCached()) - Report("Hint: pc points to the zero page.\n"); - if (sig.is_memory_access) { - const char *access_type = - sig.write_flag == SignalContext::WRITE - ? "WRITE" - : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); - Report("The signal is caused by a %s memory access.\n", access_type); - if (sig.addr < GetPageSizeCached()) - Report("Hint: address points to the zero page.\n"); - } - MaybeReportNonExecRegion(sig.pc); - InternalMmapVector stack_buffer(1); - BufferedStackTrace *stack = stack_buffer.data(); - stack->Reset(); - unwind(sig, unwind_context, stack); - stack->Print(); - MaybeDumpInstructionBytes(sig.pc); - MaybeDumpRegisters(sig.context); - Printf("%s can not provide additional info.\n", SanitizerToolName); - ReportErrorSummary(description, stack); -} - -void ReportDeadlySignal(const SignalContext &sig, u32 tid, - UnwindSignalStackCallbackType unwind, - const void *unwind_context) { - if (sig.IsStackOverflow()) - ReportStackOverflowImpl(sig, tid, unwind, unwind_context); - else - ReportDeadlySignalImpl(sig, tid, unwind, unwind_context); -} - -void HandleDeadlySignal(void *siginfo, void *context, u32 tid, - UnwindSignalStackCallbackType unwind, - const void *unwind_context) { - StartReportDeadlySignal(); - ScopedErrorReportLock rl; - SignalContext sig(siginfo, context); - ReportDeadlySignal(sig, tid, unwind, unwind_context); - Report("ABORTING\n"); - Die(); -} - -#endif // !SANITIZER_FUCHSIA && !SANITIZER_GO - -static atomic_uintptr_t reporting_thread = {0}; -static StaticSpinMutex CommonSanitizerReportMutex; - -ScopedErrorReportLock::ScopedErrorReportLock() { - uptr current = GetThreadSelf(); - for (;;) { - uptr expected = 0; - if (atomic_compare_exchange_strong(&reporting_thread, &expected, current, - memory_order_relaxed)) { - // We've claimed reporting_thread so proceed. - CommonSanitizerReportMutex.Lock(); - return; - } - - if (expected == current) { - // This is either asynch signal or nested error during error reporting. - // Fail simple to avoid deadlocks in Report(). - - // Can't use Report() here because of potential deadlocks in nested - // signal handlers. - CatastrophicErrorWrite(SanitizerToolName, - internal_strlen(SanitizerToolName)); - static const char msg[] = ": nested bug in the same thread, aborting.\n"; - CatastrophicErrorWrite(msg, sizeof(msg) - 1); - - internal__exit(common_flags()->exitcode); - } - - internal_sched_yield(); - } -} - -ScopedErrorReportLock::~ScopedErrorReportLock() { - CommonSanitizerReportMutex.Unlock(); - atomic_store_relaxed(&reporting_thread, 0); -} - -void ScopedErrorReportLock::CheckLocked() { - CommonSanitizerReportMutex.CheckLocked(); -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_report.cpp b/lib/sanitizer_common/sanitizer_symbolizer_report.cpp new file mode 100644 index 000000000000..c26724ceb7a7 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_report.cpp @@ -0,0 +1,293 @@ +//===-- sanitizer_symbolizer_report.cpp -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// This file is shared between AddressSanitizer and other sanitizer run-time +/// libraries and implements symbolized reports related functions. +/// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common.h" +#include "sanitizer_file.h" +#include "sanitizer_flags.h" +#include "sanitizer_procmaps.h" +#include "sanitizer_report_decorator.h" +#include "sanitizer_stacktrace.h" +#include "sanitizer_stacktrace_printer.h" +#include "sanitizer_symbolizer.h" + +#if SANITIZER_POSIX +# include "sanitizer_posix.h" +# include +#endif + +namespace __sanitizer { + +#if !SANITIZER_GO +void ReportErrorSummary(const char *error_type, const AddressInfo &info, + const char *alt_tool_name) { + if (!common_flags()->print_summary) return; + InternalScopedString buff(kMaxSummaryLength); + buff.append("%s ", error_type); + RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style, + common_flags()->strip_path_prefix); + ReportErrorSummary(buff.data(), alt_tool_name); +} +#endif + +#if !SANITIZER_FUCHSIA + +bool ReportFile::SupportsColors() { + SpinMutexLock l(mu); + ReopenIfNecessary(); + return SupportsColoredOutput(fd); +} + +static INLINE bool ReportSupportsColors() { + return report_file.SupportsColors(); +} + +#else // SANITIZER_FUCHSIA + +// Fuchsia's logs always go through post-processing that handles colorization. +static INLINE bool ReportSupportsColors() { return true; } + +#endif // !SANITIZER_FUCHSIA + +bool ColorizeReports() { + // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color + // printing on Windows. + if (SANITIZER_WINDOWS) + return false; + + const char *flag = common_flags()->color; + return internal_strcmp(flag, "always") == 0 || + (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors()); +} + +void ReportErrorSummary(const char *error_type, const StackTrace *stack, + const char *alt_tool_name) { +#if !SANITIZER_GO + if (!common_flags()->print_summary) + return; + if (stack->size == 0) { + ReportErrorSummary(error_type); + return; + } + // Currently, we include the first stack frame into the report summary. + // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). + uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); + SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); + ReportErrorSummary(error_type, frame->info, alt_tool_name); + frame->ClearAll(); +#endif +} + +void ReportMmapWriteExec(int prot) { +#if SANITIZER_POSIX && (!SANITIZER_GO && !SANITIZER_ANDROID) + if ((prot & (PROT_WRITE | PROT_EXEC)) != (PROT_WRITE | PROT_EXEC)) + return; + + ScopedErrorReportLock l; + SanitizerCommonDecorator d; + + InternalMmapVector stack_buffer(1); + BufferedStackTrace *stack = stack_buffer.data(); + stack->Reset(); + uptr top = 0; + uptr bottom = 0; + GET_CALLER_PC_BP_SP; + (void)sp; + bool fast = common_flags()->fast_unwind_on_fatal; + if (StackTrace::WillUseFastUnwind(fast)) { + GetThreadStackTopAndBottom(false, &top, &bottom); + stack->Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, true); + } else { + stack->Unwind(kStackTraceMax, pc, 0, nullptr, 0, 0, false); + } + + Printf("%s", d.Warning()); + Report("WARNING: %s: writable-executable page usage\n", SanitizerToolName); + Printf("%s", d.Default()); + + stack->Print(); + ReportErrorSummary("w-and-x-usage", stack); +#endif +} + +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_GO +void StartReportDeadlySignal() { + // Write the first message using fd=2, just in case. + // It may actually fail to write in case stderr is closed. + CatastrophicErrorWrite(SanitizerToolName, internal_strlen(SanitizerToolName)); + static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; + CatastrophicErrorWrite(kDeadlySignal, sizeof(kDeadlySignal) - 1); +} + +static void MaybeReportNonExecRegion(uptr pc) { +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD + MemoryMappingLayout proc_maps(/*cache_enabled*/ true); + MemoryMappedSegment segment; + while (proc_maps.Next(&segment)) { + if (pc >= segment.start && pc < segment.end && !segment.IsExecutable()) + Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n"); + } +#endif +} + +static void PrintMemoryByte(InternalScopedString *str, const char *before, + u8 byte) { + SanitizerCommonDecorator d; + str->append("%s%s%x%x%s ", before, d.MemoryByte(), byte >> 4, byte & 15, + d.Default()); +} + +static void MaybeDumpInstructionBytes(uptr pc) { + if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) + return; + InternalScopedString str(1024); + str.append("First 16 instruction bytes at pc: "); + if (IsAccessibleMemoryRange(pc, 16)) { + for (int i = 0; i < 16; ++i) { + PrintMemoryByte(&str, "", ((u8 *)pc)[i]); + } + str.append("\n"); + } else { + str.append("unaccessible\n"); + } + Report("%s", str.data()); +} + +static void MaybeDumpRegisters(void *context) { + if (!common_flags()->dump_registers) return; + SignalContext::DumpAllRegisters(context); +} + +static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + SanitizerCommonDecorator d; + Printf("%s", d.Warning()); + static const char kDescription[] = "stack-overflow"; + Report("ERROR: %s: %s on address %p (pc %p bp %p sp %p T%d)\n", + SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc, + (void *)sig.bp, (void *)sig.sp, tid); + Printf("%s", d.Default()); + InternalMmapVector stack_buffer(1); + BufferedStackTrace *stack = stack_buffer.data(); + stack->Reset(); + unwind(sig, unwind_context, stack); + stack->Print(); + ReportErrorSummary(kDescription, stack); +} + +static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + SanitizerCommonDecorator d; + Printf("%s", d.Warning()); + const char *description = sig.Describe(); + if (sig.is_memory_access && !sig.is_true_faulting_addr) + Report("ERROR: %s: %s on unknown address (pc %p bp %p sp %p T%d)\n", + SanitizerToolName, description, (void *)sig.pc, (void *)sig.bp, + (void *)sig.sp, tid); + else + Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n", + SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc, + (void *)sig.bp, (void *)sig.sp, tid); + Printf("%s", d.Default()); + if (sig.pc < GetPageSizeCached()) + Report("Hint: pc points to the zero page.\n"); + if (sig.is_memory_access) { + const char *access_type = + sig.write_flag == SignalContext::WRITE + ? "WRITE" + : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); + Report("The signal is caused by a %s memory access.\n", access_type); + if (!sig.is_true_faulting_addr) + Report("Hint: this fault was caused by a dereference of a high value " + "address (see register values below). Dissassemble the provided " + "pc to learn which register was used.\n"); + else if (sig.addr < GetPageSizeCached()) + Report("Hint: address points to the zero page.\n"); + } + MaybeReportNonExecRegion(sig.pc); + InternalMmapVector stack_buffer(1); + BufferedStackTrace *stack = stack_buffer.data(); + stack->Reset(); + unwind(sig, unwind_context, stack); + stack->Print(); + MaybeDumpInstructionBytes(sig.pc); + MaybeDumpRegisters(sig.context); + Printf("%s can not provide additional info.\n", SanitizerToolName); + ReportErrorSummary(description, stack); +} + +void ReportDeadlySignal(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + if (sig.IsStackOverflow()) + ReportStackOverflowImpl(sig, tid, unwind, unwind_context); + else + ReportDeadlySignalImpl(sig, tid, unwind, unwind_context); +} + +void HandleDeadlySignal(void *siginfo, void *context, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + StartReportDeadlySignal(); + ScopedErrorReportLock rl; + SignalContext sig(siginfo, context); + ReportDeadlySignal(sig, tid, unwind, unwind_context); + Report("ABORTING\n"); + Die(); +} + +#endif // !SANITIZER_FUCHSIA && !SANITIZER_GO + +static atomic_uintptr_t reporting_thread = {0}; +static StaticSpinMutex CommonSanitizerReportMutex; + +ScopedErrorReportLock::ScopedErrorReportLock() { + uptr current = GetThreadSelf(); + for (;;) { + uptr expected = 0; + if (atomic_compare_exchange_strong(&reporting_thread, &expected, current, + memory_order_relaxed)) { + // We've claimed reporting_thread so proceed. + CommonSanitizerReportMutex.Lock(); + return; + } + + if (expected == current) { + // This is either asynch signal or nested error during error reporting. + // Fail simple to avoid deadlocks in Report(). + + // Can't use Report() here because of potential deadlocks in nested + // signal handlers. + CatastrophicErrorWrite(SanitizerToolName, + internal_strlen(SanitizerToolName)); + static const char msg[] = ": nested bug in the same thread, aborting.\n"; + CatastrophicErrorWrite(msg, sizeof(msg) - 1); + + internal__exit(common_flags()->exitcode); + } + + internal_sched_yield(); + } +} + +ScopedErrorReportLock::~ScopedErrorReportLock() { + CommonSanitizerReportMutex.Unlock(); + atomic_store_relaxed(&reporting_thread, 0); +} + +void ScopedErrorReportLock::CheckLocked() { + CommonSanitizerReportMutex.CheckLocked(); +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/lib/sanitizer_common/sanitizer_symbolizer_win.cc deleted file mode 100644 index 1badcf5f0a35..000000000000 --- a/lib/sanitizer_common/sanitizer_symbolizer_win.cc +++ /dev/null @@ -1,318 +0,0 @@ -//===-- sanitizer_symbolizer_win.cc ---------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. -// Windows-specific implementation of symbolizer parts. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_WINDOWS - -#include "sanitizer_dbghelp.h" -#include "sanitizer_symbolizer_internal.h" - -namespace __sanitizer { - -decltype(::StackWalk64) *StackWalk64; -decltype(::SymCleanup) *SymCleanup; -decltype(::SymFromAddr) *SymFromAddr; -decltype(::SymFunctionTableAccess64) *SymFunctionTableAccess64; -decltype(::SymGetLineFromAddr64) *SymGetLineFromAddr64; -decltype(::SymGetModuleBase64) *SymGetModuleBase64; -decltype(::SymGetSearchPathW) *SymGetSearchPathW; -decltype(::SymInitialize) *SymInitialize; -decltype(::SymSetOptions) *SymSetOptions; -decltype(::SymSetSearchPathW) *SymSetSearchPathW; -decltype(::UnDecorateSymbolName) *UnDecorateSymbolName; - -namespace { - -class WinSymbolizerTool : public SymbolizerTool { - public: - // The constructor is provided to avoid synthesized memsets. - WinSymbolizerTool() {} - - bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; - bool SymbolizeData(uptr addr, DataInfo *info) override { - return false; - } - const char *Demangle(const char *name) override; -}; - -bool is_dbghelp_initialized = false; - -bool TrySymInitialize() { - SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES); - return SymInitialize(GetCurrentProcess(), 0, TRUE); - // FIXME: We don't call SymCleanup() on exit yet - should we? -} - -} // namespace - -// Initializes DbgHelp library, if it's not yet initialized. Calls to this -// function should be synchronized with respect to other calls to DbgHelp API -// (e.g. from WinSymbolizerTool). -void InitializeDbgHelpIfNeeded() { - if (is_dbghelp_initialized) - return; - - HMODULE dbghelp = LoadLibraryA("dbghelp.dll"); - CHECK(dbghelp && "failed to load dbghelp.dll"); - -#define DBGHELP_IMPORT(name) \ - do { \ - name = \ - reinterpret_cast(GetProcAddress(dbghelp, #name)); \ - CHECK(name != nullptr); \ - } while (0) - DBGHELP_IMPORT(StackWalk64); - DBGHELP_IMPORT(SymCleanup); - DBGHELP_IMPORT(SymFromAddr); - DBGHELP_IMPORT(SymFunctionTableAccess64); - DBGHELP_IMPORT(SymGetLineFromAddr64); - DBGHELP_IMPORT(SymGetModuleBase64); - DBGHELP_IMPORT(SymGetSearchPathW); - DBGHELP_IMPORT(SymInitialize); - DBGHELP_IMPORT(SymSetOptions); - DBGHELP_IMPORT(SymSetSearchPathW); - DBGHELP_IMPORT(UnDecorateSymbolName); -#undef DBGHELP_IMPORT - - if (!TrySymInitialize()) { - // OK, maybe the client app has called SymInitialize already. - // That's a bit unfortunate for us as all the DbgHelp functions are - // single-threaded and we can't coordinate with the app. - // FIXME: Can we stop the other threads at this point? - // Anyways, we have to reconfigure stuff to make sure that SymInitialize - // has all the appropriate options set. - // Cross our fingers and reinitialize DbgHelp. - Report("*** WARNING: Failed to initialize DbgHelp! ***\n"); - Report("*** Most likely this means that the app is already ***\n"); - Report("*** using DbgHelp, possibly with incompatible flags. ***\n"); - Report("*** Due to technical reasons, symbolization might crash ***\n"); - Report("*** or produce wrong results. ***\n"); - SymCleanup(GetCurrentProcess()); - TrySymInitialize(); - } - is_dbghelp_initialized = true; - - // When an executable is run from a location different from the one where it - // was originally built, we may not see the nearby PDB files. - // To work around this, let's append the directory of the main module - // to the symbol search path. All the failures below are not fatal. - const size_t kSymPathSize = 2048; - static wchar_t path_buffer[kSymPathSize + 1 + MAX_PATH]; - if (!SymGetSearchPathW(GetCurrentProcess(), path_buffer, kSymPathSize)) { - Report("*** WARNING: Failed to SymGetSearchPathW ***\n"); - return; - } - size_t sz = wcslen(path_buffer); - if (sz) { - CHECK_EQ(0, wcscat_s(path_buffer, L";")); - sz++; - } - DWORD res = GetModuleFileNameW(NULL, path_buffer + sz, MAX_PATH); - if (res == 0 || res == MAX_PATH) { - Report("*** WARNING: Failed to getting the EXE directory ***\n"); - return; - } - // Write the zero character in place of the last backslash to get the - // directory of the main module at the end of path_buffer. - wchar_t *last_bslash = wcsrchr(path_buffer + sz, L'\\'); - CHECK_NE(last_bslash, 0); - *last_bslash = L'\0'; - if (!SymSetSearchPathW(GetCurrentProcess(), path_buffer)) { - Report("*** WARNING: Failed to SymSetSearchPathW\n"); - return; - } -} - -bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) { - InitializeDbgHelpIfNeeded(); - - // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx - char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)]; - PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; - symbol->SizeOfStruct = sizeof(SYMBOL_INFO); - symbol->MaxNameLen = MAX_SYM_NAME; - DWORD64 offset = 0; - BOOL got_objname = SymFromAddr(GetCurrentProcess(), - (DWORD64)addr, &offset, symbol); - if (!got_objname) - return false; - - DWORD unused; - IMAGEHLP_LINE64 line_info; - line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)addr, - &unused, &line_info); - frame->info.function = internal_strdup(symbol->Name); - frame->info.function_offset = (uptr)offset; - if (got_fileline) { - frame->info.file = internal_strdup(line_info.FileName); - frame->info.line = line_info.LineNumber; - } - // Only consider this a successful symbolization attempt if we got file info. - // Otherwise, try llvm-symbolizer. - return got_fileline; -} - -const char *WinSymbolizerTool::Demangle(const char *name) { - CHECK(is_dbghelp_initialized); - static char demangle_buffer[1000]; - if (name[0] == '\01' && - UnDecorateSymbolName(name + 1, demangle_buffer, sizeof(demangle_buffer), - UNDNAME_NAME_ONLY)) - return demangle_buffer; - else - return name; -} - -const char *Symbolizer::PlatformDemangle(const char *name) { - return name; -} - -namespace { -struct ScopedHandle { - ScopedHandle() : h_(nullptr) {} - explicit ScopedHandle(HANDLE h) : h_(h) {} - ~ScopedHandle() { - if (h_) - ::CloseHandle(h_); - } - HANDLE get() { return h_; } - HANDLE *receive() { return &h_; } - HANDLE release() { - HANDLE h = h_; - h_ = nullptr; - return h; - } - HANDLE h_; -}; -} // namespace - -bool SymbolizerProcess::StartSymbolizerSubprocess() { - // Create inherited pipes for stdin and stdout. - ScopedHandle stdin_read, stdin_write; - ScopedHandle stdout_read, stdout_write; - SECURITY_ATTRIBUTES attrs; - attrs.nLength = sizeof(SECURITY_ATTRIBUTES); - attrs.bInheritHandle = TRUE; - attrs.lpSecurityDescriptor = nullptr; - if (!::CreatePipe(stdin_read.receive(), stdin_write.receive(), &attrs, 0) || - !::CreatePipe(stdout_read.receive(), stdout_write.receive(), &attrs, 0)) { - VReport(2, "WARNING: %s CreatePipe failed (error code: %d)\n", - SanitizerToolName, path_, GetLastError()); - return false; - } - - // Don't inherit the writing end of stdin or the reading end of stdout. - if (!SetHandleInformation(stdin_write.get(), HANDLE_FLAG_INHERIT, 0) || - !SetHandleInformation(stdout_read.get(), HANDLE_FLAG_INHERIT, 0)) { - VReport(2, "WARNING: %s SetHandleInformation failed (error code: %d)\n", - SanitizerToolName, path_, GetLastError()); - return false; - } - - // Compute the command line. Wrap double quotes around everything. - const char *argv[kArgVMax]; - GetArgV(path_, argv); - InternalScopedString command_line(kMaxPathLength * 3); - for (int i = 0; argv[i]; i++) { - const char *arg = argv[i]; - int arglen = internal_strlen(arg); - // Check that tool command lines are simple and that complete escaping is - // unnecessary. - CHECK(!internal_strchr(arg, '"') && "quotes in args unsupported"); - CHECK(!internal_strstr(arg, "\\\\") && - "double backslashes in args unsupported"); - CHECK(arglen > 0 && arg[arglen - 1] != '\\' && - "args ending in backslash and empty args unsupported"); - command_line.append("\"%s\" ", arg); - } - VReport(3, "Launching symbolizer command: %s\n", command_line.data()); - - // Launch llvm-symbolizer with stdin and stdout redirected. - STARTUPINFOA si; - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - si.dwFlags |= STARTF_USESTDHANDLES; - si.hStdInput = stdin_read.get(); - si.hStdOutput = stdout_write.get(); - PROCESS_INFORMATION pi; - memset(&pi, 0, sizeof(pi)); - if (!CreateProcessA(path_, // Executable - command_line.data(), // Command line - nullptr, // Process handle not inheritable - nullptr, // Thread handle not inheritable - TRUE, // Set handle inheritance to TRUE - 0, // Creation flags - nullptr, // Use parent's environment block - nullptr, // Use parent's starting directory - &si, &pi)) { - VReport(2, "WARNING: %s failed to create process for %s (error code: %d)\n", - SanitizerToolName, path_, GetLastError()); - return false; - } - - // Process creation succeeded, so transfer handle ownership into the fields. - input_fd_ = stdout_read.release(); - output_fd_ = stdin_write.release(); - - // The llvm-symbolizer process is responsible for quitting itself when the - // stdin pipe is closed, so we don't need these handles. Close them to prevent - // leaks. If we ever want to try to kill the symbolizer process from the - // parent, we'll want to hang on to these handles. - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - return true; -} - -static void ChooseSymbolizerTools(IntrusiveList *list, - LowLevelAllocator *allocator) { - if (!common_flags()->symbolize) { - VReport(2, "Symbolizer is disabled.\n"); - return; - } - - // Add llvm-symbolizer in case the binary has dwarf. - const char *user_path = common_flags()->external_symbolizer_path; - const char *path = - user_path ? user_path : FindPathToBinary("llvm-symbolizer.exe"); - if (path) { - VReport(2, "Using llvm-symbolizer at %spath: %s\n", - user_path ? "user-specified " : "", path); - list->push_back(new(*allocator) LLVMSymbolizer(path, allocator)); - } else { - if (user_path && user_path[0] == '\0') { - VReport(2, "External symbolizer is explicitly disabled.\n"); - } else { - VReport(2, "External symbolizer is not present.\n"); - } - } - - // Add the dbghelp based symbolizer. - list->push_back(new(*allocator) WinSymbolizerTool()); -} - -Symbolizer *Symbolizer::PlatformInit() { - IntrusiveList list; - list.clear(); - ChooseSymbolizerTools(&list, &symbolizer_allocator_); - - return new(symbolizer_allocator_) Symbolizer(list); -} - -void Symbolizer::LateInitialize() { - Symbolizer::GetOrInit(); -} - -} // namespace __sanitizer - -#endif // _WIN32 diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.cpp b/lib/sanitizer_common/sanitizer_symbolizer_win.cpp new file mode 100644 index 000000000000..2808779156ed --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_win.cpp @@ -0,0 +1,318 @@ +//===-- sanitizer_symbolizer_win.cpp --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +// Windows-specific implementation of symbolizer parts. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS + +#include "sanitizer_dbghelp.h" +#include "sanitizer_symbolizer_internal.h" + +namespace __sanitizer { + +decltype(::StackWalk64) *StackWalk64; +decltype(::SymCleanup) *SymCleanup; +decltype(::SymFromAddr) *SymFromAddr; +decltype(::SymFunctionTableAccess64) *SymFunctionTableAccess64; +decltype(::SymGetLineFromAddr64) *SymGetLineFromAddr64; +decltype(::SymGetModuleBase64) *SymGetModuleBase64; +decltype(::SymGetSearchPathW) *SymGetSearchPathW; +decltype(::SymInitialize) *SymInitialize; +decltype(::SymSetOptions) *SymSetOptions; +decltype(::SymSetSearchPathW) *SymSetSearchPathW; +decltype(::UnDecorateSymbolName) *UnDecorateSymbolName; + +namespace { + +class WinSymbolizerTool : public SymbolizerTool { + public: + // The constructor is provided to avoid synthesized memsets. + WinSymbolizerTool() {} + + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; + bool SymbolizeData(uptr addr, DataInfo *info) override { + return false; + } + const char *Demangle(const char *name) override; +}; + +bool is_dbghelp_initialized = false; + +bool TrySymInitialize() { + SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES); + return SymInitialize(GetCurrentProcess(), 0, TRUE); + // FIXME: We don't call SymCleanup() on exit yet - should we? +} + +} // namespace + +// Initializes DbgHelp library, if it's not yet initialized. Calls to this +// function should be synchronized with respect to other calls to DbgHelp API +// (e.g. from WinSymbolizerTool). +void InitializeDbgHelpIfNeeded() { + if (is_dbghelp_initialized) + return; + + HMODULE dbghelp = LoadLibraryA("dbghelp.dll"); + CHECK(dbghelp && "failed to load dbghelp.dll"); + +#define DBGHELP_IMPORT(name) \ + do { \ + name = \ + reinterpret_cast(GetProcAddress(dbghelp, #name)); \ + CHECK(name != nullptr); \ + } while (0) + DBGHELP_IMPORT(StackWalk64); + DBGHELP_IMPORT(SymCleanup); + DBGHELP_IMPORT(SymFromAddr); + DBGHELP_IMPORT(SymFunctionTableAccess64); + DBGHELP_IMPORT(SymGetLineFromAddr64); + DBGHELP_IMPORT(SymGetModuleBase64); + DBGHELP_IMPORT(SymGetSearchPathW); + DBGHELP_IMPORT(SymInitialize); + DBGHELP_IMPORT(SymSetOptions); + DBGHELP_IMPORT(SymSetSearchPathW); + DBGHELP_IMPORT(UnDecorateSymbolName); +#undef DBGHELP_IMPORT + + if (!TrySymInitialize()) { + // OK, maybe the client app has called SymInitialize already. + // That's a bit unfortunate for us as all the DbgHelp functions are + // single-threaded and we can't coordinate with the app. + // FIXME: Can we stop the other threads at this point? + // Anyways, we have to reconfigure stuff to make sure that SymInitialize + // has all the appropriate options set. + // Cross our fingers and reinitialize DbgHelp. + Report("*** WARNING: Failed to initialize DbgHelp! ***\n"); + Report("*** Most likely this means that the app is already ***\n"); + Report("*** using DbgHelp, possibly with incompatible flags. ***\n"); + Report("*** Due to technical reasons, symbolization might crash ***\n"); + Report("*** or produce wrong results. ***\n"); + SymCleanup(GetCurrentProcess()); + TrySymInitialize(); + } + is_dbghelp_initialized = true; + + // When an executable is run from a location different from the one where it + // was originally built, we may not see the nearby PDB files. + // To work around this, let's append the directory of the main module + // to the symbol search path. All the failures below are not fatal. + const size_t kSymPathSize = 2048; + static wchar_t path_buffer[kSymPathSize + 1 + MAX_PATH]; + if (!SymGetSearchPathW(GetCurrentProcess(), path_buffer, kSymPathSize)) { + Report("*** WARNING: Failed to SymGetSearchPathW ***\n"); + return; + } + size_t sz = wcslen(path_buffer); + if (sz) { + CHECK_EQ(0, wcscat_s(path_buffer, L";")); + sz++; + } + DWORD res = GetModuleFileNameW(NULL, path_buffer + sz, MAX_PATH); + if (res == 0 || res == MAX_PATH) { + Report("*** WARNING: Failed to getting the EXE directory ***\n"); + return; + } + // Write the zero character in place of the last backslash to get the + // directory of the main module at the end of path_buffer. + wchar_t *last_bslash = wcsrchr(path_buffer + sz, L'\\'); + CHECK_NE(last_bslash, 0); + *last_bslash = L'\0'; + if (!SymSetSearchPathW(GetCurrentProcess(), path_buffer)) { + Report("*** WARNING: Failed to SymSetSearchPathW\n"); + return; + } +} + +bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) { + InitializeDbgHelpIfNeeded(); + + // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)]; + PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; + DWORD64 offset = 0; + BOOL got_objname = SymFromAddr(GetCurrentProcess(), + (DWORD64)addr, &offset, symbol); + if (!got_objname) + return false; + + DWORD unused; + IMAGEHLP_LINE64 line_info; + line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)addr, + &unused, &line_info); + frame->info.function = internal_strdup(symbol->Name); + frame->info.function_offset = (uptr)offset; + if (got_fileline) { + frame->info.file = internal_strdup(line_info.FileName); + frame->info.line = line_info.LineNumber; + } + // Only consider this a successful symbolization attempt if we got file info. + // Otherwise, try llvm-symbolizer. + return got_fileline; +} + +const char *WinSymbolizerTool::Demangle(const char *name) { + CHECK(is_dbghelp_initialized); + static char demangle_buffer[1000]; + if (name[0] == '\01' && + UnDecorateSymbolName(name + 1, demangle_buffer, sizeof(demangle_buffer), + UNDNAME_NAME_ONLY)) + return demangle_buffer; + else + return name; +} + +const char *Symbolizer::PlatformDemangle(const char *name) { + return name; +} + +namespace { +struct ScopedHandle { + ScopedHandle() : h_(nullptr) {} + explicit ScopedHandle(HANDLE h) : h_(h) {} + ~ScopedHandle() { + if (h_) + ::CloseHandle(h_); + } + HANDLE get() { return h_; } + HANDLE *receive() { return &h_; } + HANDLE release() { + HANDLE h = h_; + h_ = nullptr; + return h; + } + HANDLE h_; +}; +} // namespace + +bool SymbolizerProcess::StartSymbolizerSubprocess() { + // Create inherited pipes for stdin and stdout. + ScopedHandle stdin_read, stdin_write; + ScopedHandle stdout_read, stdout_write; + SECURITY_ATTRIBUTES attrs; + attrs.nLength = sizeof(SECURITY_ATTRIBUTES); + attrs.bInheritHandle = TRUE; + attrs.lpSecurityDescriptor = nullptr; + if (!::CreatePipe(stdin_read.receive(), stdin_write.receive(), &attrs, 0) || + !::CreatePipe(stdout_read.receive(), stdout_write.receive(), &attrs, 0)) { + VReport(2, "WARNING: %s CreatePipe failed (error code: %d)\n", + SanitizerToolName, path_, GetLastError()); + return false; + } + + // Don't inherit the writing end of stdin or the reading end of stdout. + if (!SetHandleInformation(stdin_write.get(), HANDLE_FLAG_INHERIT, 0) || + !SetHandleInformation(stdout_read.get(), HANDLE_FLAG_INHERIT, 0)) { + VReport(2, "WARNING: %s SetHandleInformation failed (error code: %d)\n", + SanitizerToolName, path_, GetLastError()); + return false; + } + + // Compute the command line. Wrap double quotes around everything. + const char *argv[kArgVMax]; + GetArgV(path_, argv); + InternalScopedString command_line(kMaxPathLength * 3); + for (int i = 0; argv[i]; i++) { + const char *arg = argv[i]; + int arglen = internal_strlen(arg); + // Check that tool command lines are simple and that complete escaping is + // unnecessary. + CHECK(!internal_strchr(arg, '"') && "quotes in args unsupported"); + CHECK(!internal_strstr(arg, "\\\\") && + "double backslashes in args unsupported"); + CHECK(arglen > 0 && arg[arglen - 1] != '\\' && + "args ending in backslash and empty args unsupported"); + command_line.append("\"%s\" ", arg); + } + VReport(3, "Launching symbolizer command: %s\n", command_line.data()); + + // Launch llvm-symbolizer with stdin and stdout redirected. + STARTUPINFOA si; + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags |= STARTF_USESTDHANDLES; + si.hStdInput = stdin_read.get(); + si.hStdOutput = stdout_write.get(); + PROCESS_INFORMATION pi; + memset(&pi, 0, sizeof(pi)); + if (!CreateProcessA(path_, // Executable + command_line.data(), // Command line + nullptr, // Process handle not inheritable + nullptr, // Thread handle not inheritable + TRUE, // Set handle inheritance to TRUE + 0, // Creation flags + nullptr, // Use parent's environment block + nullptr, // Use parent's starting directory + &si, &pi)) { + VReport(2, "WARNING: %s failed to create process for %s (error code: %d)\n", + SanitizerToolName, path_, GetLastError()); + return false; + } + + // Process creation succeeded, so transfer handle ownership into the fields. + input_fd_ = stdout_read.release(); + output_fd_ = stdin_write.release(); + + // The llvm-symbolizer process is responsible for quitting itself when the + // stdin pipe is closed, so we don't need these handles. Close them to prevent + // leaks. If we ever want to try to kill the symbolizer process from the + // parent, we'll want to hang on to these handles. + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return true; +} + +static void ChooseSymbolizerTools(IntrusiveList *list, + LowLevelAllocator *allocator) { + if (!common_flags()->symbolize) { + VReport(2, "Symbolizer is disabled.\n"); + return; + } + + // Add llvm-symbolizer in case the binary has dwarf. + const char *user_path = common_flags()->external_symbolizer_path; + const char *path = + user_path ? user_path : FindPathToBinary("llvm-symbolizer.exe"); + if (path) { + VReport(2, "Using llvm-symbolizer at %spath: %s\n", + user_path ? "user-specified " : "", path); + list->push_back(new(*allocator) LLVMSymbolizer(path, allocator)); + } else { + if (user_path && user_path[0] == '\0') { + VReport(2, "External symbolizer is explicitly disabled.\n"); + } else { + VReport(2, "External symbolizer is not present.\n"); + } + } + + // Add the dbghelp based symbolizer. + list->push_back(new(*allocator) WinSymbolizerTool()); +} + +Symbolizer *Symbolizer::PlatformInit() { + IntrusiveList list; + list.clear(); + ChooseSymbolizerTools(&list, &symbolizer_allocator_); + + return new(symbolizer_allocator_) Symbolizer(list); +} + +void Symbolizer::LateInitialize() { + Symbolizer::GetOrInit(); +} + +} // namespace __sanitizer + +#endif // _WIN32 diff --git a/lib/sanitizer_common/sanitizer_termination.cc b/lib/sanitizer_common/sanitizer_termination.cc deleted file mode 100644 index a011cce42aa2..000000000000 --- a/lib/sanitizer_common/sanitizer_termination.cc +++ /dev/null @@ -1,94 +0,0 @@ -//===-- sanitizer_termination.cc --------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// This file contains the Sanitizer termination functions CheckFailed and Die, -/// and the callback functionalities associated with them. -/// -//===----------------------------------------------------------------------===// - -#include "sanitizer_common.h" -#include "sanitizer_libc.h" - -namespace __sanitizer { - -static const int kMaxNumOfInternalDieCallbacks = 5; -static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks]; - -bool AddDieCallback(DieCallbackType callback) { - for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) { - if (InternalDieCallbacks[i] == nullptr) { - InternalDieCallbacks[i] = callback; - return true; - } - } - return false; -} - -bool RemoveDieCallback(DieCallbackType callback) { - for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) { - if (InternalDieCallbacks[i] == callback) { - internal_memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1], - sizeof(InternalDieCallbacks[0]) * - (kMaxNumOfInternalDieCallbacks - i - 1)); - InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr; - return true; - } - } - return false; -} - -static DieCallbackType UserDieCallback; -void SetUserDieCallback(DieCallbackType callback) { - UserDieCallback = callback; -} - -void NORETURN Die() { - if (UserDieCallback) - UserDieCallback(); - for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) { - if (InternalDieCallbacks[i]) - InternalDieCallbacks[i](); - } - if (common_flags()->abort_on_error) - Abort(); - internal__exit(common_flags()->exitcode); -} - -static CheckFailedCallbackType CheckFailedCallback; -void SetCheckFailedCallback(CheckFailedCallbackType callback) { - CheckFailedCallback = callback; -} - -const int kSecondsToSleepWhenRecursiveCheckFailed = 2; - -void NORETURN CheckFailed(const char *file, int line, const char *cond, - u64 v1, u64 v2) { - static atomic_uint32_t num_calls; - if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) > 10) { - SleepForSeconds(kSecondsToSleepWhenRecursiveCheckFailed); - Trap(); - } - - if (CheckFailedCallback) { - CheckFailedCallback(file, line, cond, v1, v2); - } - Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond, - v1, v2); - Die(); -} - -} // namespace __sanitizer - -using namespace __sanitizer; // NOLINT - -extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_set_death_callback(void (*callback)(void)) { - SetUserDieCallback(callback); -} -} // extern "C" diff --git a/lib/sanitizer_common/sanitizer_termination.cpp b/lib/sanitizer_common/sanitizer_termination.cpp new file mode 100644 index 000000000000..84be6fc32342 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_termination.cpp @@ -0,0 +1,94 @@ +//===-- sanitizer_termination.cpp -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// This file contains the Sanitizer termination functions CheckFailed and Die, +/// and the callback functionalities associated with them. +/// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common.h" +#include "sanitizer_libc.h" + +namespace __sanitizer { + +static const int kMaxNumOfInternalDieCallbacks = 5; +static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks]; + +bool AddDieCallback(DieCallbackType callback) { + for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) { + if (InternalDieCallbacks[i] == nullptr) { + InternalDieCallbacks[i] = callback; + return true; + } + } + return false; +} + +bool RemoveDieCallback(DieCallbackType callback) { + for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) { + if (InternalDieCallbacks[i] == callback) { + internal_memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1], + sizeof(InternalDieCallbacks[0]) * + (kMaxNumOfInternalDieCallbacks - i - 1)); + InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr; + return true; + } + } + return false; +} + +static DieCallbackType UserDieCallback; +void SetUserDieCallback(DieCallbackType callback) { + UserDieCallback = callback; +} + +void NORETURN Die() { + if (UserDieCallback) + UserDieCallback(); + for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) { + if (InternalDieCallbacks[i]) + InternalDieCallbacks[i](); + } + if (common_flags()->abort_on_error) + Abort(); + internal__exit(common_flags()->exitcode); +} + +static CheckFailedCallbackType CheckFailedCallback; +void SetCheckFailedCallback(CheckFailedCallbackType callback) { + CheckFailedCallback = callback; +} + +const int kSecondsToSleepWhenRecursiveCheckFailed = 2; + +void NORETURN CheckFailed(const char *file, int line, const char *cond, + u64 v1, u64 v2) { + static atomic_uint32_t num_calls; + if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) > 10) { + SleepForSeconds(kSecondsToSleepWhenRecursiveCheckFailed); + Trap(); + } + + if (CheckFailedCallback) { + CheckFailedCallback(file, line, cond, v1, v2); + } + Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond, + v1, v2); + Die(); +} + +} // namespace __sanitizer + +using namespace __sanitizer; + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_set_death_callback(void (*callback)(void)) { + SetUserDieCallback(callback); +} +} // extern "C" diff --git a/lib/sanitizer_common/sanitizer_thread_registry.cc b/lib/sanitizer_common/sanitizer_thread_registry.cc deleted file mode 100644 index 02691287d763..000000000000 --- a/lib/sanitizer_common/sanitizer_thread_registry.cc +++ /dev/null @@ -1,351 +0,0 @@ -//===-- sanitizer_thread_registry.cc --------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between sanitizer tools. -// -// General thread bookkeeping functionality. -//===----------------------------------------------------------------------===// - -#include "sanitizer_thread_registry.h" - -namespace __sanitizer { - -ThreadContextBase::ThreadContextBase(u32 tid) - : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0), - status(ThreadStatusInvalid), detached(false), - thread_type(ThreadType::Regular), parent_tid(0), next(0) { - name[0] = '\0'; - atomic_store(&thread_destroyed, 0, memory_order_release); -} - -ThreadContextBase::~ThreadContextBase() { - // ThreadContextBase should never be deleted. - CHECK(0); -} - -void ThreadContextBase::SetName(const char *new_name) { - name[0] = '\0'; - if (new_name) { - internal_strncpy(name, new_name, sizeof(name)); - name[sizeof(name) - 1] = '\0'; - } -} - -void ThreadContextBase::SetDead() { - CHECK(status == ThreadStatusRunning || - status == ThreadStatusFinished); - status = ThreadStatusDead; - user_id = 0; - OnDead(); -} - -void ThreadContextBase::SetDestroyed() { - atomic_store(&thread_destroyed, 1, memory_order_release); -} - -bool ThreadContextBase::GetDestroyed() { - return !!atomic_load(&thread_destroyed, memory_order_acquire); -} - -void ThreadContextBase::SetJoined(void *arg) { - // FIXME(dvyukov): print message and continue (it's user error). - CHECK_EQ(false, detached); - CHECK_EQ(ThreadStatusFinished, status); - status = ThreadStatusDead; - user_id = 0; - OnJoined(arg); -} - -void ThreadContextBase::SetFinished() { - // ThreadRegistry::FinishThread calls here in ThreadStatusCreated state - // for a thread that never actually started. In that case the thread - // should go to ThreadStatusFinished regardless of whether it was created - // as detached. - if (!detached || status == ThreadStatusCreated) status = ThreadStatusFinished; - OnFinished(); -} - -void ThreadContextBase::SetStarted(tid_t _os_id, ThreadType _thread_type, - void *arg) { - status = ThreadStatusRunning; - os_id = _os_id; - thread_type = _thread_type; - OnStarted(arg); -} - -void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id, - bool _detached, u32 _parent_tid, void *arg) { - status = ThreadStatusCreated; - user_id = _user_id; - unique_id = _unique_id; - detached = _detached; - // Parent tid makes no sense for the main thread. - if (tid != 0) - parent_tid = _parent_tid; - OnCreated(arg); -} - -void ThreadContextBase::Reset() { - status = ThreadStatusInvalid; - SetName(0); - atomic_store(&thread_destroyed, 0, memory_order_release); - OnReset(); -} - -// ThreadRegistry implementation. - -const u32 ThreadRegistry::kUnknownTid = ~0U; - -ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads, - u32 thread_quarantine_size, u32 max_reuse) - : context_factory_(factory), - max_threads_(max_threads), - thread_quarantine_size_(thread_quarantine_size), - max_reuse_(max_reuse), - mtx_(), - n_contexts_(0), - total_threads_(0), - alive_threads_(0), - max_alive_threads_(0), - running_threads_(0) { - threads_ = (ThreadContextBase **)MmapOrDie(max_threads_ * sizeof(threads_[0]), - "ThreadRegistry"); - dead_threads_.clear(); - invalid_threads_.clear(); -} - -void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running, - uptr *alive) { - BlockingMutexLock l(&mtx_); - if (total) *total = n_contexts_; - if (running) *running = running_threads_; - if (alive) *alive = alive_threads_; -} - -uptr ThreadRegistry::GetMaxAliveThreads() { - BlockingMutexLock l(&mtx_); - return max_alive_threads_; -} - -u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid, - void *arg) { - BlockingMutexLock l(&mtx_); - u32 tid = kUnknownTid; - ThreadContextBase *tctx = QuarantinePop(); - if (tctx) { - tid = tctx->tid; - } else if (n_contexts_ < max_threads_) { - // Allocate new thread context and tid. - tid = n_contexts_++; - tctx = context_factory_(tid); - threads_[tid] = tctx; - } else { -#if !SANITIZER_GO - Report("%s: Thread limit (%u threads) exceeded. Dying.\n", - SanitizerToolName, max_threads_); -#else - Printf("race: limit on %u simultaneously alive goroutines is exceeded," - " dying\n", max_threads_); -#endif - Die(); - } - CHECK_NE(tctx, 0); - CHECK_NE(tid, kUnknownTid); - CHECK_LT(tid, max_threads_); - CHECK_EQ(tctx->status, ThreadStatusInvalid); - alive_threads_++; - if (max_alive_threads_ < alive_threads_) { - max_alive_threads_++; - CHECK_EQ(alive_threads_, max_alive_threads_); - } - tctx->SetCreated(user_id, total_threads_++, detached, - parent_tid, arg); - return tid; -} - -void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb, - void *arg) { - CheckLocked(); - for (u32 tid = 0; tid < n_contexts_; tid++) { - ThreadContextBase *tctx = threads_[tid]; - if (tctx == 0) - continue; - cb(tctx, arg); - } -} - -u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) { - BlockingMutexLock l(&mtx_); - for (u32 tid = 0; tid < n_contexts_; tid++) { - ThreadContextBase *tctx = threads_[tid]; - if (tctx != 0 && cb(tctx, arg)) - return tctx->tid; - } - return kUnknownTid; -} - -ThreadContextBase * -ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) { - CheckLocked(); - for (u32 tid = 0; tid < n_contexts_; tid++) { - ThreadContextBase *tctx = threads_[tid]; - if (tctx != 0 && cb(tctx, arg)) - return tctx; - } - return 0; -} - -static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx, - void *arg) { - return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid && - tctx->status != ThreadStatusDead); -} - -ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id) { - return FindThreadContextLocked(FindThreadContextByOsIdCallback, - (void *)os_id); -} - -void ThreadRegistry::SetThreadName(u32 tid, const char *name) { - BlockingMutexLock l(&mtx_); - CHECK_LT(tid, n_contexts_); - ThreadContextBase *tctx = threads_[tid]; - CHECK_NE(tctx, 0); - CHECK_EQ(SANITIZER_FUCHSIA ? ThreadStatusCreated : ThreadStatusRunning, - tctx->status); - tctx->SetName(name); -} - -void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) { - BlockingMutexLock l(&mtx_); - for (u32 tid = 0; tid < n_contexts_; tid++) { - ThreadContextBase *tctx = threads_[tid]; - if (tctx != 0 && tctx->user_id == user_id && - tctx->status != ThreadStatusInvalid) { - tctx->SetName(name); - return; - } - } -} - -void ThreadRegistry::DetachThread(u32 tid, void *arg) { - BlockingMutexLock l(&mtx_); - CHECK_LT(tid, n_contexts_); - ThreadContextBase *tctx = threads_[tid]; - CHECK_NE(tctx, 0); - if (tctx->status == ThreadStatusInvalid) { - Report("%s: Detach of non-existent thread\n", SanitizerToolName); - return; - } - tctx->OnDetached(arg); - if (tctx->status == ThreadStatusFinished) { - tctx->SetDead(); - QuarantinePush(tctx); - } else { - tctx->detached = true; - } -} - -void ThreadRegistry::JoinThread(u32 tid, void *arg) { - bool destroyed = false; - do { - { - BlockingMutexLock l(&mtx_); - CHECK_LT(tid, n_contexts_); - ThreadContextBase *tctx = threads_[tid]; - CHECK_NE(tctx, 0); - if (tctx->status == ThreadStatusInvalid) { - Report("%s: Join of non-existent thread\n", SanitizerToolName); - return; - } - if ((destroyed = tctx->GetDestroyed())) { - tctx->SetJoined(arg); - QuarantinePush(tctx); - } - } - if (!destroyed) - internal_sched_yield(); - } while (!destroyed); -} - -// Normally this is called when the thread is about to exit. If -// called in ThreadStatusCreated state, then this thread was never -// really started. We just did CreateThread for a prospective new -// thread before trying to create it, and then failed to actually -// create it, and so never called StartThread. -void ThreadRegistry::FinishThread(u32 tid) { - BlockingMutexLock l(&mtx_); - CHECK_GT(alive_threads_, 0); - alive_threads_--; - CHECK_LT(tid, n_contexts_); - ThreadContextBase *tctx = threads_[tid]; - CHECK_NE(tctx, 0); - bool dead = tctx->detached; - if (tctx->status == ThreadStatusRunning) { - CHECK_GT(running_threads_, 0); - running_threads_--; - } else { - // The thread never really existed. - CHECK_EQ(tctx->status, ThreadStatusCreated); - dead = true; - } - tctx->SetFinished(); - if (dead) { - tctx->SetDead(); - QuarantinePush(tctx); - } - tctx->SetDestroyed(); -} - -void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type, - void *arg) { - BlockingMutexLock l(&mtx_); - running_threads_++; - CHECK_LT(tid, n_contexts_); - ThreadContextBase *tctx = threads_[tid]; - CHECK_NE(tctx, 0); - CHECK_EQ(ThreadStatusCreated, tctx->status); - tctx->SetStarted(os_id, thread_type, arg); -} - -void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) { - if (tctx->tid == 0) - return; // Don't reuse the main thread. It's a special snowflake. - dead_threads_.push_back(tctx); - if (dead_threads_.size() <= thread_quarantine_size_) - return; - tctx = dead_threads_.front(); - dead_threads_.pop_front(); - CHECK_EQ(tctx->status, ThreadStatusDead); - tctx->Reset(); - tctx->reuse_count++; - if (max_reuse_ > 0 && tctx->reuse_count >= max_reuse_) - return; - invalid_threads_.push_back(tctx); -} - -ThreadContextBase *ThreadRegistry::QuarantinePop() { - if (invalid_threads_.size() == 0) - return 0; - ThreadContextBase *tctx = invalid_threads_.front(); - invalid_threads_.pop_front(); - return tctx; -} - -void ThreadRegistry::SetThreadUserId(u32 tid, uptr user_id) { - BlockingMutexLock l(&mtx_); - CHECK_LT(tid, n_contexts_); - ThreadContextBase *tctx = threads_[tid]; - CHECK_NE(tctx, 0); - CHECK_NE(tctx->status, ThreadStatusInvalid); - CHECK_NE(tctx->status, ThreadStatusDead); - CHECK_EQ(tctx->user_id, 0); - tctx->user_id = user_id; -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_thread_registry.cpp b/lib/sanitizer_common/sanitizer_thread_registry.cpp new file mode 100644 index 000000000000..f2c6f2799315 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_thread_registry.cpp @@ -0,0 +1,351 @@ +//===-- sanitizer_thread_registry.cpp -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between sanitizer tools. +// +// General thread bookkeeping functionality. +//===----------------------------------------------------------------------===// + +#include "sanitizer_thread_registry.h" + +namespace __sanitizer { + +ThreadContextBase::ThreadContextBase(u32 tid) + : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0), + status(ThreadStatusInvalid), detached(false), + thread_type(ThreadType::Regular), parent_tid(0), next(0) { + name[0] = '\0'; + atomic_store(&thread_destroyed, 0, memory_order_release); +} + +ThreadContextBase::~ThreadContextBase() { + // ThreadContextBase should never be deleted. + CHECK(0); +} + +void ThreadContextBase::SetName(const char *new_name) { + name[0] = '\0'; + if (new_name) { + internal_strncpy(name, new_name, sizeof(name)); + name[sizeof(name) - 1] = '\0'; + } +} + +void ThreadContextBase::SetDead() { + CHECK(status == ThreadStatusRunning || + status == ThreadStatusFinished); + status = ThreadStatusDead; + user_id = 0; + OnDead(); +} + +void ThreadContextBase::SetDestroyed() { + atomic_store(&thread_destroyed, 1, memory_order_release); +} + +bool ThreadContextBase::GetDestroyed() { + return !!atomic_load(&thread_destroyed, memory_order_acquire); +} + +void ThreadContextBase::SetJoined(void *arg) { + // FIXME(dvyukov): print message and continue (it's user error). + CHECK_EQ(false, detached); + CHECK_EQ(ThreadStatusFinished, status); + status = ThreadStatusDead; + user_id = 0; + OnJoined(arg); +} + +void ThreadContextBase::SetFinished() { + // ThreadRegistry::FinishThread calls here in ThreadStatusCreated state + // for a thread that never actually started. In that case the thread + // should go to ThreadStatusFinished regardless of whether it was created + // as detached. + if (!detached || status == ThreadStatusCreated) status = ThreadStatusFinished; + OnFinished(); +} + +void ThreadContextBase::SetStarted(tid_t _os_id, ThreadType _thread_type, + void *arg) { + status = ThreadStatusRunning; + os_id = _os_id; + thread_type = _thread_type; + OnStarted(arg); +} + +void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id, + bool _detached, u32 _parent_tid, void *arg) { + status = ThreadStatusCreated; + user_id = _user_id; + unique_id = _unique_id; + detached = _detached; + // Parent tid makes no sense for the main thread. + if (tid != 0) + parent_tid = _parent_tid; + OnCreated(arg); +} + +void ThreadContextBase::Reset() { + status = ThreadStatusInvalid; + SetName(0); + atomic_store(&thread_destroyed, 0, memory_order_release); + OnReset(); +} + +// ThreadRegistry implementation. + +const u32 ThreadRegistry::kUnknownTid = ~0U; + +ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads, + u32 thread_quarantine_size, u32 max_reuse) + : context_factory_(factory), + max_threads_(max_threads), + thread_quarantine_size_(thread_quarantine_size), + max_reuse_(max_reuse), + mtx_(), + n_contexts_(0), + total_threads_(0), + alive_threads_(0), + max_alive_threads_(0), + running_threads_(0) { + threads_ = (ThreadContextBase **)MmapOrDie(max_threads_ * sizeof(threads_[0]), + "ThreadRegistry"); + dead_threads_.clear(); + invalid_threads_.clear(); +} + +void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running, + uptr *alive) { + BlockingMutexLock l(&mtx_); + if (total) *total = n_contexts_; + if (running) *running = running_threads_; + if (alive) *alive = alive_threads_; +} + +uptr ThreadRegistry::GetMaxAliveThreads() { + BlockingMutexLock l(&mtx_); + return max_alive_threads_; +} + +u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid, + void *arg) { + BlockingMutexLock l(&mtx_); + u32 tid = kUnknownTid; + ThreadContextBase *tctx = QuarantinePop(); + if (tctx) { + tid = tctx->tid; + } else if (n_contexts_ < max_threads_) { + // Allocate new thread context and tid. + tid = n_contexts_++; + tctx = context_factory_(tid); + threads_[tid] = tctx; + } else { +#if !SANITIZER_GO + Report("%s: Thread limit (%u threads) exceeded. Dying.\n", + SanitizerToolName, max_threads_); +#else + Printf("race: limit on %u simultaneously alive goroutines is exceeded," + " dying\n", max_threads_); +#endif + Die(); + } + CHECK_NE(tctx, 0); + CHECK_NE(tid, kUnknownTid); + CHECK_LT(tid, max_threads_); + CHECK_EQ(tctx->status, ThreadStatusInvalid); + alive_threads_++; + if (max_alive_threads_ < alive_threads_) { + max_alive_threads_++; + CHECK_EQ(alive_threads_, max_alive_threads_); + } + tctx->SetCreated(user_id, total_threads_++, detached, + parent_tid, arg); + return tid; +} + +void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb, + void *arg) { + CheckLocked(); + for (u32 tid = 0; tid < n_contexts_; tid++) { + ThreadContextBase *tctx = threads_[tid]; + if (tctx == 0) + continue; + cb(tctx, arg); + } +} + +u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) { + BlockingMutexLock l(&mtx_); + for (u32 tid = 0; tid < n_contexts_; tid++) { + ThreadContextBase *tctx = threads_[tid]; + if (tctx != 0 && cb(tctx, arg)) + return tctx->tid; + } + return kUnknownTid; +} + +ThreadContextBase * +ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) { + CheckLocked(); + for (u32 tid = 0; tid < n_contexts_; tid++) { + ThreadContextBase *tctx = threads_[tid]; + if (tctx != 0 && cb(tctx, arg)) + return tctx; + } + return 0; +} + +static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx, + void *arg) { + return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid && + tctx->status != ThreadStatusDead); +} + +ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id) { + return FindThreadContextLocked(FindThreadContextByOsIdCallback, + (void *)os_id); +} + +void ThreadRegistry::SetThreadName(u32 tid, const char *name) { + BlockingMutexLock l(&mtx_); + CHECK_LT(tid, n_contexts_); + ThreadContextBase *tctx = threads_[tid]; + CHECK_NE(tctx, 0); + CHECK_EQ(SANITIZER_FUCHSIA ? ThreadStatusCreated : ThreadStatusRunning, + tctx->status); + tctx->SetName(name); +} + +void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) { + BlockingMutexLock l(&mtx_); + for (u32 tid = 0; tid < n_contexts_; tid++) { + ThreadContextBase *tctx = threads_[tid]; + if (tctx != 0 && tctx->user_id == user_id && + tctx->status != ThreadStatusInvalid) { + tctx->SetName(name); + return; + } + } +} + +void ThreadRegistry::DetachThread(u32 tid, void *arg) { + BlockingMutexLock l(&mtx_); + CHECK_LT(tid, n_contexts_); + ThreadContextBase *tctx = threads_[tid]; + CHECK_NE(tctx, 0); + if (tctx->status == ThreadStatusInvalid) { + Report("%s: Detach of non-existent thread\n", SanitizerToolName); + return; + } + tctx->OnDetached(arg); + if (tctx->status == ThreadStatusFinished) { + tctx->SetDead(); + QuarantinePush(tctx); + } else { + tctx->detached = true; + } +} + +void ThreadRegistry::JoinThread(u32 tid, void *arg) { + bool destroyed = false; + do { + { + BlockingMutexLock l(&mtx_); + CHECK_LT(tid, n_contexts_); + ThreadContextBase *tctx = threads_[tid]; + CHECK_NE(tctx, 0); + if (tctx->status == ThreadStatusInvalid) { + Report("%s: Join of non-existent thread\n", SanitizerToolName); + return; + } + if ((destroyed = tctx->GetDestroyed())) { + tctx->SetJoined(arg); + QuarantinePush(tctx); + } + } + if (!destroyed) + internal_sched_yield(); + } while (!destroyed); +} + +// Normally this is called when the thread is about to exit. If +// called in ThreadStatusCreated state, then this thread was never +// really started. We just did CreateThread for a prospective new +// thread before trying to create it, and then failed to actually +// create it, and so never called StartThread. +void ThreadRegistry::FinishThread(u32 tid) { + BlockingMutexLock l(&mtx_); + CHECK_GT(alive_threads_, 0); + alive_threads_--; + CHECK_LT(tid, n_contexts_); + ThreadContextBase *tctx = threads_[tid]; + CHECK_NE(tctx, 0); + bool dead = tctx->detached; + if (tctx->status == ThreadStatusRunning) { + CHECK_GT(running_threads_, 0); + running_threads_--; + } else { + // The thread never really existed. + CHECK_EQ(tctx->status, ThreadStatusCreated); + dead = true; + } + tctx->SetFinished(); + if (dead) { + tctx->SetDead(); + QuarantinePush(tctx); + } + tctx->SetDestroyed(); +} + +void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type, + void *arg) { + BlockingMutexLock l(&mtx_); + running_threads_++; + CHECK_LT(tid, n_contexts_); + ThreadContextBase *tctx = threads_[tid]; + CHECK_NE(tctx, 0); + CHECK_EQ(ThreadStatusCreated, tctx->status); + tctx->SetStarted(os_id, thread_type, arg); +} + +void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) { + if (tctx->tid == 0) + return; // Don't reuse the main thread. It's a special snowflake. + dead_threads_.push_back(tctx); + if (dead_threads_.size() <= thread_quarantine_size_) + return; + tctx = dead_threads_.front(); + dead_threads_.pop_front(); + CHECK_EQ(tctx->status, ThreadStatusDead); + tctx->Reset(); + tctx->reuse_count++; + if (max_reuse_ > 0 && tctx->reuse_count >= max_reuse_) + return; + invalid_threads_.push_back(tctx); +} + +ThreadContextBase *ThreadRegistry::QuarantinePop() { + if (invalid_threads_.size() == 0) + return 0; + ThreadContextBase *tctx = invalid_threads_.front(); + invalid_threads_.pop_front(); + return tctx; +} + +void ThreadRegistry::SetThreadUserId(u32 tid, uptr user_id) { + BlockingMutexLock l(&mtx_); + CHECK_LT(tid, n_contexts_); + ThreadContextBase *tctx = threads_[tid]; + CHECK_NE(tctx, 0); + CHECK_NE(tctx->status, ThreadStatusInvalid); + CHECK_NE(tctx->status, ThreadStatusDead); + CHECK_EQ(tctx->user_id, 0); + tctx->user_id = user_id; +} + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_tls_get_addr.cc b/lib/sanitizer_common/sanitizer_tls_get_addr.cc deleted file mode 100644 index 5e33e2a514f4..000000000000 --- a/lib/sanitizer_common/sanitizer_tls_get_addr.cc +++ /dev/null @@ -1,154 +0,0 @@ -//===-- sanitizer_tls_get_addr.cc -----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Handle the __tls_get_addr call. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_tls_get_addr.h" - -#include "sanitizer_flags.h" -#include "sanitizer_platform_interceptors.h" - -namespace __sanitizer { -#if SANITIZER_INTERCEPT_TLS_GET_ADDR - -// The actual parameter that comes to __tls_get_addr -// is a pointer to a struct with two words in it: -struct TlsGetAddrParam { - uptr dso_id; - uptr offset; -}; - -// Glibc starting from 2.19 allocates tls using __signal_safe_memalign, -// which has such header. -struct Glibc_2_19_tls_header { - uptr size; - uptr start; -}; - -// This must be static TLS -__attribute__((tls_model("initial-exec"))) -static __thread DTLS dtls; - -// Make sure we properly destroy the DTLS objects: -// this counter should never get too large. -static atomic_uintptr_t number_of_live_dtls; - -static const uptr kDestroyedThread = -1; - -static inline void DTLS_Deallocate(DTLS::DTV *dtv, uptr size) { - if (!size) return; - VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size); - UnmapOrDie(dtv, size * sizeof(DTLS::DTV)); - atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed); -} - -static inline void DTLS_Resize(uptr new_size) { - if (dtls.dtv_size >= new_size) return; - new_size = RoundUpToPowerOfTwo(new_size); - new_size = Max(new_size, 4096UL / sizeof(DTLS::DTV)); - DTLS::DTV *new_dtv = - (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize"); - uptr num_live_dtls = - atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed); - VReport(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls); - CHECK_LT(num_live_dtls, 1 << 20); - uptr old_dtv_size = dtls.dtv_size; - DTLS::DTV *old_dtv = dtls.dtv; - if (old_dtv_size) - internal_memcpy(new_dtv, dtls.dtv, dtls.dtv_size * sizeof(DTLS::DTV)); - dtls.dtv = new_dtv; - dtls.dtv_size = new_size; - if (old_dtv_size) - DTLS_Deallocate(old_dtv, old_dtv_size); -} - -void DTLS_Destroy() { - if (!common_flags()->intercept_tls_get_addr) return; - VReport(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size); - uptr s = dtls.dtv_size; - dtls.dtv_size = kDestroyedThread; // Do this before unmap for AS-safety. - DTLS_Deallocate(dtls.dtv, s); -} - -#if defined(__powerpc64__) || defined(__mips__) -// This is glibc's TLS_DTV_OFFSET: -// "Dynamic thread vector pointers point 0x8000 past the start of each -// TLS block." -static const uptr kDtvOffset = 0x8000; -#else -static const uptr kDtvOffset = 0; -#endif - -DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res, - uptr static_tls_begin, uptr static_tls_end) { - if (!common_flags()->intercept_tls_get_addr) return 0; - TlsGetAddrParam *arg = reinterpret_cast(arg_void); - uptr dso_id = arg->dso_id; - if (dtls.dtv_size == kDestroyedThread) return 0; - DTLS_Resize(dso_id + 1); - if (dtls.dtv[dso_id].beg) return 0; - uptr tls_size = 0; - uptr tls_beg = reinterpret_cast(res) - arg->offset - kDtvOffset; - VReport(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p " - "num_live_dtls %zd\n", - arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg, - atomic_load(&number_of_live_dtls, memory_order_relaxed)); - if (dtls.last_memalign_ptr == tls_beg) { - tls_size = dtls.last_memalign_size; - VReport(2, "__tls_get_addr: glibc <=2.18 suspected; tls={%p,%p}\n", - tls_beg, tls_size); - } else if (tls_beg >= static_tls_begin && tls_beg < static_tls_end) { - // This is the static TLS block which was initialized / unpoisoned at thread - // creation. - VReport(2, "__tls_get_addr: static tls: %p\n", tls_beg); - tls_size = 0; - } else if ((tls_beg % 4096) == sizeof(Glibc_2_19_tls_header)) { - // We may want to check gnu_get_libc_version(). - Glibc_2_19_tls_header *header = (Glibc_2_19_tls_header *)tls_beg - 1; - tls_size = header->size; - tls_beg = header->start; - VReport(2, "__tls_get_addr: glibc >=2.19 suspected; tls={%p %p}\n", - tls_beg, tls_size); - } else { - VReport(2, "__tls_get_addr: Can't guess glibc version\n"); - // This may happen inside the DTOR of main thread, so just ignore it. - tls_size = 0; - } - dtls.dtv[dso_id].beg = tls_beg; - dtls.dtv[dso_id].size = tls_size; - return dtls.dtv + dso_id; -} - -void DTLS_on_libc_memalign(void *ptr, uptr size) { - if (!common_flags()->intercept_tls_get_addr) return; - VReport(2, "DTLS_on_libc_memalign: %p %p\n", ptr, size); - dtls.last_memalign_ptr = reinterpret_cast(ptr); - dtls.last_memalign_size = size; -} - -DTLS *DTLS_Get() { return &dtls; } - -bool DTLSInDestruction(DTLS *dtls) { - return dtls->dtv_size == kDestroyedThread; -} - -#else -void DTLS_on_libc_memalign(void *ptr, uptr size) {} -DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, - unsigned long, unsigned long) { return 0; } -DTLS *DTLS_Get() { return 0; } -void DTLS_Destroy() {} -bool DTLSInDestruction(DTLS *dtls) { - UNREACHABLE("dtls is unsupported on this platform!"); -} - -#endif // SANITIZER_INTERCEPT_TLS_GET_ADDR - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_tls_get_addr.cpp b/lib/sanitizer_common/sanitizer_tls_get_addr.cpp new file mode 100644 index 000000000000..9ca898a306a8 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_tls_get_addr.cpp @@ -0,0 +1,154 @@ +//===-- sanitizer_tls_get_addr.cpp ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Handle the __tls_get_addr call. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_tls_get_addr.h" + +#include "sanitizer_flags.h" +#include "sanitizer_platform_interceptors.h" + +namespace __sanitizer { +#if SANITIZER_INTERCEPT_TLS_GET_ADDR + +// The actual parameter that comes to __tls_get_addr +// is a pointer to a struct with two words in it: +struct TlsGetAddrParam { + uptr dso_id; + uptr offset; +}; + +// Glibc starting from 2.19 allocates tls using __signal_safe_memalign, +// which has such header. +struct Glibc_2_19_tls_header { + uptr size; + uptr start; +}; + +// This must be static TLS +__attribute__((tls_model("initial-exec"))) +static __thread DTLS dtls; + +// Make sure we properly destroy the DTLS objects: +// this counter should never get too large. +static atomic_uintptr_t number_of_live_dtls; + +static const uptr kDestroyedThread = -1; + +static inline void DTLS_Deallocate(DTLS::DTV *dtv, uptr size) { + if (!size) return; + VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size); + UnmapOrDie(dtv, size * sizeof(DTLS::DTV)); + atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed); +} + +static inline void DTLS_Resize(uptr new_size) { + if (dtls.dtv_size >= new_size) return; + new_size = RoundUpToPowerOfTwo(new_size); + new_size = Max(new_size, 4096UL / sizeof(DTLS::DTV)); + DTLS::DTV *new_dtv = + (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize"); + uptr num_live_dtls = + atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed); + VReport(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls); + CHECK_LT(num_live_dtls, 1 << 20); + uptr old_dtv_size = dtls.dtv_size; + DTLS::DTV *old_dtv = dtls.dtv; + if (old_dtv_size) + internal_memcpy(new_dtv, dtls.dtv, dtls.dtv_size * sizeof(DTLS::DTV)); + dtls.dtv = new_dtv; + dtls.dtv_size = new_size; + if (old_dtv_size) + DTLS_Deallocate(old_dtv, old_dtv_size); +} + +void DTLS_Destroy() { + if (!common_flags()->intercept_tls_get_addr) return; + VReport(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size); + uptr s = dtls.dtv_size; + dtls.dtv_size = kDestroyedThread; // Do this before unmap for AS-safety. + DTLS_Deallocate(dtls.dtv, s); +} + +#if defined(__powerpc64__) || defined(__mips__) +// This is glibc's TLS_DTV_OFFSET: +// "Dynamic thread vector pointers point 0x8000 past the start of each +// TLS block." +static const uptr kDtvOffset = 0x8000; +#else +static const uptr kDtvOffset = 0; +#endif + +DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res, + uptr static_tls_begin, uptr static_tls_end) { + if (!common_flags()->intercept_tls_get_addr) return 0; + TlsGetAddrParam *arg = reinterpret_cast(arg_void); + uptr dso_id = arg->dso_id; + if (dtls.dtv_size == kDestroyedThread) return 0; + DTLS_Resize(dso_id + 1); + if (dtls.dtv[dso_id].beg) return 0; + uptr tls_size = 0; + uptr tls_beg = reinterpret_cast(res) - arg->offset - kDtvOffset; + VReport(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p " + "num_live_dtls %zd\n", + arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg, + atomic_load(&number_of_live_dtls, memory_order_relaxed)); + if (dtls.last_memalign_ptr == tls_beg) { + tls_size = dtls.last_memalign_size; + VReport(2, "__tls_get_addr: glibc <=2.18 suspected; tls={%p,%p}\n", + tls_beg, tls_size); + } else if (tls_beg >= static_tls_begin && tls_beg < static_tls_end) { + // This is the static TLS block which was initialized / unpoisoned at thread + // creation. + VReport(2, "__tls_get_addr: static tls: %p\n", tls_beg); + tls_size = 0; + } else if ((tls_beg % 4096) == sizeof(Glibc_2_19_tls_header)) { + // We may want to check gnu_get_libc_version(). + Glibc_2_19_tls_header *header = (Glibc_2_19_tls_header *)tls_beg - 1; + tls_size = header->size; + tls_beg = header->start; + VReport(2, "__tls_get_addr: glibc >=2.19 suspected; tls={%p %p}\n", + tls_beg, tls_size); + } else { + VReport(2, "__tls_get_addr: Can't guess glibc version\n"); + // This may happen inside the DTOR of main thread, so just ignore it. + tls_size = 0; + } + dtls.dtv[dso_id].beg = tls_beg; + dtls.dtv[dso_id].size = tls_size; + return dtls.dtv + dso_id; +} + +void DTLS_on_libc_memalign(void *ptr, uptr size) { + if (!common_flags()->intercept_tls_get_addr) return; + VReport(2, "DTLS_on_libc_memalign: %p %p\n", ptr, size); + dtls.last_memalign_ptr = reinterpret_cast(ptr); + dtls.last_memalign_size = size; +} + +DTLS *DTLS_Get() { return &dtls; } + +bool DTLSInDestruction(DTLS *dtls) { + return dtls->dtv_size == kDestroyedThread; +} + +#else +void DTLS_on_libc_memalign(void *ptr, uptr size) {} +DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, + unsigned long, unsigned long) { return 0; } +DTLS *DTLS_Get() { return 0; } +void DTLS_Destroy() {} +bool DTLSInDestruction(DTLS *dtls) { + UNREACHABLE("dtls is unsupported on this platform!"); +} + +#endif // SANITIZER_INTERCEPT_TLS_GET_ADDR + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_tls_get_addr.h b/lib/sanitizer_common/sanitizer_tls_get_addr.h index cc178d3d15ae..c7cd5a8bffcf 100644 --- a/lib/sanitizer_common/sanitizer_tls_get_addr.h +++ b/lib/sanitizer_common/sanitizer_tls_get_addr.h @@ -42,7 +42,7 @@ struct DTLS { uptr dtv_size; DTV *dtv; // dtv_size elements, allocated by MmapOrDie. - // Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cc + // Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cpp uptr last_memalign_size; uptr last_memalign_ptr; }; diff --git a/lib/sanitizer_common/sanitizer_type_traits.cc b/lib/sanitizer_common/sanitizer_type_traits.cc deleted file mode 100644 index e3e431a13d44..000000000000 --- a/lib/sanitizer_common/sanitizer_type_traits.cc +++ /dev/null @@ -1,20 +0,0 @@ -//===-- sanitizer_type_traits.cc --------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Implements a subset of C++ type traits. This is so we can avoid depending -// on system C++ headers. -// -//===----------------------------------------------------------------------===// -#include "sanitizer_type_traits.h" - -namespace __sanitizer { - -const bool true_type::value; -const bool false_type::value; - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_type_traits.cpp b/lib/sanitizer_common/sanitizer_type_traits.cpp new file mode 100644 index 000000000000..5ee37d7376f9 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_type_traits.cpp @@ -0,0 +1,20 @@ +//===-- sanitizer_type_traits.cpp -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implements a subset of C++ type traits. This is so we can avoid depending +// on system C++ headers. +// +//===----------------------------------------------------------------------===// +#include "sanitizer_type_traits.h" + +namespace __sanitizer { + +const bool true_type::value; +const bool false_type::value; + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc deleted file mode 100644 index 30581e848594..000000000000 --- a/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc +++ /dev/null @@ -1,176 +0,0 @@ -//===-- sanitizer_unwind_linux_libcdep.cc ---------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file contains the unwind.h-based (aka "slow") stack unwinding routines -// available to the tools on Linux, Android, NetBSD, FreeBSD, and Solaris. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_SOLARIS -#include "sanitizer_common.h" -#include "sanitizer_stacktrace.h" - -#if SANITIZER_ANDROID -#include // for dlopen() -#endif - -#if SANITIZER_FREEBSD -#define _GNU_SOURCE // to declare _Unwind_Backtrace() from -#endif -#include - -namespace __sanitizer { - -//---------------------------- UnwindSlow -------------------------------------- - -typedef struct { - uptr absolute_pc; - uptr stack_top; - uptr stack_size; -} backtrace_frame_t; - -extern "C" { -typedef void *(*acquire_my_map_info_list_func)(); -typedef void (*release_my_map_info_list_func)(void *map); -typedef sptr (*unwind_backtrace_signal_arch_func)( - void *siginfo, void *sigcontext, void *map_info_list, - backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth); -acquire_my_map_info_list_func acquire_my_map_info_list; -release_my_map_info_list_func release_my_map_info_list; -unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch; -} // extern "C" - -#if SANITIZER_ANDROID -void SanitizerInitializeUnwinder() { - if (AndroidGetApiLevel() >= ANDROID_LOLLIPOP_MR1) return; - - // Pre-lollipop Android can not unwind through signal handler frames with - // libgcc unwinder, but it has a libcorkscrew.so library with the necessary - // workarounds. - void *p = dlopen("libcorkscrew.so", RTLD_LAZY); - if (!p) { - VReport(1, - "Failed to open libcorkscrew.so. You may see broken stack traces " - "in SEGV reports."); - return; - } - acquire_my_map_info_list = - (acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list"); - release_my_map_info_list = - (release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list"); - unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym( - p, "unwind_backtrace_signal_arch"); - if (!acquire_my_map_info_list || !release_my_map_info_list || - !unwind_backtrace_signal_arch) { - VReport(1, - "Failed to find one of the required symbols in libcorkscrew.so. " - "You may see broken stack traces in SEGV reports."); - acquire_my_map_info_list = 0; - unwind_backtrace_signal_arch = 0; - release_my_map_info_list = 0; - } -} -#endif - -#if defined(__arm__) && !SANITIZER_NETBSD -// NetBSD uses dwarf EH -#define UNWIND_STOP _URC_END_OF_STACK -#define UNWIND_CONTINUE _URC_NO_REASON -#else -#define UNWIND_STOP _URC_NORMAL_STOP -#define UNWIND_CONTINUE _URC_NO_REASON -#endif - -uptr Unwind_GetIP(struct _Unwind_Context *ctx) { -#if defined(__arm__) && !SANITIZER_MAC - uptr val; - _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE, - 15 /* r15 = PC */, _UVRSD_UINT32, &val); - CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed"); - // Clear the Thumb bit. - return val & ~(uptr)1; -#else - return (uptr)_Unwind_GetIP(ctx); -#endif -} - -struct UnwindTraceArg { - BufferedStackTrace *stack; - u32 max_depth; -}; - -_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { - UnwindTraceArg *arg = (UnwindTraceArg*)param; - CHECK_LT(arg->stack->size, arg->max_depth); - uptr pc = Unwind_GetIP(ctx); - const uptr kPageSize = GetPageSizeCached(); - // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and - // x86_64) is invalid and stop unwinding here. If we're adding support for - // a platform where this isn't true, we need to reconsider this check. - if (pc < kPageSize) return UNWIND_STOP; - arg->stack->trace_buffer[arg->stack->size++] = pc; - if (arg->stack->size == arg->max_depth) return UNWIND_STOP; - return UNWIND_CONTINUE; -} - -void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) { - CHECK_GE(max_depth, 2); - size = 0; - UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; - _Unwind_Backtrace(Unwind_Trace, &arg); - // We need to pop a few frames so that pc is on top. - uptr to_pop = LocatePcInTrace(pc); - // trace_buffer[0] belongs to the current function so we always pop it, - // unless there is only 1 frame in the stack trace (1 frame is always better - // than 0!). - // 1-frame stacks don't normally happen, but this depends on the actual - // unwinder implementation (libgcc, libunwind, etc) which is outside of our - // control. - if (to_pop == 0 && size > 1) - to_pop = 1; - PopStackFrames(to_pop); -#if defined(__GNUC__) && defined(__sparc__) - // __builtin_return_address returns the address of the call instruction - // on the SPARC and not the return address, so we need to compensate. - trace_buffer[0] = GetNextInstructionPc(pc); -#else - trace_buffer[0] = pc; -#endif -} - -void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) { - CHECK(context); - CHECK_GE(max_depth, 2); - if (!unwind_backtrace_signal_arch) { - UnwindSlow(pc, max_depth); - return; - } - - void *map = acquire_my_map_info_list(); - CHECK(map); - InternalMmapVector frames(kStackTraceMax); - // siginfo argument appears to be unused. - sptr res = unwind_backtrace_signal_arch(/* siginfo */ 0, context, map, - frames.data(), - /* ignore_depth */ 0, max_depth); - release_my_map_info_list(map); - if (res < 0) return; - CHECK_LE((uptr)res, kStackTraceMax); - - size = 0; - // +2 compensate for libcorkscrew unwinder returning addresses of call - // instructions instead of raw return addresses. - for (sptr i = 0; i < res; ++i) - trace_buffer[size++] = frames[i].absolute_pc + 2; -} - -} // namespace __sanitizer - -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || - // SANITIZER_SOLARIS diff --git a/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cpp b/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cpp new file mode 100644 index 000000000000..b2628dcc4dc1 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cpp @@ -0,0 +1,180 @@ +//===-- sanitizer_unwind_linux_libcdep.cpp --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains the unwind.h-based (aka "slow") stack unwinding routines +// available to the tools on Linux, Android, NetBSD, FreeBSD, and Solaris. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ + SANITIZER_SOLARIS +#include "sanitizer_common.h" +#include "sanitizer_stacktrace.h" + +#if SANITIZER_ANDROID +#include // for dlopen() +#endif + +#if SANITIZER_FREEBSD +#define _GNU_SOURCE // to declare _Unwind_Backtrace() from +#endif +#include + +namespace __sanitizer { + +namespace { + +//---------------------------- UnwindSlow -------------------------------------- + +typedef struct { + uptr absolute_pc; + uptr stack_top; + uptr stack_size; +} backtrace_frame_t; + +extern "C" { +typedef void *(*acquire_my_map_info_list_func)(); +typedef void (*release_my_map_info_list_func)(void *map); +typedef sptr (*unwind_backtrace_signal_arch_func)( + void *siginfo, void *sigcontext, void *map_info_list, + backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth); +acquire_my_map_info_list_func acquire_my_map_info_list; +release_my_map_info_list_func release_my_map_info_list; +unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch; +} // extern "C" + +#if defined(__arm__) && !SANITIZER_NETBSD +// NetBSD uses dwarf EH +#define UNWIND_STOP _URC_END_OF_STACK +#define UNWIND_CONTINUE _URC_NO_REASON +#else +#define UNWIND_STOP _URC_NORMAL_STOP +#define UNWIND_CONTINUE _URC_NO_REASON +#endif + +uptr Unwind_GetIP(struct _Unwind_Context *ctx) { +#if defined(__arm__) && !SANITIZER_MAC + uptr val; + _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE, + 15 /* r15 = PC */, _UVRSD_UINT32, &val); + CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed"); + // Clear the Thumb bit. + return val & ~(uptr)1; +#else + return (uptr)_Unwind_GetIP(ctx); +#endif +} + +struct UnwindTraceArg { + BufferedStackTrace *stack; + u32 max_depth; +}; + +_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { + UnwindTraceArg *arg = (UnwindTraceArg*)param; + CHECK_LT(arg->stack->size, arg->max_depth); + uptr pc = Unwind_GetIP(ctx); + const uptr kPageSize = GetPageSizeCached(); + // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and + // x86_64) is invalid and stop unwinding here. If we're adding support for + // a platform where this isn't true, we need to reconsider this check. + if (pc < kPageSize) return UNWIND_STOP; + arg->stack->trace_buffer[arg->stack->size++] = pc; + if (arg->stack->size == arg->max_depth) return UNWIND_STOP; + return UNWIND_CONTINUE; +} + +} // namespace + +#if SANITIZER_ANDROID +void SanitizerInitializeUnwinder() { + if (AndroidGetApiLevel() >= ANDROID_LOLLIPOP_MR1) return; + + // Pre-lollipop Android can not unwind through signal handler frames with + // libgcc unwinder, but it has a libcorkscrew.so library with the necessary + // workarounds. + void *p = dlopen("libcorkscrew.so", RTLD_LAZY); + if (!p) { + VReport(1, + "Failed to open libcorkscrew.so. You may see broken stack traces " + "in SEGV reports."); + return; + } + acquire_my_map_info_list = + (acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list"); + release_my_map_info_list = + (release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list"); + unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym( + p, "unwind_backtrace_signal_arch"); + if (!acquire_my_map_info_list || !release_my_map_info_list || + !unwind_backtrace_signal_arch) { + VReport(1, + "Failed to find one of the required symbols in libcorkscrew.so. " + "You may see broken stack traces in SEGV reports."); + acquire_my_map_info_list = 0; + unwind_backtrace_signal_arch = 0; + release_my_map_info_list = 0; + } +} +#endif + +void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) { + CHECK_GE(max_depth, 2); + size = 0; + UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; + _Unwind_Backtrace(Unwind_Trace, &arg); + // We need to pop a few frames so that pc is on top. + uptr to_pop = LocatePcInTrace(pc); + // trace_buffer[0] belongs to the current function so we always pop it, + // unless there is only 1 frame in the stack trace (1 frame is always better + // than 0!). + // 1-frame stacks don't normally happen, but this depends on the actual + // unwinder implementation (libgcc, libunwind, etc) which is outside of our + // control. + if (to_pop == 0 && size > 1) + to_pop = 1; + PopStackFrames(to_pop); +#if defined(__GNUC__) && defined(__sparc__) + // __builtin_return_address returns the address of the call instruction + // on the SPARC and not the return address, so we need to compensate. + trace_buffer[0] = GetNextInstructionPc(pc); +#else + trace_buffer[0] = pc; +#endif +} + +void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) { + CHECK(context); + CHECK_GE(max_depth, 2); + if (!unwind_backtrace_signal_arch) { + UnwindSlow(pc, max_depth); + return; + } + + void *map = acquire_my_map_info_list(); + CHECK(map); + InternalMmapVector frames(kStackTraceMax); + // siginfo argument appears to be unused. + sptr res = unwind_backtrace_signal_arch(/* siginfo */ 0, context, map, + frames.data(), + /* ignore_depth */ 0, max_depth); + release_my_map_info_list(map); + if (res < 0) return; + CHECK_LE((uptr)res, kStackTraceMax); + + size = 0; + // +2 compensate for libcorkscrew unwinder returning addresses of call + // instructions instead of raw return addresses. + for (sptr i = 0; i < res; ++i) + trace_buffer[size++] = frames[i].absolute_pc + 2; +} + +} // namespace __sanitizer + +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || + // SANITIZER_SOLARIS diff --git a/lib/sanitizer_common/sanitizer_unwind_win.cc b/lib/sanitizer_common/sanitizer_unwind_win.cc deleted file mode 100644 index 93908ababe25..000000000000 --- a/lib/sanitizer_common/sanitizer_unwind_win.cc +++ /dev/null @@ -1,75 +0,0 @@ -//===-- sanitizer_unwind_win.cc -------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -/// Sanitizer unwind Windows specific functions. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_WINDOWS - -#define WIN32_LEAN_AND_MEAN -#define NOGDI -#include - -#include "sanitizer_dbghelp.h" // for StackWalk64 -#include "sanitizer_stacktrace.h" -#include "sanitizer_symbolizer.h" // for InitializeDbgHelpIfNeeded - -using namespace __sanitizer; - -#if !SANITIZER_GO -void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) { - CHECK_GE(max_depth, 2); - // FIXME: CaptureStackBackTrace might be too slow for us. - // FIXME: Compare with StackWalk64. - // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc - size = CaptureStackBackTrace(1, Min(max_depth, kStackTraceMax), - (void **)&trace_buffer[0], 0); - if (size == 0) - return; - - // Skip the RTL frames by searching for the PC in the stacktrace. - uptr pc_location = LocatePcInTrace(pc); - PopStackFrames(pc_location); -} - -void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) { - CHECK(context); - CHECK_GE(max_depth, 2); - CONTEXT ctx = *(CONTEXT *)context; - STACKFRAME64 stack_frame; - memset(&stack_frame, 0, sizeof(stack_frame)); - - InitializeDbgHelpIfNeeded(); - - size = 0; -#if defined(_WIN64) - int machine_type = IMAGE_FILE_MACHINE_AMD64; - stack_frame.AddrPC.Offset = ctx.Rip; - stack_frame.AddrFrame.Offset = ctx.Rbp; - stack_frame.AddrStack.Offset = ctx.Rsp; -#else - int machine_type = IMAGE_FILE_MACHINE_I386; - stack_frame.AddrPC.Offset = ctx.Eip; - stack_frame.AddrFrame.Offset = ctx.Ebp; - stack_frame.AddrStack.Offset = ctx.Esp; -#endif - stack_frame.AddrPC.Mode = AddrModeFlat; - stack_frame.AddrFrame.Mode = AddrModeFlat; - stack_frame.AddrStack.Mode = AddrModeFlat; - while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(), - &stack_frame, &ctx, NULL, SymFunctionTableAccess64, - SymGetModuleBase64, NULL) && - size < Min(max_depth, kStackTraceMax)) { - trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset; - } -} -#endif // #if !SANITIZER_GO - -#endif // SANITIZER_WINDOWS diff --git a/lib/sanitizer_common/sanitizer_unwind_win.cpp b/lib/sanitizer_common/sanitizer_unwind_win.cpp new file mode 100644 index 000000000000..8e06940685dc --- /dev/null +++ b/lib/sanitizer_common/sanitizer_unwind_win.cpp @@ -0,0 +1,75 @@ +//===-- sanitizer_unwind_win.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// Sanitizer unwind Windows specific functions. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS + +#define WIN32_LEAN_AND_MEAN +#define NOGDI +#include + +#include "sanitizer_dbghelp.h" // for StackWalk64 +#include "sanitizer_stacktrace.h" +#include "sanitizer_symbolizer.h" // for InitializeDbgHelpIfNeeded + +using namespace __sanitizer; + +#if !SANITIZER_GO +void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) { + CHECK_GE(max_depth, 2); + // FIXME: CaptureStackBackTrace might be too slow for us. + // FIXME: Compare with StackWalk64. + // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc + size = CaptureStackBackTrace(1, Min(max_depth, kStackTraceMax), + (void **)&trace_buffer[0], 0); + if (size == 0) + return; + + // Skip the RTL frames by searching for the PC in the stacktrace. + uptr pc_location = LocatePcInTrace(pc); + PopStackFrames(pc_location); +} + +void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) { + CHECK(context); + CHECK_GE(max_depth, 2); + CONTEXT ctx = *(CONTEXT *)context; + STACKFRAME64 stack_frame; + memset(&stack_frame, 0, sizeof(stack_frame)); + + InitializeDbgHelpIfNeeded(); + + size = 0; +#if defined(_WIN64) + int machine_type = IMAGE_FILE_MACHINE_AMD64; + stack_frame.AddrPC.Offset = ctx.Rip; + stack_frame.AddrFrame.Offset = ctx.Rbp; + stack_frame.AddrStack.Offset = ctx.Rsp; +#else + int machine_type = IMAGE_FILE_MACHINE_I386; + stack_frame.AddrPC.Offset = ctx.Eip; + stack_frame.AddrFrame.Offset = ctx.Ebp; + stack_frame.AddrStack.Offset = ctx.Esp; +#endif + stack_frame.AddrPC.Mode = AddrModeFlat; + stack_frame.AddrFrame.Mode = AddrModeFlat; + stack_frame.AddrStack.Mode = AddrModeFlat; + while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(), + &stack_frame, &ctx, NULL, SymFunctionTableAccess64, + SymGetModuleBase64, NULL) && + size < Min(max_depth, kStackTraceMax)) { + trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset; + } +} +#endif // #if !SANITIZER_GO + +#endif // SANITIZER_WINDOWS diff --git a/lib/sanitizer_common/sanitizer_vector.h b/lib/sanitizer_common/sanitizer_vector.h index 4b9ae7db4c13..31216f3ec3a6 100644 --- a/lib/sanitizer_common/sanitizer_vector.h +++ b/lib/sanitizer_common/sanitizer_vector.h @@ -23,11 +23,7 @@ namespace __sanitizer { template class Vector { public: - explicit Vector() - : begin_() - , end_() - , last_() { - } + Vector() : begin_(), end_(), last_() {} ~Vector() { if (begin_) diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc deleted file mode 100644 index 457cecb8cec1..000000000000 --- a/lib/sanitizer_common/sanitizer_win.cc +++ /dev/null @@ -1,1115 +0,0 @@ -//===-- sanitizer_win.cc --------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries and implements windows-specific functions from -// sanitizer_libc.h. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_WINDOWS - -#define WIN32_LEAN_AND_MEAN -#define NOGDI -#include -#include -#include -#include - -#include "sanitizer_common.h" -#include "sanitizer_file.h" -#include "sanitizer_libc.h" -#include "sanitizer_mutex.h" -#include "sanitizer_placement_new.h" -#include "sanitizer_win_defs.h" - -#if defined(PSAPI_VERSION) && PSAPI_VERSION == 1 -#pragma comment(lib, "psapi") -#endif -#if SANITIZER_WIN_TRACE -#include -// Windows trace logging provider init -#pragma comment(lib, "advapi32.lib") -TRACELOGGING_DECLARE_PROVIDER(g_asan_provider); -// GUID must be the same in utils/AddressSanitizerLoggingProvider.wprp -TRACELOGGING_DEFINE_PROVIDER(g_asan_provider, "AddressSanitizerLoggingProvider", - (0x6c6c766d, 0x3846, 0x4e6a, 0xa4, 0xfb, 0x5b, - 0x53, 0x0b, 0xd0, 0xf3, 0xfa)); -#else -#define TraceLoggingUnregister(x) -#endif - -// A macro to tell the compiler that this part of the code cannot be reached, -// if the compiler supports this feature. Since we're using this in -// code that is called when terminating the process, the expansion of the -// macro should not terminate the process to avoid infinite recursion. -#if defined(__clang__) -# define BUILTIN_UNREACHABLE() __builtin_unreachable() -#elif defined(__GNUC__) && \ - (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) -# define BUILTIN_UNREACHABLE() __builtin_unreachable() -#elif defined(_MSC_VER) -# define BUILTIN_UNREACHABLE() __assume(0) -#else -# define BUILTIN_UNREACHABLE() -#endif - -namespace __sanitizer { - -#include "sanitizer_syscall_generic.inc" - -// --------------------- sanitizer_common.h -uptr GetPageSize() { - SYSTEM_INFO si; - GetSystemInfo(&si); - return si.dwPageSize; -} - -uptr GetMmapGranularity() { - SYSTEM_INFO si; - GetSystemInfo(&si); - return si.dwAllocationGranularity; -} - -uptr GetMaxUserVirtualAddress() { - SYSTEM_INFO si; - GetSystemInfo(&si); - return (uptr)si.lpMaximumApplicationAddress; -} - -uptr GetMaxVirtualAddress() { - return GetMaxUserVirtualAddress(); -} - -bool FileExists(const char *filename) { - return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES; -} - -uptr internal_getpid() { - return GetProcessId(GetCurrentProcess()); -} - -// In contrast to POSIX, on Windows GetCurrentThreadId() -// returns a system-unique identifier. -tid_t GetTid() { - return GetCurrentThreadId(); -} - -uptr GetThreadSelf() { - return GetTid(); -} - -#if !SANITIZER_GO -void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, - uptr *stack_bottom) { - CHECK(stack_top); - CHECK(stack_bottom); - MEMORY_BASIC_INFORMATION mbi; - CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0); - // FIXME: is it possible for the stack to not be a single allocation? - // Are these values what ASan expects to get (reserved, not committed; - // including stack guard page) ? - *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize; - *stack_bottom = (uptr)mbi.AllocationBase; -} -#endif // #if !SANITIZER_GO - -void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { - void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - if (rv == 0) - ReportMmapFailureAndDie(size, mem_type, "allocate", - GetLastError(), raw_report); - return rv; -} - -void UnmapOrDie(void *addr, uptr size) { - if (!size || !addr) - return; - - MEMORY_BASIC_INFORMATION mbi; - CHECK(VirtualQuery(addr, &mbi, sizeof(mbi))); - - // MEM_RELEASE can only be used to unmap whole regions previously mapped with - // VirtualAlloc. So we first try MEM_RELEASE since it is better, and if that - // fails try MEM_DECOMMIT. - if (VirtualFree(addr, 0, MEM_RELEASE) == 0) { - if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) { - Report("ERROR: %s failed to " - "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n", - SanitizerToolName, size, size, addr, GetLastError()); - CHECK("unable to unmap" && 0); - } - } -} - -static void *ReturnNullptrOnOOMOrDie(uptr size, const char *mem_type, - const char *mmap_type) { - error_t last_error = GetLastError(); - if (last_error == ERROR_NOT_ENOUGH_MEMORY) - return nullptr; - ReportMmapFailureAndDie(size, mem_type, mmap_type, last_error); -} - -void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { - void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - if (rv == 0) - return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); - return rv; -} - -// We want to map a chunk of address space aligned to 'alignment'. -void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, - const char *mem_type) { - CHECK(IsPowerOfTwo(size)); - CHECK(IsPowerOfTwo(alignment)); - - // Windows will align our allocations to at least 64K. - alignment = Max(alignment, GetMmapGranularity()); - - uptr mapped_addr = - (uptr)VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - if (!mapped_addr) - return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); - - // If we got it right on the first try, return. Otherwise, unmap it and go to - // the slow path. - if (IsAligned(mapped_addr, alignment)) - return (void*)mapped_addr; - if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0) - ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError()); - - // If we didn't get an aligned address, overallocate, find an aligned address, - // unmap, and try to allocate at that aligned address. - int retries = 0; - const int kMaxRetries = 10; - for (; retries < kMaxRetries && - (mapped_addr == 0 || !IsAligned(mapped_addr, alignment)); - retries++) { - // Overallocate size + alignment bytes. - mapped_addr = - (uptr)VirtualAlloc(0, size + alignment, MEM_RESERVE, PAGE_NOACCESS); - if (!mapped_addr) - return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); - - // Find the aligned address. - uptr aligned_addr = RoundUpTo(mapped_addr, alignment); - - // Free the overallocation. - if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0) - ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError()); - - // Attempt to allocate exactly the number of bytes we need at the aligned - // address. This may fail for a number of reasons, in which case we continue - // the loop. - mapped_addr = (uptr)VirtualAlloc((void *)aligned_addr, size, - MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - } - - // Fail if we can't make this work quickly. - if (retries == kMaxRetries && mapped_addr == 0) - return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); - - return (void *)mapped_addr; -} - -bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { - // FIXME: is this really "NoReserve"? On Win32 this does not matter much, - // but on Win64 it does. - (void)name; // unsupported -#if !SANITIZER_GO && SANITIZER_WINDOWS64 - // On asan/Windows64, use MEM_COMMIT would result in error - // 1455:ERROR_COMMITMENT_LIMIT. - // Asan uses exception handler to commit page on demand. - void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE, PAGE_READWRITE); -#else - void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE | MEM_COMMIT, - PAGE_READWRITE); -#endif - if (p == 0) { - Report("ERROR: %s failed to " - "allocate %p (%zd) bytes at %p (error code: %d)\n", - SanitizerToolName, size, size, fixed_addr, GetLastError()); - return false; - } - return true; -} - -// Memory space mapped by 'MmapFixedOrDie' must have been reserved by -// 'MmapFixedNoAccess'. -void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) { - void *p = VirtualAlloc((LPVOID)fixed_addr, size, - MEM_COMMIT, PAGE_READWRITE); - if (p == 0) { - char mem_type[30]; - internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", - fixed_addr); - ReportMmapFailureAndDie(size, mem_type, "allocate", GetLastError()); - } - return p; -} - -// Uses fixed_addr for now. -// Will use offset instead once we've implemented this function for real. -uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, const char *name) { - return reinterpret_cast(MmapFixedOrDieOnFatalError(fixed_addr, size)); -} - -uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size, - const char *name) { - return reinterpret_cast(MmapFixedOrDie(fixed_addr, size)); -} - -void ReservedAddressRange::Unmap(uptr addr, uptr size) { - // Only unmap if it covers the entire range. - CHECK((addr == reinterpret_cast(base_)) && (size == size_)); - // We unmap the whole range, just null out the base. - base_ = nullptr; - size_ = 0; - UnmapOrDie(reinterpret_cast(addr), size); -} - -void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) { - void *p = VirtualAlloc((LPVOID)fixed_addr, size, - MEM_COMMIT, PAGE_READWRITE); - if (p == 0) { - char mem_type[30]; - internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", - fixed_addr); - return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); - } - return p; -} - -void *MmapNoReserveOrDie(uptr size, const char *mem_type) { - // FIXME: make this really NoReserve? - return MmapOrDie(size, mem_type); -} - -uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { - base_ = fixed_addr ? MmapFixedNoAccess(fixed_addr, size) : MmapNoAccess(size); - size_ = size; - name_ = name; - (void)os_handle_; // unsupported - return reinterpret_cast(base_); -} - - -void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { - (void)name; // unsupported - void *res = VirtualAlloc((LPVOID)fixed_addr, size, - MEM_RESERVE, PAGE_NOACCESS); - if (res == 0) - Report("WARNING: %s failed to " - "mprotect %p (%zd) bytes at %p (error code: %d)\n", - SanitizerToolName, size, size, fixed_addr, GetLastError()); - return res; -} - -void *MmapNoAccess(uptr size) { - void *res = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_NOACCESS); - if (res == 0) - Report("WARNING: %s failed to " - "mprotect %p (%zd) bytes (error code: %d)\n", - SanitizerToolName, size, size, GetLastError()); - return res; -} - -bool MprotectNoAccess(uptr addr, uptr size) { - DWORD old_protection; - return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection); -} - -void ReleaseMemoryPagesToOS(uptr beg, uptr end) { - // This is almost useless on 32-bits. - // FIXME: add madvise-analog when we move to 64-bits. -} - -bool NoHugePagesInRegion(uptr addr, uptr size) { - // FIXME: probably similar to ReleaseMemoryToOS. - return true; -} - -bool DontDumpShadowMemory(uptr addr, uptr length) { - // This is almost useless on 32-bits. - // FIXME: add madvise-analog when we move to 64-bits. - return true; -} - -uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, - uptr *largest_gap_found, - uptr *max_occupied_addr) { - uptr address = 0; - while (true) { - MEMORY_BASIC_INFORMATION info; - if (!::VirtualQuery((void*)address, &info, sizeof(info))) - return 0; - - if (info.State == MEM_FREE) { - uptr shadow_address = RoundUpTo((uptr)info.BaseAddress + left_padding, - alignment); - if (shadow_address + size < (uptr)info.BaseAddress + info.RegionSize) - return shadow_address; - } - - // Move to the next region. - address = (uptr)info.BaseAddress + info.RegionSize; - } - return 0; -} - -bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { - MEMORY_BASIC_INFORMATION mbi; - CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi))); - return mbi.Protect == PAGE_NOACCESS && - (uptr)mbi.BaseAddress + mbi.RegionSize >= range_end; -} - -void *MapFileToMemory(const char *file_name, uptr *buff_size) { - UNIMPLEMENTED(); -} - -void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { - UNIMPLEMENTED(); -} - -static const int kMaxEnvNameLength = 128; -static const DWORD kMaxEnvValueLength = 32767; - -namespace { - -struct EnvVariable { - char name[kMaxEnvNameLength]; - char value[kMaxEnvValueLength]; -}; - -} // namespace - -static const int kEnvVariables = 5; -static EnvVariable env_vars[kEnvVariables]; -static int num_env_vars; - -const char *GetEnv(const char *name) { - // Note: this implementation caches the values of the environment variables - // and limits their quantity. - for (int i = 0; i < num_env_vars; i++) { - if (0 == internal_strcmp(name, env_vars[i].name)) - return env_vars[i].value; - } - CHECK_LT(num_env_vars, kEnvVariables); - DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value, - kMaxEnvValueLength); - if (rv > 0 && rv < kMaxEnvValueLength) { - CHECK_LT(internal_strlen(name), kMaxEnvNameLength); - internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength); - num_env_vars++; - return env_vars[num_env_vars - 1].value; - } - return 0; -} - -const char *GetPwd() { - UNIMPLEMENTED(); -} - -u32 GetUid() { - UNIMPLEMENTED(); -} - -namespace { -struct ModuleInfo { - const char *filepath; - uptr base_address; - uptr end_address; -}; - -#if !SANITIZER_GO -int CompareModulesBase(const void *pl, const void *pr) { - const ModuleInfo *l = (const ModuleInfo *)pl, *r = (const ModuleInfo *)pr; - if (l->base_address < r->base_address) - return -1; - return l->base_address > r->base_address; -} -#endif -} // namespace - -#if !SANITIZER_GO -void DumpProcessMap() { - Report("Dumping process modules:\n"); - ListOfModules modules; - modules.init(); - uptr num_modules = modules.size(); - - InternalMmapVector module_infos(num_modules); - for (size_t i = 0; i < num_modules; ++i) { - module_infos[i].filepath = modules[i].full_name(); - module_infos[i].base_address = modules[i].ranges().front()->beg; - module_infos[i].end_address = modules[i].ranges().back()->end; - } - qsort(module_infos.data(), num_modules, sizeof(ModuleInfo), - CompareModulesBase); - - for (size_t i = 0; i < num_modules; ++i) { - const ModuleInfo &mi = module_infos[i]; - if (mi.end_address != 0) { - Printf("\t%p-%p %s\n", mi.base_address, mi.end_address, - mi.filepath[0] ? mi.filepath : "[no name]"); - } else if (mi.filepath[0]) { - Printf("\t??\?-??? %s\n", mi.filepath); - } else { - Printf("\t???\n"); - } - } -} -#endif - -void PrintModuleMap() { } - -void DisableCoreDumperIfNecessary() { - // Do nothing. -} - -void ReExec() { - UNIMPLEMENTED(); -} - -void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} - -bool StackSizeIsUnlimited() { - UNIMPLEMENTED(); -} - -void SetStackSizeLimitInBytes(uptr limit) { - UNIMPLEMENTED(); -} - -bool AddressSpaceIsUnlimited() { - UNIMPLEMENTED(); -} - -void SetAddressSpaceUnlimited() { - UNIMPLEMENTED(); -} - -bool IsPathSeparator(const char c) { - return c == '\\' || c == '/'; -} - -static bool IsAlpha(char c) { - c = ToLower(c); - return c >= 'a' && c <= 'z'; -} - -bool IsAbsolutePath(const char *path) { - return path != nullptr && IsAlpha(path[0]) && path[1] == ':' && - IsPathSeparator(path[2]); -} - -void SleepForSeconds(int seconds) { - Sleep(seconds * 1000); -} - -void SleepForMillis(int millis) { - Sleep(millis); -} - -u64 NanoTime() { - static LARGE_INTEGER frequency = {}; - LARGE_INTEGER counter; - if (UNLIKELY(frequency.QuadPart == 0)) { - QueryPerformanceFrequency(&frequency); - CHECK_NE(frequency.QuadPart, 0); - } - QueryPerformanceCounter(&counter); - counter.QuadPart *= 1000ULL * 1000000ULL; - counter.QuadPart /= frequency.QuadPart; - return counter.QuadPart; -} - -u64 MonotonicNanoTime() { return NanoTime(); } - -void Abort() { - internal__exit(3); -} - -#if !SANITIZER_GO -// Read the file to extract the ImageBase field from the PE header. If ASLR is -// disabled and this virtual address is available, the loader will typically -// load the image at this address. Therefore, we call it the preferred base. Any -// addresses in the DWARF typically assume that the object has been loaded at -// this address. -static uptr GetPreferredBase(const char *modname) { - fd_t fd = OpenFile(modname, RdOnly, nullptr); - if (fd == kInvalidFd) - return 0; - FileCloser closer(fd); - - // Read just the DOS header. - IMAGE_DOS_HEADER dos_header; - uptr bytes_read; - if (!ReadFromFile(fd, &dos_header, sizeof(dos_header), &bytes_read) || - bytes_read != sizeof(dos_header)) - return 0; - - // The file should start with the right signature. - if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) - return 0; - - // The layout at e_lfanew is: - // "PE\0\0" - // IMAGE_FILE_HEADER - // IMAGE_OPTIONAL_HEADER - // Seek to e_lfanew and read all that data. - char buf[4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER)]; - if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) == - INVALID_SET_FILE_POINTER) - return 0; - if (!ReadFromFile(fd, &buf[0], sizeof(buf), &bytes_read) || - bytes_read != sizeof(buf)) - return 0; - - // Check for "PE\0\0" before the PE header. - char *pe_sig = &buf[0]; - if (internal_memcmp(pe_sig, "PE\0\0", 4) != 0) - return 0; - - // Skip over IMAGE_FILE_HEADER. We could do more validation here if we wanted. - IMAGE_OPTIONAL_HEADER *pe_header = - (IMAGE_OPTIONAL_HEADER *)(pe_sig + 4 + sizeof(IMAGE_FILE_HEADER)); - - // Check for more magic in the PE header. - if (pe_header->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) - return 0; - - // Finally, return the ImageBase. - return (uptr)pe_header->ImageBase; -} - -void ListOfModules::init() { - clearOrInit(); - HANDLE cur_process = GetCurrentProcess(); - - // Query the list of modules. Start by assuming there are no more than 256 - // modules and retry if that's not sufficient. - HMODULE *hmodules = 0; - uptr modules_buffer_size = sizeof(HMODULE) * 256; - DWORD bytes_required; - while (!hmodules) { - hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__); - CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size, - &bytes_required)); - if (bytes_required > modules_buffer_size) { - // Either there turned out to be more than 256 hmodules, or new hmodules - // could have loaded since the last try. Retry. - UnmapOrDie(hmodules, modules_buffer_size); - hmodules = 0; - modules_buffer_size = bytes_required; - } - } - - // |num_modules| is the number of modules actually present, - size_t num_modules = bytes_required / sizeof(HMODULE); - for (size_t i = 0; i < num_modules; ++i) { - HMODULE handle = hmodules[i]; - MODULEINFO mi; - if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi))) - continue; - - // Get the UTF-16 path and convert to UTF-8. - wchar_t modname_utf16[kMaxPathLength]; - int modname_utf16_len = - GetModuleFileNameW(handle, modname_utf16, kMaxPathLength); - if (modname_utf16_len == 0) - modname_utf16[0] = '\0'; - char module_name[kMaxPathLength]; - int module_name_len = - ::WideCharToMultiByte(CP_UTF8, 0, modname_utf16, modname_utf16_len + 1, - &module_name[0], kMaxPathLength, NULL, NULL); - module_name[module_name_len] = '\0'; - - uptr base_address = (uptr)mi.lpBaseOfDll; - uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage; - - // Adjust the base address of the module so that we get a VA instead of an - // RVA when computing the module offset. This helps llvm-symbolizer find the - // right DWARF CU. In the common case that the image is loaded at it's - // preferred address, we will now print normal virtual addresses. - uptr preferred_base = GetPreferredBase(&module_name[0]); - uptr adjusted_base = base_address - preferred_base; - - LoadedModule cur_module; - cur_module.set(module_name, adjusted_base); - // We add the whole module as one single address range. - cur_module.addAddressRange(base_address, end_address, /*executable*/ true, - /*writable*/ true); - modules_.push_back(cur_module); - } - UnmapOrDie(hmodules, modules_buffer_size); -} - -void ListOfModules::fallbackInit() { clear(); } - -// We can't use atexit() directly at __asan_init time as the CRT is not fully -// initialized at this point. Place the functions into a vector and use -// atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers). -InternalMmapVectorNoCtor atexit_functions; - -int Atexit(void (*function)(void)) { - atexit_functions.push_back(function); - return 0; -} - -static int RunAtexit() { - TraceLoggingUnregister(g_asan_provider); - int ret = 0; - for (uptr i = 0; i < atexit_functions.size(); ++i) { - ret |= atexit(atexit_functions[i]); - } - return ret; -} - -#pragma section(".CRT$XID", long, read) // NOLINT -__declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit; -#endif - -// ------------------ sanitizer_libc.h -fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) { - // FIXME: Use the wide variants to handle Unicode filenames. - fd_t res; - if (mode == RdOnly) { - res = CreateFileA(filename, GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); - } else if (mode == WrOnly) { - res = CreateFileA(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, nullptr); - } else { - UNIMPLEMENTED(); - } - CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd); - CHECK(res != kStderrFd || kStderrFd == kInvalidFd); - if (res == kInvalidFd && last_error) - *last_error = GetLastError(); - return res; -} - -void CloseFile(fd_t fd) { - CloseHandle(fd); -} - -bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, - error_t *error_p) { - CHECK(fd != kInvalidFd); - - // bytes_read can't be passed directly to ReadFile: - // uptr is unsigned long long on 64-bit Windows. - unsigned long num_read_long; - - bool success = ::ReadFile(fd, buff, buff_size, &num_read_long, nullptr); - if (!success && error_p) - *error_p = GetLastError(); - if (bytes_read) - *bytes_read = num_read_long; - return success; -} - -bool SupportsColoredOutput(fd_t fd) { - // FIXME: support colored output. - return false; -} - -bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, - error_t *error_p) { - CHECK(fd != kInvalidFd); - - // Handle null optional parameters. - error_t dummy_error; - error_p = error_p ? error_p : &dummy_error; - uptr dummy_bytes_written; - bytes_written = bytes_written ? bytes_written : &dummy_bytes_written; - - // Initialize output parameters in case we fail. - *error_p = 0; - *bytes_written = 0; - - // Map the conventional Unix fds 1 and 2 to Windows handles. They might be - // closed, in which case this will fail. - if (fd == kStdoutFd || fd == kStderrFd) { - fd = GetStdHandle(fd == kStdoutFd ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); - if (fd == 0) { - *error_p = ERROR_INVALID_HANDLE; - return false; - } - } - - DWORD bytes_written_32; - if (!WriteFile(fd, buff, buff_size, &bytes_written_32, 0)) { - *error_p = GetLastError(); - return false; - } else { - *bytes_written = bytes_written_32; - return true; - } -} - -uptr internal_sched_yield() { - Sleep(0); - return 0; -} - -void internal__exit(int exitcode) { - TraceLoggingUnregister(g_asan_provider); - // ExitProcess runs some finalizers, so use TerminateProcess to avoid that. - // The debugger doesn't stop on TerminateProcess like it does on ExitProcess, - // so add our own breakpoint here. - if (::IsDebuggerPresent()) - __debugbreak(); - TerminateProcess(GetCurrentProcess(), exitcode); - BUILTIN_UNREACHABLE(); -} - -uptr internal_ftruncate(fd_t fd, uptr size) { - UNIMPLEMENTED(); -} - -uptr GetRSS() { - PROCESS_MEMORY_COUNTERS counters; - if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) - return 0; - return counters.WorkingSetSize; -} - -void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; } -void internal_join_thread(void *th) { } - -// ---------------------- BlockingMutex ---------------- {{{1 - -BlockingMutex::BlockingMutex() { - CHECK(sizeof(SRWLOCK) <= sizeof(opaque_storage_)); - internal_memset(this, 0, sizeof(*this)); -} - -void BlockingMutex::Lock() { - AcquireSRWLockExclusive((PSRWLOCK)opaque_storage_); - CHECK_EQ(owner_, 0); - owner_ = GetThreadSelf(); -} - -void BlockingMutex::Unlock() { - CheckLocked(); - owner_ = 0; - ReleaseSRWLockExclusive((PSRWLOCK)opaque_storage_); -} - -void BlockingMutex::CheckLocked() { - CHECK_EQ(owner_, GetThreadSelf()); -} - -uptr GetTlsSize() { - return 0; -} - -void InitTlsSize() { -} - -void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, - uptr *tls_addr, uptr *tls_size) { -#if SANITIZER_GO - *stk_addr = 0; - *stk_size = 0; - *tls_addr = 0; - *tls_size = 0; -#else - uptr stack_top, stack_bottom; - GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); - *stk_addr = stack_bottom; - *stk_size = stack_top - stack_bottom; - *tls_addr = 0; - *tls_size = 0; -#endif -} - -void ReportFile::Write(const char *buffer, uptr length) { - SpinMutexLock l(mu); - ReopenIfNecessary(); - if (!WriteToFile(fd, buffer, length)) { - // stderr may be closed, but we may be able to print to the debugger - // instead. This is the case when launching a program from Visual Studio, - // and the following routine should write to its console. - OutputDebugStringA(buffer); - } -} - -void SetAlternateSignalStack() { - // FIXME: Decide what to do on Windows. -} - -void UnsetAlternateSignalStack() { - // FIXME: Decide what to do on Windows. -} - -void InstallDeadlySignalHandlers(SignalHandlerType handler) { - (void)handler; - // FIXME: Decide what to do on Windows. -} - -HandleSignalMode GetHandleSignalMode(int signum) { - // FIXME: Decide what to do on Windows. - return kHandleSignalNo; -} - -// Check based on flags if we should handle this exception. -bool IsHandledDeadlyException(DWORD exceptionCode) { - switch (exceptionCode) { - case EXCEPTION_ACCESS_VIOLATION: - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - case EXCEPTION_STACK_OVERFLOW: - case EXCEPTION_DATATYPE_MISALIGNMENT: - case EXCEPTION_IN_PAGE_ERROR: - return common_flags()->handle_segv; - case EXCEPTION_ILLEGAL_INSTRUCTION: - case EXCEPTION_PRIV_INSTRUCTION: - case EXCEPTION_BREAKPOINT: - return common_flags()->handle_sigill; - case EXCEPTION_FLT_DENORMAL_OPERAND: - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - case EXCEPTION_FLT_INEXACT_RESULT: - case EXCEPTION_FLT_INVALID_OPERATION: - case EXCEPTION_FLT_OVERFLOW: - case EXCEPTION_FLT_STACK_CHECK: - case EXCEPTION_FLT_UNDERFLOW: - case EXCEPTION_INT_DIVIDE_BY_ZERO: - case EXCEPTION_INT_OVERFLOW: - return common_flags()->handle_sigfpe; - } - return false; -} - -bool IsAccessibleMemoryRange(uptr beg, uptr size) { - SYSTEM_INFO si; - GetNativeSystemInfo(&si); - uptr page_size = si.dwPageSize; - uptr page_mask = ~(page_size - 1); - - for (uptr page = beg & page_mask, end = (beg + size - 1) & page_mask; - page <= end;) { - MEMORY_BASIC_INFORMATION info; - if (VirtualQuery((LPCVOID)page, &info, sizeof(info)) != sizeof(info)) - return false; - - if (info.Protect == 0 || info.Protect == PAGE_NOACCESS || - info.Protect == PAGE_EXECUTE) - return false; - - if (info.RegionSize == 0) - return false; - - page += info.RegionSize; - } - - return true; -} - -bool SignalContext::IsStackOverflow() const { - return (DWORD)GetType() == EXCEPTION_STACK_OVERFLOW; -} - -void SignalContext::InitPcSpBp() { - EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; - CONTEXT *context_record = (CONTEXT *)context; - - pc = (uptr)exception_record->ExceptionAddress; -#ifdef _WIN64 - bp = (uptr)context_record->Rbp; - sp = (uptr)context_record->Rsp; -#else - bp = (uptr)context_record->Ebp; - sp = (uptr)context_record->Esp; -#endif -} - -uptr SignalContext::GetAddress() const { - EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; - return exception_record->ExceptionInformation[1]; -} - -bool SignalContext::IsMemoryAccess() const { - return GetWriteFlag() != SignalContext::UNKNOWN; -} - -SignalContext::WriteFlag SignalContext::GetWriteFlag() const { - EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; - // The contents of this array are documented at - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx - // The first element indicates read as 0, write as 1, or execute as 8. The - // second element is the faulting address. - switch (exception_record->ExceptionInformation[0]) { - case 0: - return SignalContext::READ; - case 1: - return SignalContext::WRITE; - case 8: - return SignalContext::UNKNOWN; - } - return SignalContext::UNKNOWN; -} - -void SignalContext::DumpAllRegisters(void *context) { - // FIXME: Implement this. -} - -int SignalContext::GetType() const { - return static_cast(siginfo)->ExceptionCode; -} - -const char *SignalContext::Describe() const { - unsigned code = GetType(); - // Get the string description of the exception if this is a known deadly - // exception. - switch (code) { - case EXCEPTION_ACCESS_VIOLATION: - return "access-violation"; - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - return "array-bounds-exceeded"; - case EXCEPTION_STACK_OVERFLOW: - return "stack-overflow"; - case EXCEPTION_DATATYPE_MISALIGNMENT: - return "datatype-misalignment"; - case EXCEPTION_IN_PAGE_ERROR: - return "in-page-error"; - case EXCEPTION_ILLEGAL_INSTRUCTION: - return "illegal-instruction"; - case EXCEPTION_PRIV_INSTRUCTION: - return "priv-instruction"; - case EXCEPTION_BREAKPOINT: - return "breakpoint"; - case EXCEPTION_FLT_DENORMAL_OPERAND: - return "flt-denormal-operand"; - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - return "flt-divide-by-zero"; - case EXCEPTION_FLT_INEXACT_RESULT: - return "flt-inexact-result"; - case EXCEPTION_FLT_INVALID_OPERATION: - return "flt-invalid-operation"; - case EXCEPTION_FLT_OVERFLOW: - return "flt-overflow"; - case EXCEPTION_FLT_STACK_CHECK: - return "flt-stack-check"; - case EXCEPTION_FLT_UNDERFLOW: - return "flt-underflow"; - case EXCEPTION_INT_DIVIDE_BY_ZERO: - return "int-divide-by-zero"; - case EXCEPTION_INT_OVERFLOW: - return "int-overflow"; - } - return "unknown exception"; -} - -uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { - // FIXME: Actually implement this function. - CHECK_GT(buf_len, 0); - buf[0] = 0; - return 0; -} - -uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { - return ReadBinaryName(buf, buf_len); -} - -void CheckVMASize() { - // Do nothing. -} - -void InitializePlatformEarly() { - // Do nothing. -} - -void MaybeReexec() { - // No need to re-exec on Windows. -} - -void CheckASLR() { - // Do nothing -} - -void CheckMPROTECT() { - // Do nothing -} - -char **GetArgv() { - // FIXME: Actually implement this function. - return 0; -} - -char **GetEnviron() { - // FIXME: Actually implement this function. - return 0; -} - -pid_t StartSubprocess(const char *program, const char *const argv[], - fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { - // FIXME: implement on this platform - // Should be implemented based on - // SymbolizerProcess::StarAtSymbolizerSubprocess - // from lib/sanitizer_common/sanitizer_symbolizer_win.cc. - return -1; -} - -bool IsProcessRunning(pid_t pid) { - // FIXME: implement on this platform. - return false; -} - -int WaitForProcess(pid_t pid) { return -1; } - -// FIXME implement on this platform. -void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { } - -void CheckNoDeepBind(const char *filename, int flag) { - // Do nothing. -} - -// FIXME: implement on this platform. -bool GetRandom(void *buffer, uptr length, bool blocking) { - UNIMPLEMENTED(); -} - -u32 GetNumberOfCPUs() { - SYSTEM_INFO sysinfo = {}; - GetNativeSystemInfo(&sysinfo); - return sysinfo.dwNumberOfProcessors; -} - -#if SANITIZER_WIN_TRACE -// TODO(mcgov): Rename this project-wide to PlatformLogInit -void AndroidLogInit(void) { - HRESULT hr = TraceLoggingRegister(g_asan_provider); - if (!SUCCEEDED(hr)) - return; -} - -void SetAbortMessage(const char *) {} - -void LogFullErrorReport(const char *buffer) { - if (common_flags()->log_to_syslog) { - InternalMmapVector filename; - DWORD filename_length = 0; - do { - filename.resize(filename.size() + 0x100); - filename_length = - GetModuleFileNameW(NULL, filename.begin(), filename.size()); - } while (filename_length >= filename.size()); - TraceLoggingWrite(g_asan_provider, "AsanReportEvent", - TraceLoggingValue(filename.begin(), "ExecutableName"), - TraceLoggingValue(buffer, "AsanReportContents")); - } -} -#endif // SANITIZER_WIN_TRACE - -} // namespace __sanitizer - -#endif // _WIN32 diff --git a/lib/sanitizer_common/sanitizer_win.cpp b/lib/sanitizer_common/sanitizer_win.cpp new file mode 100644 index 000000000000..36dde49d8708 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_win.cpp @@ -0,0 +1,1124 @@ +//===-- sanitizer_win.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries and implements windows-specific functions from +// sanitizer_libc.h. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS + +#define WIN32_LEAN_AND_MEAN +#define NOGDI +#include +#include +#include +#include + +#include "sanitizer_common.h" +#include "sanitizer_file.h" +#include "sanitizer_libc.h" +#include "sanitizer_mutex.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_win_defs.h" + +#if defined(PSAPI_VERSION) && PSAPI_VERSION == 1 +#pragma comment(lib, "psapi") +#endif +#if SANITIZER_WIN_TRACE +#include +// Windows trace logging provider init +#pragma comment(lib, "advapi32.lib") +TRACELOGGING_DECLARE_PROVIDER(g_asan_provider); +// GUID must be the same in utils/AddressSanitizerLoggingProvider.wprp +TRACELOGGING_DEFINE_PROVIDER(g_asan_provider, "AddressSanitizerLoggingProvider", + (0x6c6c766d, 0x3846, 0x4e6a, 0xa4, 0xfb, 0x5b, + 0x53, 0x0b, 0xd0, 0xf3, 0xfa)); +#else +#define TraceLoggingUnregister(x) +#endif + +// A macro to tell the compiler that this part of the code cannot be reached, +// if the compiler supports this feature. Since we're using this in +// code that is called when terminating the process, the expansion of the +// macro should not terminate the process to avoid infinite recursion. +#if defined(__clang__) +# define BUILTIN_UNREACHABLE() __builtin_unreachable() +#elif defined(__GNUC__) && \ + (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define BUILTIN_UNREACHABLE() __builtin_unreachable() +#elif defined(_MSC_VER) +# define BUILTIN_UNREACHABLE() __assume(0) +#else +# define BUILTIN_UNREACHABLE() +#endif + +namespace __sanitizer { + +#include "sanitizer_syscall_generic.inc" + +// --------------------- sanitizer_common.h +uptr GetPageSize() { + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwPageSize; +} + +uptr GetMmapGranularity() { + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwAllocationGranularity; +} + +uptr GetMaxUserVirtualAddress() { + SYSTEM_INFO si; + GetSystemInfo(&si); + return (uptr)si.lpMaximumApplicationAddress; +} + +uptr GetMaxVirtualAddress() { + return GetMaxUserVirtualAddress(); +} + +bool FileExists(const char *filename) { + return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES; +} + +uptr internal_getpid() { + return GetProcessId(GetCurrentProcess()); +} + +// In contrast to POSIX, on Windows GetCurrentThreadId() +// returns a system-unique identifier. +tid_t GetTid() { + return GetCurrentThreadId(); +} + +uptr GetThreadSelf() { + return GetTid(); +} + +#if !SANITIZER_GO +void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, + uptr *stack_bottom) { + CHECK(stack_top); + CHECK(stack_bottom); + MEMORY_BASIC_INFORMATION mbi; + CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0); + // FIXME: is it possible for the stack to not be a single allocation? + // Are these values what ASan expects to get (reserved, not committed; + // including stack guard page) ? + *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize; + *stack_bottom = (uptr)mbi.AllocationBase; +} +#endif // #if !SANITIZER_GO + +void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { + void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (rv == 0) + ReportMmapFailureAndDie(size, mem_type, "allocate", + GetLastError(), raw_report); + return rv; +} + +void UnmapOrDie(void *addr, uptr size) { + if (!size || !addr) + return; + + MEMORY_BASIC_INFORMATION mbi; + CHECK(VirtualQuery(addr, &mbi, sizeof(mbi))); + + // MEM_RELEASE can only be used to unmap whole regions previously mapped with + // VirtualAlloc. So we first try MEM_RELEASE since it is better, and if that + // fails try MEM_DECOMMIT. + if (VirtualFree(addr, 0, MEM_RELEASE) == 0) { + if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) { + Report("ERROR: %s failed to " + "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n", + SanitizerToolName, size, size, addr, GetLastError()); + CHECK("unable to unmap" && 0); + } + } +} + +static void *ReturnNullptrOnOOMOrDie(uptr size, const char *mem_type, + const char *mmap_type) { + error_t last_error = GetLastError(); + if (last_error == ERROR_NOT_ENOUGH_MEMORY) + return nullptr; + ReportMmapFailureAndDie(size, mem_type, mmap_type, last_error); +} + +void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { + void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (rv == 0) + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); + return rv; +} + +// We want to map a chunk of address space aligned to 'alignment'. +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type) { + CHECK(IsPowerOfTwo(size)); + CHECK(IsPowerOfTwo(alignment)); + + // Windows will align our allocations to at least 64K. + alignment = Max(alignment, GetMmapGranularity()); + + uptr mapped_addr = + (uptr)VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (!mapped_addr) + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); + + // If we got it right on the first try, return. Otherwise, unmap it and go to + // the slow path. + if (IsAligned(mapped_addr, alignment)) + return (void*)mapped_addr; + if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0) + ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError()); + + // If we didn't get an aligned address, overallocate, find an aligned address, + // unmap, and try to allocate at that aligned address. + int retries = 0; + const int kMaxRetries = 10; + for (; retries < kMaxRetries && + (mapped_addr == 0 || !IsAligned(mapped_addr, alignment)); + retries++) { + // Overallocate size + alignment bytes. + mapped_addr = + (uptr)VirtualAlloc(0, size + alignment, MEM_RESERVE, PAGE_NOACCESS); + if (!mapped_addr) + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); + + // Find the aligned address. + uptr aligned_addr = RoundUpTo(mapped_addr, alignment); + + // Free the overallocation. + if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0) + ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError()); + + // Attempt to allocate exactly the number of bytes we need at the aligned + // address. This may fail for a number of reasons, in which case we continue + // the loop. + mapped_addr = (uptr)VirtualAlloc((void *)aligned_addr, size, + MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + } + + // Fail if we can't make this work quickly. + if (retries == kMaxRetries && mapped_addr == 0) + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); + + return (void *)mapped_addr; +} + +bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { + // FIXME: is this really "NoReserve"? On Win32 this does not matter much, + // but on Win64 it does. + (void)name; // unsupported +#if !SANITIZER_GO && SANITIZER_WINDOWS64 + // On asan/Windows64, use MEM_COMMIT would result in error + // 1455:ERROR_COMMITMENT_LIMIT. + // Asan uses exception handler to commit page on demand. + void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE, PAGE_READWRITE); +#else + void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE); +#endif + if (p == 0) { + Report("ERROR: %s failed to " + "allocate %p (%zd) bytes at %p (error code: %d)\n", + SanitizerToolName, size, size, fixed_addr, GetLastError()); + return false; + } + return true; +} + +bool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, const char *name) { + // FIXME: Windows support large pages too. Might be worth checking + return MmapFixedNoReserve(fixed_addr, size, name); +} + +// Memory space mapped by 'MmapFixedOrDie' must have been reserved by +// 'MmapFixedNoAccess'. +void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) { + void *p = VirtualAlloc((LPVOID)fixed_addr, size, + MEM_COMMIT, PAGE_READWRITE); + if (p == 0) { + char mem_type[30]; + internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", + fixed_addr); + ReportMmapFailureAndDie(size, mem_type, "allocate", GetLastError()); + } + return p; +} + +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, const char *name) { + return reinterpret_cast(MmapFixedOrDieOnFatalError(fixed_addr, size)); +} + +uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size, + const char *name) { + return reinterpret_cast(MmapFixedOrDie(fixed_addr, size)); +} + +void ReservedAddressRange::Unmap(uptr addr, uptr size) { + // Only unmap if it covers the entire range. + CHECK((addr == reinterpret_cast(base_)) && (size == size_)); + // We unmap the whole range, just null out the base. + base_ = nullptr; + size_ = 0; + UnmapOrDie(reinterpret_cast(addr), size); +} + +void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) { + void *p = VirtualAlloc((LPVOID)fixed_addr, size, + MEM_COMMIT, PAGE_READWRITE); + if (p == 0) { + char mem_type[30]; + internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", + fixed_addr); + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); + } + return p; +} + +void *MmapNoReserveOrDie(uptr size, const char *mem_type) { + // FIXME: make this really NoReserve? + return MmapOrDie(size, mem_type); +} + +uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { + base_ = fixed_addr ? MmapFixedNoAccess(fixed_addr, size) : MmapNoAccess(size); + size_ = size; + name_ = name; + (void)os_handle_; // unsupported + return reinterpret_cast(base_); +} + + +void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { + (void)name; // unsupported + void *res = VirtualAlloc((LPVOID)fixed_addr, size, + MEM_RESERVE, PAGE_NOACCESS); + if (res == 0) + Report("WARNING: %s failed to " + "mprotect %p (%zd) bytes at %p (error code: %d)\n", + SanitizerToolName, size, size, fixed_addr, GetLastError()); + return res; +} + +void *MmapNoAccess(uptr size) { + void *res = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_NOACCESS); + if (res == 0) + Report("WARNING: %s failed to " + "mprotect %p (%zd) bytes (error code: %d)\n", + SanitizerToolName, size, size, GetLastError()); + return res; +} + +bool MprotectNoAccess(uptr addr, uptr size) { + DWORD old_protection; + return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection); +} + +void ReleaseMemoryPagesToOS(uptr beg, uptr end) { + // This is almost useless on 32-bits. + // FIXME: add madvise-analog when we move to 64-bits. +} + +void SetShadowRegionHugePageMode(uptr addr, uptr size) { + // FIXME: probably similar to ReleaseMemoryToOS. +} + +bool DontDumpShadowMemory(uptr addr, uptr length) { + // This is almost useless on 32-bits. + // FIXME: add madvise-analog when we move to 64-bits. + return true; +} + +uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, + uptr *largest_gap_found, + uptr *max_occupied_addr) { + uptr address = 0; + while (true) { + MEMORY_BASIC_INFORMATION info; + if (!::VirtualQuery((void*)address, &info, sizeof(info))) + return 0; + + if (info.State == MEM_FREE) { + uptr shadow_address = RoundUpTo((uptr)info.BaseAddress + left_padding, + alignment); + if (shadow_address + size < (uptr)info.BaseAddress + info.RegionSize) + return shadow_address; + } + + // Move to the next region. + address = (uptr)info.BaseAddress + info.RegionSize; + } + return 0; +} + +bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { + MEMORY_BASIC_INFORMATION mbi; + CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi))); + return mbi.Protect == PAGE_NOACCESS && + (uptr)mbi.BaseAddress + mbi.RegionSize >= range_end; +} + +void *MapFileToMemory(const char *file_name, uptr *buff_size) { + UNIMPLEMENTED(); +} + +void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { + UNIMPLEMENTED(); +} + +static const int kMaxEnvNameLength = 128; +static const DWORD kMaxEnvValueLength = 32767; + +namespace { + +struct EnvVariable { + char name[kMaxEnvNameLength]; + char value[kMaxEnvValueLength]; +}; + +} // namespace + +static const int kEnvVariables = 5; +static EnvVariable env_vars[kEnvVariables]; +static int num_env_vars; + +const char *GetEnv(const char *name) { + // Note: this implementation caches the values of the environment variables + // and limits their quantity. + for (int i = 0; i < num_env_vars; i++) { + if (0 == internal_strcmp(name, env_vars[i].name)) + return env_vars[i].value; + } + CHECK_LT(num_env_vars, kEnvVariables); + DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value, + kMaxEnvValueLength); + if (rv > 0 && rv < kMaxEnvValueLength) { + CHECK_LT(internal_strlen(name), kMaxEnvNameLength); + internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength); + num_env_vars++; + return env_vars[num_env_vars - 1].value; + } + return 0; +} + +const char *GetPwd() { + UNIMPLEMENTED(); +} + +u32 GetUid() { + UNIMPLEMENTED(); +} + +namespace { +struct ModuleInfo { + const char *filepath; + uptr base_address; + uptr end_address; +}; + +#if !SANITIZER_GO +int CompareModulesBase(const void *pl, const void *pr) { + const ModuleInfo *l = (const ModuleInfo *)pl, *r = (const ModuleInfo *)pr; + if (l->base_address < r->base_address) + return -1; + return l->base_address > r->base_address; +} +#endif +} // namespace + +#if !SANITIZER_GO +void DumpProcessMap() { + Report("Dumping process modules:\n"); + ListOfModules modules; + modules.init(); + uptr num_modules = modules.size(); + + InternalMmapVector module_infos(num_modules); + for (size_t i = 0; i < num_modules; ++i) { + module_infos[i].filepath = modules[i].full_name(); + module_infos[i].base_address = modules[i].ranges().front()->beg; + module_infos[i].end_address = modules[i].ranges().back()->end; + } + qsort(module_infos.data(), num_modules, sizeof(ModuleInfo), + CompareModulesBase); + + for (size_t i = 0; i < num_modules; ++i) { + const ModuleInfo &mi = module_infos[i]; + if (mi.end_address != 0) { + Printf("\t%p-%p %s\n", mi.base_address, mi.end_address, + mi.filepath[0] ? mi.filepath : "[no name]"); + } else if (mi.filepath[0]) { + Printf("\t??\?-??? %s\n", mi.filepath); + } else { + Printf("\t???\n"); + } + } +} +#endif + +void PrintModuleMap() { } + +void DisableCoreDumperIfNecessary() { + // Do nothing. +} + +void ReExec() { + UNIMPLEMENTED(); +} + +void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} + +bool StackSizeIsUnlimited() { + UNIMPLEMENTED(); +} + +void SetStackSizeLimitInBytes(uptr limit) { + UNIMPLEMENTED(); +} + +bool AddressSpaceIsUnlimited() { + UNIMPLEMENTED(); +} + +void SetAddressSpaceUnlimited() { + UNIMPLEMENTED(); +} + +bool IsPathSeparator(const char c) { + return c == '\\' || c == '/'; +} + +static bool IsAlpha(char c) { + c = ToLower(c); + return c >= 'a' && c <= 'z'; +} + +bool IsAbsolutePath(const char *path) { + return path != nullptr && IsAlpha(path[0]) && path[1] == ':' && + IsPathSeparator(path[2]); +} + +void SleepForSeconds(int seconds) { + Sleep(seconds * 1000); +} + +void SleepForMillis(int millis) { + Sleep(millis); +} + +u64 NanoTime() { + static LARGE_INTEGER frequency = {}; + LARGE_INTEGER counter; + if (UNLIKELY(frequency.QuadPart == 0)) { + QueryPerformanceFrequency(&frequency); + CHECK_NE(frequency.QuadPart, 0); + } + QueryPerformanceCounter(&counter); + counter.QuadPart *= 1000ULL * 1000000ULL; + counter.QuadPart /= frequency.QuadPart; + return counter.QuadPart; +} + +u64 MonotonicNanoTime() { return NanoTime(); } + +void Abort() { + internal__exit(3); +} + +#if !SANITIZER_GO +// Read the file to extract the ImageBase field from the PE header. If ASLR is +// disabled and this virtual address is available, the loader will typically +// load the image at this address. Therefore, we call it the preferred base. Any +// addresses in the DWARF typically assume that the object has been loaded at +// this address. +static uptr GetPreferredBase(const char *modname) { + fd_t fd = OpenFile(modname, RdOnly, nullptr); + if (fd == kInvalidFd) + return 0; + FileCloser closer(fd); + + // Read just the DOS header. + IMAGE_DOS_HEADER dos_header; + uptr bytes_read; + if (!ReadFromFile(fd, &dos_header, sizeof(dos_header), &bytes_read) || + bytes_read != sizeof(dos_header)) + return 0; + + // The file should start with the right signature. + if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) + return 0; + + // The layout at e_lfanew is: + // "PE\0\0" + // IMAGE_FILE_HEADER + // IMAGE_OPTIONAL_HEADER + // Seek to e_lfanew and read all that data. + char buf[4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER)]; + if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) == + INVALID_SET_FILE_POINTER) + return 0; + if (!ReadFromFile(fd, &buf[0], sizeof(buf), &bytes_read) || + bytes_read != sizeof(buf)) + return 0; + + // Check for "PE\0\0" before the PE header. + char *pe_sig = &buf[0]; + if (internal_memcmp(pe_sig, "PE\0\0", 4) != 0) + return 0; + + // Skip over IMAGE_FILE_HEADER. We could do more validation here if we wanted. + IMAGE_OPTIONAL_HEADER *pe_header = + (IMAGE_OPTIONAL_HEADER *)(pe_sig + 4 + sizeof(IMAGE_FILE_HEADER)); + + // Check for more magic in the PE header. + if (pe_header->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) + return 0; + + // Finally, return the ImageBase. + return (uptr)pe_header->ImageBase; +} + +void ListOfModules::init() { + clearOrInit(); + HANDLE cur_process = GetCurrentProcess(); + + // Query the list of modules. Start by assuming there are no more than 256 + // modules and retry if that's not sufficient. + HMODULE *hmodules = 0; + uptr modules_buffer_size = sizeof(HMODULE) * 256; + DWORD bytes_required; + while (!hmodules) { + hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__); + CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size, + &bytes_required)); + if (bytes_required > modules_buffer_size) { + // Either there turned out to be more than 256 hmodules, or new hmodules + // could have loaded since the last try. Retry. + UnmapOrDie(hmodules, modules_buffer_size); + hmodules = 0; + modules_buffer_size = bytes_required; + } + } + + // |num_modules| is the number of modules actually present, + size_t num_modules = bytes_required / sizeof(HMODULE); + for (size_t i = 0; i < num_modules; ++i) { + HMODULE handle = hmodules[i]; + MODULEINFO mi; + if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi))) + continue; + + // Get the UTF-16 path and convert to UTF-8. + wchar_t modname_utf16[kMaxPathLength]; + int modname_utf16_len = + GetModuleFileNameW(handle, modname_utf16, kMaxPathLength); + if (modname_utf16_len == 0) + modname_utf16[0] = '\0'; + char module_name[kMaxPathLength]; + int module_name_len = + ::WideCharToMultiByte(CP_UTF8, 0, modname_utf16, modname_utf16_len + 1, + &module_name[0], kMaxPathLength, NULL, NULL); + module_name[module_name_len] = '\0'; + + uptr base_address = (uptr)mi.lpBaseOfDll; + uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage; + + // Adjust the base address of the module so that we get a VA instead of an + // RVA when computing the module offset. This helps llvm-symbolizer find the + // right DWARF CU. In the common case that the image is loaded at it's + // preferred address, we will now print normal virtual addresses. + uptr preferred_base = GetPreferredBase(&module_name[0]); + uptr adjusted_base = base_address - preferred_base; + + LoadedModule cur_module; + cur_module.set(module_name, adjusted_base); + // We add the whole module as one single address range. + cur_module.addAddressRange(base_address, end_address, /*executable*/ true, + /*writable*/ true); + modules_.push_back(cur_module); + } + UnmapOrDie(hmodules, modules_buffer_size); +} + +void ListOfModules::fallbackInit() { clear(); } + +// We can't use atexit() directly at __asan_init time as the CRT is not fully +// initialized at this point. Place the functions into a vector and use +// atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers). +InternalMmapVectorNoCtor atexit_functions; + +int Atexit(void (*function)(void)) { + atexit_functions.push_back(function); + return 0; +} + +static int RunAtexit() { + TraceLoggingUnregister(g_asan_provider); + int ret = 0; + for (uptr i = 0; i < atexit_functions.size(); ++i) { + ret |= atexit(atexit_functions[i]); + } + return ret; +} + +#pragma section(".CRT$XID", long, read) +__declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit; +#endif + +// ------------------ sanitizer_libc.h +fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) { + // FIXME: Use the wide variants to handle Unicode filenames. + fd_t res; + if (mode == RdOnly) { + res = CreateFileA(filename, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + } else if (mode == WrOnly) { + res = CreateFileA(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, nullptr); + } else { + UNIMPLEMENTED(); + } + CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd); + CHECK(res != kStderrFd || kStderrFd == kInvalidFd); + if (res == kInvalidFd && last_error) + *last_error = GetLastError(); + return res; +} + +void CloseFile(fd_t fd) { + CloseHandle(fd); +} + +bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, + error_t *error_p) { + CHECK(fd != kInvalidFd); + + // bytes_read can't be passed directly to ReadFile: + // uptr is unsigned long long on 64-bit Windows. + unsigned long num_read_long; + + bool success = ::ReadFile(fd, buff, buff_size, &num_read_long, nullptr); + if (!success && error_p) + *error_p = GetLastError(); + if (bytes_read) + *bytes_read = num_read_long; + return success; +} + +bool SupportsColoredOutput(fd_t fd) { + // FIXME: support colored output. + return false; +} + +bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, + error_t *error_p) { + CHECK(fd != kInvalidFd); + + // Handle null optional parameters. + error_t dummy_error; + error_p = error_p ? error_p : &dummy_error; + uptr dummy_bytes_written; + bytes_written = bytes_written ? bytes_written : &dummy_bytes_written; + + // Initialize output parameters in case we fail. + *error_p = 0; + *bytes_written = 0; + + // Map the conventional Unix fds 1 and 2 to Windows handles. They might be + // closed, in which case this will fail. + if (fd == kStdoutFd || fd == kStderrFd) { + fd = GetStdHandle(fd == kStdoutFd ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); + if (fd == 0) { + *error_p = ERROR_INVALID_HANDLE; + return false; + } + } + + DWORD bytes_written_32; + if (!WriteFile(fd, buff, buff_size, &bytes_written_32, 0)) { + *error_p = GetLastError(); + return false; + } else { + *bytes_written = bytes_written_32; + return true; + } +} + +uptr internal_sched_yield() { + Sleep(0); + return 0; +} + +void internal__exit(int exitcode) { + TraceLoggingUnregister(g_asan_provider); + // ExitProcess runs some finalizers, so use TerminateProcess to avoid that. + // The debugger doesn't stop on TerminateProcess like it does on ExitProcess, + // so add our own breakpoint here. + if (::IsDebuggerPresent()) + __debugbreak(); + TerminateProcess(GetCurrentProcess(), exitcode); + BUILTIN_UNREACHABLE(); +} + +uptr internal_ftruncate(fd_t fd, uptr size) { + UNIMPLEMENTED(); +} + +uptr GetRSS() { + PROCESS_MEMORY_COUNTERS counters; + if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) + return 0; + return counters.WorkingSetSize; +} + +void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; } +void internal_join_thread(void *th) { } + +// ---------------------- BlockingMutex ---------------- {{{1 + +BlockingMutex::BlockingMutex() { + CHECK(sizeof(SRWLOCK) <= sizeof(opaque_storage_)); + internal_memset(this, 0, sizeof(*this)); +} + +void BlockingMutex::Lock() { + AcquireSRWLockExclusive((PSRWLOCK)opaque_storage_); + CHECK_EQ(owner_, 0); + owner_ = GetThreadSelf(); +} + +void BlockingMutex::Unlock() { + CheckLocked(); + owner_ = 0; + ReleaseSRWLockExclusive((PSRWLOCK)opaque_storage_); +} + +void BlockingMutex::CheckLocked() { + CHECK_EQ(owner_, GetThreadSelf()); +} + +uptr GetTlsSize() { + return 0; +} + +void InitTlsSize() { +} + +void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, + uptr *tls_addr, uptr *tls_size) { +#if SANITIZER_GO + *stk_addr = 0; + *stk_size = 0; + *tls_addr = 0; + *tls_size = 0; +#else + uptr stack_top, stack_bottom; + GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); + *stk_addr = stack_bottom; + *stk_size = stack_top - stack_bottom; + *tls_addr = 0; + *tls_size = 0; +#endif +} + +void ReportFile::Write(const char *buffer, uptr length) { + SpinMutexLock l(mu); + ReopenIfNecessary(); + if (!WriteToFile(fd, buffer, length)) { + // stderr may be closed, but we may be able to print to the debugger + // instead. This is the case when launching a program from Visual Studio, + // and the following routine should write to its console. + OutputDebugStringA(buffer); + } +} + +void SetAlternateSignalStack() { + // FIXME: Decide what to do on Windows. +} + +void UnsetAlternateSignalStack() { + // FIXME: Decide what to do on Windows. +} + +void InstallDeadlySignalHandlers(SignalHandlerType handler) { + (void)handler; + // FIXME: Decide what to do on Windows. +} + +HandleSignalMode GetHandleSignalMode(int signum) { + // FIXME: Decide what to do on Windows. + return kHandleSignalNo; +} + +// Check based on flags if we should handle this exception. +bool IsHandledDeadlyException(DWORD exceptionCode) { + switch (exceptionCode) { + case EXCEPTION_ACCESS_VIOLATION: + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + case EXCEPTION_STACK_OVERFLOW: + case EXCEPTION_DATATYPE_MISALIGNMENT: + case EXCEPTION_IN_PAGE_ERROR: + return common_flags()->handle_segv; + case EXCEPTION_ILLEGAL_INSTRUCTION: + case EXCEPTION_PRIV_INSTRUCTION: + case EXCEPTION_BREAKPOINT: + return common_flags()->handle_sigill; + case EXCEPTION_FLT_DENORMAL_OPERAND: + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_FLT_INEXACT_RESULT: + case EXCEPTION_FLT_INVALID_OPERATION: + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_FLT_STACK_CHECK: + case EXCEPTION_FLT_UNDERFLOW: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_OVERFLOW: + return common_flags()->handle_sigfpe; + } + return false; +} + +bool IsAccessibleMemoryRange(uptr beg, uptr size) { + SYSTEM_INFO si; + GetNativeSystemInfo(&si); + uptr page_size = si.dwPageSize; + uptr page_mask = ~(page_size - 1); + + for (uptr page = beg & page_mask, end = (beg + size - 1) & page_mask; + page <= end;) { + MEMORY_BASIC_INFORMATION info; + if (VirtualQuery((LPCVOID)page, &info, sizeof(info)) != sizeof(info)) + return false; + + if (info.Protect == 0 || info.Protect == PAGE_NOACCESS || + info.Protect == PAGE_EXECUTE) + return false; + + if (info.RegionSize == 0) + return false; + + page += info.RegionSize; + } + + return true; +} + +bool SignalContext::IsStackOverflow() const { + return (DWORD)GetType() == EXCEPTION_STACK_OVERFLOW; +} + +void SignalContext::InitPcSpBp() { + EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; + CONTEXT *context_record = (CONTEXT *)context; + + pc = (uptr)exception_record->ExceptionAddress; +#ifdef _WIN64 + bp = (uptr)context_record->Rbp; + sp = (uptr)context_record->Rsp; +#else + bp = (uptr)context_record->Ebp; + sp = (uptr)context_record->Esp; +#endif +} + +uptr SignalContext::GetAddress() const { + EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; + return exception_record->ExceptionInformation[1]; +} + +bool SignalContext::IsMemoryAccess() const { + return GetWriteFlag() != SignalContext::UNKNOWN; +} + +bool SignalContext::IsTrueFaultingAddress() const { + // FIXME: Provide real implementation for this. See Linux and Mac variants. + return IsMemoryAccess(); +} + +SignalContext::WriteFlag SignalContext::GetWriteFlag() const { + EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; + // The contents of this array are documented at + // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx + // The first element indicates read as 0, write as 1, or execute as 8. The + // second element is the faulting address. + switch (exception_record->ExceptionInformation[0]) { + case 0: + return SignalContext::READ; + case 1: + return SignalContext::WRITE; + case 8: + return SignalContext::UNKNOWN; + } + return SignalContext::UNKNOWN; +} + +void SignalContext::DumpAllRegisters(void *context) { + // FIXME: Implement this. +} + +int SignalContext::GetType() const { + return static_cast(siginfo)->ExceptionCode; +} + +const char *SignalContext::Describe() const { + unsigned code = GetType(); + // Get the string description of the exception if this is a known deadly + // exception. + switch (code) { + case EXCEPTION_ACCESS_VIOLATION: + return "access-violation"; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + return "array-bounds-exceeded"; + case EXCEPTION_STACK_OVERFLOW: + return "stack-overflow"; + case EXCEPTION_DATATYPE_MISALIGNMENT: + return "datatype-misalignment"; + case EXCEPTION_IN_PAGE_ERROR: + return "in-page-error"; + case EXCEPTION_ILLEGAL_INSTRUCTION: + return "illegal-instruction"; + case EXCEPTION_PRIV_INSTRUCTION: + return "priv-instruction"; + case EXCEPTION_BREAKPOINT: + return "breakpoint"; + case EXCEPTION_FLT_DENORMAL_OPERAND: + return "flt-denormal-operand"; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + return "flt-divide-by-zero"; + case EXCEPTION_FLT_INEXACT_RESULT: + return "flt-inexact-result"; + case EXCEPTION_FLT_INVALID_OPERATION: + return "flt-invalid-operation"; + case EXCEPTION_FLT_OVERFLOW: + return "flt-overflow"; + case EXCEPTION_FLT_STACK_CHECK: + return "flt-stack-check"; + case EXCEPTION_FLT_UNDERFLOW: + return "flt-underflow"; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + return "int-divide-by-zero"; + case EXCEPTION_INT_OVERFLOW: + return "int-overflow"; + } + return "unknown exception"; +} + +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { + // FIXME: Actually implement this function. + CHECK_GT(buf_len, 0); + buf[0] = 0; + return 0; +} + +uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { + return ReadBinaryName(buf, buf_len); +} + +void CheckVMASize() { + // Do nothing. +} + +void InitializePlatformEarly() { + // Do nothing. +} + +void MaybeReexec() { + // No need to re-exec on Windows. +} + +void CheckASLR() { + // Do nothing +} + +void CheckMPROTECT() { + // Do nothing +} + +char **GetArgv() { + // FIXME: Actually implement this function. + return 0; +} + +char **GetEnviron() { + // FIXME: Actually implement this function. + return 0; +} + +pid_t StartSubprocess(const char *program, const char *const argv[], + fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { + // FIXME: implement on this platform + // Should be implemented based on + // SymbolizerProcess::StarAtSymbolizerSubprocess + // from lib/sanitizer_common/sanitizer_symbolizer_win.cpp. + return -1; +} + +bool IsProcessRunning(pid_t pid) { + // FIXME: implement on this platform. + return false; +} + +int WaitForProcess(pid_t pid) { return -1; } + +// FIXME implement on this platform. +void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { } + +void CheckNoDeepBind(const char *filename, int flag) { + // Do nothing. +} + +// FIXME: implement on this platform. +bool GetRandom(void *buffer, uptr length, bool blocking) { + UNIMPLEMENTED(); +} + +u32 GetNumberOfCPUs() { + SYSTEM_INFO sysinfo = {}; + GetNativeSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; +} + +#if SANITIZER_WIN_TRACE +// TODO(mcgov): Rename this project-wide to PlatformLogInit +void AndroidLogInit(void) { + HRESULT hr = TraceLoggingRegister(g_asan_provider); + if (!SUCCEEDED(hr)) + return; +} + +void SetAbortMessage(const char *) {} + +void LogFullErrorReport(const char *buffer) { + if (common_flags()->log_to_syslog) { + InternalMmapVector filename; + DWORD filename_length = 0; + do { + filename.resize(filename.size() + 0x100); + filename_length = + GetModuleFileNameW(NULL, filename.begin(), filename.size()); + } while (filename_length >= filename.size()); + TraceLoggingWrite(g_asan_provider, "AsanReportEvent", + TraceLoggingValue(filename.begin(), "ExecutableName"), + TraceLoggingValue(buffer, "AsanReportContents")); + } +} +#endif // SANITIZER_WIN_TRACE + +} // namespace __sanitizer + +#endif // _WIN32 diff --git a/lib/sanitizer_common/sanitizer_win_defs.h b/lib/sanitizer_common/sanitizer_win_defs.h index bcd94a08dc44..bfe38a332367 100644 --- a/lib/sanitizer_common/sanitizer_win_defs.h +++ b/lib/sanitizer_common/sanitizer_win_defs.h @@ -43,6 +43,8 @@ #define STRINGIFY_(A) #A #define STRINGIFY(A) STRINGIFY_(A) +#if !SANITIZER_GO + // ----------------- A workaround for the absence of weak symbols -------------- // We don't have a direct equivalent of weak symbols when using MSVC, but we can // use the /alternatename directive to tell the linker to default a specific @@ -158,5 +160,15 @@ // return a >= b; // } // + +#else // SANITIZER_GO + +// Go neither needs nor wants weak references. +// The shenanigans above don't work for gcc. +# define WIN_WEAK_EXPORT_DEF(ReturnType, Name, ...) \ + extern "C" ReturnType Name(__VA_ARGS__) + +#endif // SANITIZER_GO + #endif // SANITIZER_WINDOWS #endif // SANITIZER_WIN_DEFS_H diff --git a/lib/sanitizer_common/sanitizer_win_dll_thunk.cc b/lib/sanitizer_common/sanitizer_win_dll_thunk.cc deleted file mode 100644 index 5a947916de0a..000000000000 --- a/lib/sanitizer_common/sanitizer_win_dll_thunk.cc +++ /dev/null @@ -1,101 +0,0 @@ -//===-- sanitizer_win_dll_thunk.cc ----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// This file defines a family of thunks that should be statically linked into -// the DLLs that have instrumentation in order to delegate the calls to the -// shared runtime that lives in the main binary. -// See https://github.com/google/sanitizers/issues/209 for the details. -//===----------------------------------------------------------------------===// - -#ifdef SANITIZER_DLL_THUNK -#include "sanitizer_win_defs.h" -#include "sanitizer_win_dll_thunk.h" -#include "interception/interception.h" - -extern "C" { -void *WINAPI GetModuleHandleA(const char *module_name); -void abort(); -} - -namespace __sanitizer { -uptr dllThunkGetRealAddrOrDie(const char *name) { - uptr ret = - __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name); - if (!ret) - abort(); - return ret; -} - -int dllThunkIntercept(const char* main_function, uptr dll_function) { - uptr wrapper = dllThunkGetRealAddrOrDie(main_function); - if (!__interception::OverrideFunction(dll_function, wrapper, 0)) - abort(); - return 0; -} - -int dllThunkInterceptWhenPossible(const char* main_function, - const char* default_function, uptr dll_function) { - uptr wrapper = __interception::InternalGetProcAddress( - (void *)GetModuleHandleA(0), main_function); - if (!wrapper) - wrapper = dllThunkGetRealAddrOrDie(default_function); - if (!__interception::OverrideFunction(dll_function, wrapper, 0)) - abort(); - return 0; -} -} // namespace __sanitizer - -// Include Sanitizer Common interface. -#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) -#include "sanitizer_common_interface.inc" - -#pragma section(".DLLTH$A", read) // NOLINT -#pragma section(".DLLTH$Z", read) // NOLINT - -typedef void (*DllThunkCB)(); -extern "C" { -__declspec(allocate(".DLLTH$A")) DllThunkCB __start_dll_thunk; -__declspec(allocate(".DLLTH$Z")) DllThunkCB __stop_dll_thunk; -} - -// Disable compiler warnings that show up if we declare our own version -// of a compiler intrinsic (e.g. strlen). -#pragma warning(disable: 4391) -#pragma warning(disable: 4392) - -extern "C" int __dll_thunk_init() { - static bool flag = false; - // __dll_thunk_init is expected to be called by only one thread. - if (flag) return 0; - flag = true; - - for (DllThunkCB *it = &__start_dll_thunk; it < &__stop_dll_thunk; ++it) - if (*it) - (*it)(); - - // In DLLs, the callbacks are expected to return 0, - // otherwise CRT initialization fails. - return 0; -} - -// We want to call dll_thunk_init before C/C++ initializers / constructors are -// executed, otherwise functions like memset might be invoked. -#pragma section(".CRT$XIB", long, read) // NOLINT -__declspec(allocate(".CRT$XIB")) int (*__dll_thunk_preinit)() = - __dll_thunk_init; - -static void WINAPI dll_thunk_thread_init(void *mod, unsigned long reason, - void *reserved) { - if (reason == /*DLL_PROCESS_ATTACH=*/1) __dll_thunk_init(); -} - -#pragma section(".CRT$XLAB", long, read) // NOLINT -__declspec(allocate(".CRT$XLAB")) void (WINAPI *__dll_thunk_tls_init)(void *, - unsigned long, void *) = dll_thunk_thread_init; - -#endif // SANITIZER_DLL_THUNK diff --git a/lib/sanitizer_common/sanitizer_win_dll_thunk.cpp b/lib/sanitizer_common/sanitizer_win_dll_thunk.cpp new file mode 100644 index 000000000000..1562c161a762 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_win_dll_thunk.cpp @@ -0,0 +1,101 @@ +//===-- sanitizer_win_dll_thunk.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// This file defines a family of thunks that should be statically linked into +// the DLLs that have instrumentation in order to delegate the calls to the +// shared runtime that lives in the main binary. +// See https://github.com/google/sanitizers/issues/209 for the details. +//===----------------------------------------------------------------------===// + +#ifdef SANITIZER_DLL_THUNK +#include "sanitizer_win_defs.h" +#include "sanitizer_win_dll_thunk.h" +#include "interception/interception.h" + +extern "C" { +void *WINAPI GetModuleHandleA(const char *module_name); +void abort(); +} + +namespace __sanitizer { +uptr dllThunkGetRealAddrOrDie(const char *name) { + uptr ret = + __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name); + if (!ret) + abort(); + return ret; +} + +int dllThunkIntercept(const char* main_function, uptr dll_function) { + uptr wrapper = dllThunkGetRealAddrOrDie(main_function); + if (!__interception::OverrideFunction(dll_function, wrapper, 0)) + abort(); + return 0; +} + +int dllThunkInterceptWhenPossible(const char* main_function, + const char* default_function, uptr dll_function) { + uptr wrapper = __interception::InternalGetProcAddress( + (void *)GetModuleHandleA(0), main_function); + if (!wrapper) + wrapper = dllThunkGetRealAddrOrDie(default_function); + if (!__interception::OverrideFunction(dll_function, wrapper, 0)) + abort(); + return 0; +} +} // namespace __sanitizer + +// Include Sanitizer Common interface. +#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name) +#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) +#include "sanitizer_common_interface.inc" + +#pragma section(".DLLTH$A", read) +#pragma section(".DLLTH$Z", read) + +typedef void (*DllThunkCB)(); +extern "C" { +__declspec(allocate(".DLLTH$A")) DllThunkCB __start_dll_thunk; +__declspec(allocate(".DLLTH$Z")) DllThunkCB __stop_dll_thunk; +} + +// Disable compiler warnings that show up if we declare our own version +// of a compiler intrinsic (e.g. strlen). +#pragma warning(disable: 4391) +#pragma warning(disable: 4392) + +extern "C" int __dll_thunk_init() { + static bool flag = false; + // __dll_thunk_init is expected to be called by only one thread. + if (flag) return 0; + flag = true; + + for (DllThunkCB *it = &__start_dll_thunk; it < &__stop_dll_thunk; ++it) + if (*it) + (*it)(); + + // In DLLs, the callbacks are expected to return 0, + // otherwise CRT initialization fails. + return 0; +} + +// We want to call dll_thunk_init before C/C++ initializers / constructors are +// executed, otherwise functions like memset might be invoked. +#pragma section(".CRT$XIB", long, read) +__declspec(allocate(".CRT$XIB")) int (*__dll_thunk_preinit)() = + __dll_thunk_init; + +static void WINAPI dll_thunk_thread_init(void *mod, unsigned long reason, + void *reserved) { + if (reason == /*DLL_PROCESS_ATTACH=*/1) __dll_thunk_init(); +} + +#pragma section(".CRT$XLAB", long, read) +__declspec(allocate(".CRT$XLAB")) void (WINAPI *__dll_thunk_tls_init)(void *, + unsigned long, void *) = dll_thunk_thread_init; + +#endif // SANITIZER_DLL_THUNK diff --git a/lib/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cc b/lib/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cc deleted file mode 100644 index 89756f1b70af..000000000000 --- a/lib/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cc +++ /dev/null @@ -1,26 +0,0 @@ -//===-- santizer_win_dynamic_runtime_thunk.cc -----------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines things that need to be present in the application modules -// to interact with Sanitizer Common, when it is included in a dll. -// -//===----------------------------------------------------------------------===// -#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK -#define SANITIZER_IMPORT_INTERFACE 1 -#include "sanitizer_win_defs.h" -// Define weak alias for all weak functions imported from sanitizer common. -#define INTERFACE_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name) -#include "sanitizer_common_interface.inc" -#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK - -namespace __sanitizer { -// Add one, otherwise unused, external symbol to this object file so that the -// Visual C++ linker includes it and reads the .drective section. -void ForceWholeArchiveIncludeForSanitizerCommon() {} -} diff --git a/lib/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cpp b/lib/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cpp new file mode 100644 index 000000000000..87c032c6e61b --- /dev/null +++ b/lib/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cpp @@ -0,0 +1,26 @@ +//===-- santizer_win_dynamic_runtime_thunk.cpp ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines things that need to be present in the application modules +// to interact with Sanitizer Common, when it is included in a dll. +// +//===----------------------------------------------------------------------===// +#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK +#define SANITIZER_IMPORT_INTERFACE 1 +#include "sanitizer_win_defs.h" +// Define weak alias for all weak functions imported from sanitizer common. +#define INTERFACE_FUNCTION(Name) +#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name) +#include "sanitizer_common_interface.inc" +#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK + +namespace __sanitizer { +// Add one, otherwise unused, external symbol to this object file so that the +// Visual C++ linker includes it and reads the .drective section. +void ForceWholeArchiveIncludeForSanitizerCommon() {} +} diff --git a/lib/sanitizer_common/sanitizer_win_weak_interception.cc b/lib/sanitizer_common/sanitizer_win_weak_interception.cc deleted file mode 100644 index b1ac44d75ceb..000000000000 --- a/lib/sanitizer_common/sanitizer_win_weak_interception.cc +++ /dev/null @@ -1,93 +0,0 @@ -//===-- sanitizer_win_weak_interception.cc --------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// This module should be included in the sanitizer when it is implemented as a -// shared library on Windows (dll), in order to delegate the calls of weak -// functions to the implementation in the main executable when a strong -// definition is provided. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_WINDOWS && SANITIZER_DYNAMIC -#include "sanitizer_win_weak_interception.h" -#include "sanitizer_allocator_interface.h" -#include "sanitizer_interface_internal.h" -#include "sanitizer_win_defs.h" -#include "interception/interception.h" - -extern "C" { -void *WINAPI GetModuleHandleA(const char *module_name); -void abort(); -} - -namespace __sanitizer { -// Try to get a pointer to real_function in the main module and override -// dll_function with that pointer. If the function isn't found, nothing changes. -int interceptWhenPossible(uptr dll_function, const char *real_function) { - uptr real = __interception::InternalGetProcAddress( - (void *)GetModuleHandleA(0), real_function); - if (real && !__interception::OverrideFunction((uptr)dll_function, real, 0)) - abort(); - return 0; -} -} // namespace __sanitizer - -// Declare weak hooks. -extern "C" { -void __sanitizer_weak_hook_memcmp(uptr called_pc, const void *s1, - const void *s2, uptr n, int result); -void __sanitizer_weak_hook_strcmp(uptr called_pc, const char *s1, - const char *s2, int result); -void __sanitizer_weak_hook_strncmp(uptr called_pc, const char *s1, - const char *s2, uptr n, int result); -void __sanitizer_weak_hook_strstr(uptr called_pc, const char *s1, - const char *s2, char *result); -} - -// Include Sanitizer Common interface. -#define INTERFACE_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) -#include "sanitizer_common_interface.inc" - -#pragma section(".WEAK$A", read) // NOLINT -#pragma section(".WEAK$Z", read) // NOLINT - -typedef void (*InterceptCB)(); -extern "C" { -__declspec(allocate(".WEAK$A")) InterceptCB __start_weak_list; -__declspec(allocate(".WEAK$Z")) InterceptCB __stop_weak_list; -} - -static int weak_intercept_init() { - static bool flag = false; - // weak_interception_init is expected to be called by only one thread. - if (flag) return 0; - flag = true; - - for (InterceptCB *it = &__start_weak_list; it < &__stop_weak_list; ++it) - if (*it) - (*it)(); - - // In DLLs, the callbacks are expected to return 0, - // otherwise CRT initialization fails. - return 0; -} - -#pragma section(".CRT$XIB", long, read) // NOLINT -__declspec(allocate(".CRT$XIB")) int (*__weak_intercept_preinit)() = - weak_intercept_init; - -static void WINAPI weak_intercept_thread_init(void *mod, unsigned long reason, - void *reserved) { - if (reason == /*DLL_PROCESS_ATTACH=*/1) weak_intercept_init(); -} - -#pragma section(".CRT$XLAB", long, read) // NOLINT -__declspec(allocate(".CRT$XLAB")) void(WINAPI *__weak_intercept_tls_init)( - void *, unsigned long, void *) = weak_intercept_thread_init; - -#endif // SANITIZER_WINDOWS && SANITIZER_DYNAMIC diff --git a/lib/sanitizer_common/sanitizer_win_weak_interception.cpp b/lib/sanitizer_common/sanitizer_win_weak_interception.cpp new file mode 100644 index 000000000000..b14bbf76d9a7 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_win_weak_interception.cpp @@ -0,0 +1,94 @@ +//===-- sanitizer_win_weak_interception.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// This module should be included in the sanitizer when it is implemented as a +// shared library on Windows (dll), in order to delegate the calls of weak +// functions to the implementation in the main executable when a strong +// definition is provided. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS && SANITIZER_DYNAMIC +#include "sanitizer_win_weak_interception.h" +#include "sanitizer_allocator_interface.h" +#include "sanitizer_interface_internal.h" +#include "sanitizer_win_defs.h" +#include "interception/interception.h" + +extern "C" { +void *WINAPI GetModuleHandleA(const char *module_name); +void abort(); +} + +namespace __sanitizer { +// Try to get a pointer to real_function in the main module and override +// dll_function with that pointer. If the function isn't found, nothing changes. +int interceptWhenPossible(uptr dll_function, const char *real_function) { + uptr real = __interception::InternalGetProcAddress( + (void *)GetModuleHandleA(0), real_function); + if (real && !__interception::OverrideFunction((uptr)dll_function, real, 0)) + abort(); + return 0; +} +} // namespace __sanitizer + +// Declare weak hooks. +extern "C" { +void __sanitizer_on_print(const char *str); +void __sanitizer_weak_hook_memcmp(uptr called_pc, const void *s1, + const void *s2, uptr n, int result); +void __sanitizer_weak_hook_strcmp(uptr called_pc, const char *s1, + const char *s2, int result); +void __sanitizer_weak_hook_strncmp(uptr called_pc, const char *s1, + const char *s2, uptr n, int result); +void __sanitizer_weak_hook_strstr(uptr called_pc, const char *s1, + const char *s2, char *result); +} + +// Include Sanitizer Common interface. +#define INTERFACE_FUNCTION(Name) +#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) +#include "sanitizer_common_interface.inc" + +#pragma section(".WEAK$A", read) +#pragma section(".WEAK$Z", read) + +typedef void (*InterceptCB)(); +extern "C" { +__declspec(allocate(".WEAK$A")) InterceptCB __start_weak_list; +__declspec(allocate(".WEAK$Z")) InterceptCB __stop_weak_list; +} + +static int weak_intercept_init() { + static bool flag = false; + // weak_interception_init is expected to be called by only one thread. + if (flag) return 0; + flag = true; + + for (InterceptCB *it = &__start_weak_list; it < &__stop_weak_list; ++it) + if (*it) + (*it)(); + + // In DLLs, the callbacks are expected to return 0, + // otherwise CRT initialization fails. + return 0; +} + +#pragma section(".CRT$XIB", long, read) +__declspec(allocate(".CRT$XIB")) int (*__weak_intercept_preinit)() = + weak_intercept_init; + +static void WINAPI weak_intercept_thread_init(void *mod, unsigned long reason, + void *reserved) { + if (reason == /*DLL_PROCESS_ATTACH=*/1) weak_intercept_init(); +} + +#pragma section(".CRT$XLAB", long, read) +__declspec(allocate(".CRT$XLAB")) void(WINAPI *__weak_intercept_tls_init)( + void *, unsigned long, void *) = weak_intercept_thread_init; + +#endif // SANITIZER_WINDOWS && SANITIZER_DYNAMIC diff --git a/lib/sanitizer_common/symbolizer/sanitizer_symbolize.cc b/lib/sanitizer_common/symbolizer/sanitizer_symbolize.cc deleted file mode 100644 index 8150b7a09a0e..000000000000 --- a/lib/sanitizer_common/symbolizer/sanitizer_symbolize.cc +++ /dev/null @@ -1,80 +0,0 @@ -//===-- sanitizer_symbolize.cc ----------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Implementation of weak hooks from sanitizer_symbolizer_posix_libcdep.cc. -// -//===----------------------------------------------------------------------===// - -#include -#include - -#include "llvm/DebugInfo/Symbolize/DIPrinter.h" -#include "llvm/DebugInfo/Symbolize/Symbolize.h" - -static llvm::symbolize::LLVMSymbolizer *getDefaultSymbolizer() { - static llvm::symbolize::LLVMSymbolizer *DefaultSymbolizer = - new llvm::symbolize::LLVMSymbolizer(); - return DefaultSymbolizer; -} - -namespace __sanitizer { -int internal_snprintf(char *buffer, unsigned long length, const char *format, - ...); -} // namespace __sanitizer - -extern "C" { - -typedef uint64_t u64; - -bool __sanitizer_symbolize_code(const char *ModuleName, uint64_t ModuleOffset, - char *Buffer, int MaxLength) { - std::string Result; - { - llvm::raw_string_ostream OS(Result); - llvm::symbolize::DIPrinter Printer(OS); - // TODO: it is neccessary to set proper SectionIndex here. - // object::SectionedAddress::UndefSection works for only absolute addresses. - auto ResOrErr = getDefaultSymbolizer()->symbolizeInlinedCode( - ModuleName, - {ModuleOffset, llvm::object::SectionedAddress::UndefSection}); - Printer << (ResOrErr ? ResOrErr.get() : llvm::DIInliningInfo()); - } - return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s", - Result.c_str()) < MaxLength; -} - -bool __sanitizer_symbolize_data(const char *ModuleName, uint64_t ModuleOffset, - char *Buffer, int MaxLength) { - std::string Result; - { - llvm::raw_string_ostream OS(Result); - llvm::symbolize::DIPrinter Printer(OS); - // TODO: it is neccessary to set proper SectionIndex here. - // object::SectionedAddress::UndefSection works for only absolute addresses. - auto ResOrErr = getDefaultSymbolizer()->symbolizeData( - ModuleName, - {ModuleOffset, llvm::object::SectionedAddress::UndefSection}); - Printer << (ResOrErr ? ResOrErr.get() : llvm::DIGlobal()); - } - return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s", - Result.c_str()) < MaxLength; -} - -void __sanitizer_symbolize_flush() { getDefaultSymbolizer()->flush(); } - -int __sanitizer_symbolize_demangle(const char *Name, char *Buffer, - int MaxLength) { - std::string Result = - llvm::symbolize::LLVMSymbolizer::DemangleName(Name, nullptr); - return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s", - Result.c_str()) < MaxLength - ? static_cast(Result.size() + 1) - : 0; -} - -} // extern "C" diff --git a/lib/sanitizer_common/symbolizer/sanitizer_symbolize.cpp b/lib/sanitizer_common/symbolizer/sanitizer_symbolize.cpp new file mode 100644 index 000000000000..ba285bc1e884 --- /dev/null +++ b/lib/sanitizer_common/symbolizer/sanitizer_symbolize.cpp @@ -0,0 +1,80 @@ +//===-- sanitizer_symbolize.cpp ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementation of weak hooks from sanitizer_symbolizer_posix_libcdep.cpp. +// +//===----------------------------------------------------------------------===// + +#include +#include + +#include "llvm/DebugInfo/Symbolize/DIPrinter.h" +#include "llvm/DebugInfo/Symbolize/Symbolize.h" + +static llvm::symbolize::LLVMSymbolizer *getDefaultSymbolizer() { + static llvm::symbolize::LLVMSymbolizer *DefaultSymbolizer = + new llvm::symbolize::LLVMSymbolizer(); + return DefaultSymbolizer; +} + +namespace __sanitizer { +int internal_snprintf(char *buffer, unsigned long length, const char *format, + ...); +} // namespace __sanitizer + +extern "C" { + +typedef uint64_t u64; + +bool __sanitizer_symbolize_code(const char *ModuleName, uint64_t ModuleOffset, + char *Buffer, int MaxLength) { + std::string Result; + { + llvm::raw_string_ostream OS(Result); + llvm::symbolize::DIPrinter Printer(OS); + // TODO: it is neccessary to set proper SectionIndex here. + // object::SectionedAddress::UndefSection works for only absolute addresses. + auto ResOrErr = getDefaultSymbolizer()->symbolizeInlinedCode( + ModuleName, + {ModuleOffset, llvm::object::SectionedAddress::UndefSection}); + Printer << (ResOrErr ? ResOrErr.get() : llvm::DIInliningInfo()); + } + return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s", + Result.c_str()) < MaxLength; +} + +bool __sanitizer_symbolize_data(const char *ModuleName, uint64_t ModuleOffset, + char *Buffer, int MaxLength) { + std::string Result; + { + llvm::raw_string_ostream OS(Result); + llvm::symbolize::DIPrinter Printer(OS); + // TODO: it is neccessary to set proper SectionIndex here. + // object::SectionedAddress::UndefSection works for only absolute addresses. + auto ResOrErr = getDefaultSymbolizer()->symbolizeData( + ModuleName, + {ModuleOffset, llvm::object::SectionedAddress::UndefSection}); + Printer << (ResOrErr ? ResOrErr.get() : llvm::DIGlobal()); + } + return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s", + Result.c_str()) < MaxLength; +} + +void __sanitizer_symbolize_flush() { getDefaultSymbolizer()->flush(); } + +int __sanitizer_symbolize_demangle(const char *Name, char *Buffer, + int MaxLength) { + std::string Result = + llvm::symbolize::LLVMSymbolizer::DemangleName(Name, nullptr); + return __sanitizer::internal_snprintf(Buffer, MaxLength, "%s", + Result.c_str()) < MaxLength + ? static_cast(Result.size() + 1) + : 0; +} + +} // extern "C" diff --git a/lib/sanitizer_common/symbolizer/sanitizer_wrappers.cc b/lib/sanitizer_common/symbolizer/sanitizer_wrappers.cc deleted file mode 100644 index c85ebe5e2e29..000000000000 --- a/lib/sanitizer_common/symbolizer/sanitizer_wrappers.cc +++ /dev/null @@ -1,198 +0,0 @@ -//===-- sanitizer_wrappers.cc -----------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Redirect some functions to sanitizer interceptors. -// -//===----------------------------------------------------------------------===// - -#include -#include -#include -#include -#include -#include - -#include - -// Need to match ../sanitizer_common/sanitizer_internal_defs.h -#if defined(ARCH_PPC) -#define OFF_T unsigned long -#else -#define OFF_T unsigned long long -#endif - -namespace __sanitizer { -unsigned long internal_open(const char *filename, int flags); -unsigned long internal_open(const char *filename, int flags, unsigned mode); -unsigned long internal_close(int fd); -unsigned long internal_stat(const char *path, void *buf); -unsigned long internal_lstat(const char *path, void *buf); -unsigned long internal_fstat(int fd, void *buf); -size_t internal_strlen(const char *s); -unsigned long internal_mmap(void *addr, unsigned long length, int prot, - int flags, int fd, OFF_T offset); -void *internal_memcpy(void *dest, const void *src, unsigned long n); -// Used to propagate errno. -bool internal_iserror(unsigned long retval, int *rverrno = 0); -} // namespace __sanitizer - -namespace { - -template -struct GetTypes; - -template -struct GetTypes { - using Result = R; - template - struct Arg { - using Type = typename std::tuple_element>::type; - }; -}; - -#define LLVM_SYMBOLIZER_GET_FUNC(Function) \ - ((__interceptor_##Function) \ - ? (__interceptor_##Function) \ - : reinterpret_cast(dlsym(RTLD_NEXT, #Function))) - -#define LLVM_SYMBOLIZER_INTERCEPTOR1(Function, ...) \ - GetTypes<__VA_ARGS__>::Result __interceptor_##Function( \ - GetTypes<__VA_ARGS__>::Arg<0>::Type) __attribute__((weak)); \ - GetTypes<__VA_ARGS__>::Result Function( \ - GetTypes<__VA_ARGS__>::Arg<0>::Type arg0) { \ - return LLVM_SYMBOLIZER_GET_FUNC(Function)(arg0); \ - } - -#define LLVM_SYMBOLIZER_INTERCEPTOR2(Function, ...) \ - GetTypes<__VA_ARGS__>::Result __interceptor_##Function( \ - GetTypes<__VA_ARGS__>::Arg<0>::Type, \ - GetTypes<__VA_ARGS__>::Arg<1>::Type) __attribute__((weak)); \ - GetTypes<__VA_ARGS__>::Result Function( \ - GetTypes<__VA_ARGS__>::Arg<0>::Type arg0, \ - GetTypes<__VA_ARGS__>::Arg<1>::Type arg1) { \ - return LLVM_SYMBOLIZER_GET_FUNC(Function)(arg0, arg1); \ - } - -#define LLVM_SYMBOLIZER_INTERCEPTOR3(Function, ...) \ - GetTypes<__VA_ARGS__>::Result __interceptor_##Function( \ - GetTypes<__VA_ARGS__>::Arg<0>::Type, \ - GetTypes<__VA_ARGS__>::Arg<1>::Type, \ - GetTypes<__VA_ARGS__>::Arg<2>::Type) __attribute__((weak)); \ - GetTypes<__VA_ARGS__>::Result Function( \ - GetTypes<__VA_ARGS__>::Arg<0>::Type arg0, \ - GetTypes<__VA_ARGS__>::Arg<1>::Type arg1, \ - GetTypes<__VA_ARGS__>::Arg<2>::Type arg2) { \ - return LLVM_SYMBOLIZER_GET_FUNC(Function)(arg0, arg1, arg2); \ - } - -#define LLVM_SYMBOLIZER_INTERCEPTOR4(Function, ...) \ - GetTypes<__VA_ARGS__>::Result __interceptor_##Function( \ - GetTypes<__VA_ARGS__>::Arg<0>::Type, \ - GetTypes<__VA_ARGS__>::Arg<1>::Type, \ - GetTypes<__VA_ARGS__>::Arg<2>::Type, \ - GetTypes<__VA_ARGS__>::Arg<3>::Type) __attribute__((weak)); \ - GetTypes<__VA_ARGS__>::Result Function( \ - GetTypes<__VA_ARGS__>::Arg<0>::Type arg0, \ - GetTypes<__VA_ARGS__>::Arg<1>::Type arg1, \ - GetTypes<__VA_ARGS__>::Arg<2>::Type arg2, \ - GetTypes<__VA_ARGS__>::Arg<3>::Type arg3) { \ - return LLVM_SYMBOLIZER_GET_FUNC(Function)(arg0, arg1, arg2, arg3); \ - } - -} // namespace - -// C-style interface around internal sanitizer libc functions. -extern "C" { - -#define RETURN_OR_SET_ERRNO(T, res) \ - int rverrno; \ - if (__sanitizer::internal_iserror(res, &rverrno)) { \ - errno = rverrno; \ - return (T)-1; \ - } \ - return (T)res; - -int open(const char *filename, int flags, ...) { - unsigned long res; - if (flags | O_CREAT) { - va_list va; - va_start(va, flags); - unsigned mode = va_arg(va, unsigned); - va_end(va); - res = __sanitizer::internal_open(filename, flags, mode); - } else { - res = __sanitizer::internal_open(filename, flags); - } - RETURN_OR_SET_ERRNO(int, res); -} - -int close(int fd) { - unsigned long res = __sanitizer::internal_close(fd); - RETURN_OR_SET_ERRNO(int, res); -} - -#define STAT(func, arg, buf) \ - unsigned long res = __sanitizer::internal_##func(arg, buf); \ - RETURN_OR_SET_ERRNO(int, res); - -int stat(const char *path, struct stat *buf) { STAT(stat, path, buf); } - -int lstat(const char *path, struct stat *buf) { STAT(lstat, path, buf); } - -int fstat(int fd, struct stat *buf) { STAT(fstat, fd, buf); } - -// Redirect versioned stat functions to the __sanitizer::internal() as well. -int __xstat(int version, const char *path, struct stat *buf) { - STAT(stat, path, buf); -} - -int __lxstat(int version, const char *path, struct stat *buf) { - STAT(lstat, path, buf); -} - -int __fxstat(int version, int fd, struct stat *buf) { STAT(fstat, fd, buf); } - -size_t strlen(const char *s) { return __sanitizer::internal_strlen(s); } - -void *mmap(void *addr, size_t length, int prot, int flags, int fd, - off_t offset) { - unsigned long res = __sanitizer::internal_mmap( - addr, (unsigned long)length, prot, flags, fd, (unsigned long long)offset); - RETURN_OR_SET_ERRNO(void *, res); -} - -LLVM_SYMBOLIZER_INTERCEPTOR3(read, ssize_t(int, void *, size_t)) -LLVM_SYMBOLIZER_INTERCEPTOR4(pread, ssize_t(int, void *, size_t, off_t)) -LLVM_SYMBOLIZER_INTERCEPTOR4(pread64, ssize_t(int, void *, size_t, off64_t)) -LLVM_SYMBOLIZER_INTERCEPTOR2(realpath, char *(const char *, char *)) - -LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_cond_broadcast, int(pthread_cond_t *)) -LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_cond_wait, - int(pthread_cond_t *, pthread_mutex_t *)) -LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_mutex_lock, int(pthread_mutex_t *)) -LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_mutex_unlock, int(pthread_mutex_t *)) -LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_mutex_destroy, int(pthread_mutex_t *)) -LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_mutex_init, - int(pthread_mutex_t *, - const pthread_mutexattr_t *)) -LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_mutexattr_destroy, - int(pthread_mutexattr_t *)) -LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_mutexattr_init, int(pthread_mutexattr_t *)) -LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_mutexattr_settype, - int(pthread_mutexattr_t *, int)) -LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_getspecific, void *(pthread_key_t)) -LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_key_create, - int(pthread_key_t *, void (*)(void *))) -LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_once, - int(pthread_once_t *, void (*)(void))) -LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_setspecific, - int(pthread_key_t, const void *)) -LLVM_SYMBOLIZER_INTERCEPTOR3(pthread_sigmask, - int(int, const sigset_t *, sigset_t *)) - -} // extern "C" diff --git a/lib/sanitizer_common/symbolizer/sanitizer_wrappers.cpp b/lib/sanitizer_common/symbolizer/sanitizer_wrappers.cpp new file mode 100644 index 000000000000..ac351d3a8362 --- /dev/null +++ b/lib/sanitizer_common/symbolizer/sanitizer_wrappers.cpp @@ -0,0 +1,198 @@ +//===-- sanitizer_wrappers.cpp ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Redirect some functions to sanitizer interceptors. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include +#include + +#include + +// Need to match ../sanitizer_common/sanitizer_internal_defs.h +#if defined(ARCH_PPC) +#define OFF_T unsigned long +#else +#define OFF_T unsigned long long +#endif + +namespace __sanitizer { +unsigned long internal_open(const char *filename, int flags); +unsigned long internal_open(const char *filename, int flags, unsigned mode); +unsigned long internal_close(int fd); +unsigned long internal_stat(const char *path, void *buf); +unsigned long internal_lstat(const char *path, void *buf); +unsigned long internal_fstat(int fd, void *buf); +size_t internal_strlen(const char *s); +unsigned long internal_mmap(void *addr, unsigned long length, int prot, + int flags, int fd, OFF_T offset); +void *internal_memcpy(void *dest, const void *src, unsigned long n); +// Used to propagate errno. +bool internal_iserror(unsigned long retval, int *rverrno = 0); +} // namespace __sanitizer + +namespace { + +template +struct GetTypes; + +template +struct GetTypes { + using Result = R; + template + struct Arg { + using Type = typename std::tuple_element>::type; + }; +}; + +#define LLVM_SYMBOLIZER_GET_FUNC(Function) \ + ((__interceptor_##Function) \ + ? (__interceptor_##Function) \ + : reinterpret_cast(dlsym(RTLD_NEXT, #Function))) + +#define LLVM_SYMBOLIZER_INTERCEPTOR1(Function, ...) \ + GetTypes<__VA_ARGS__>::Result __interceptor_##Function( \ + GetTypes<__VA_ARGS__>::Arg<0>::Type) __attribute__((weak)); \ + GetTypes<__VA_ARGS__>::Result Function( \ + GetTypes<__VA_ARGS__>::Arg<0>::Type arg0) { \ + return LLVM_SYMBOLIZER_GET_FUNC(Function)(arg0); \ + } + +#define LLVM_SYMBOLIZER_INTERCEPTOR2(Function, ...) \ + GetTypes<__VA_ARGS__>::Result __interceptor_##Function( \ + GetTypes<__VA_ARGS__>::Arg<0>::Type, \ + GetTypes<__VA_ARGS__>::Arg<1>::Type) __attribute__((weak)); \ + GetTypes<__VA_ARGS__>::Result Function( \ + GetTypes<__VA_ARGS__>::Arg<0>::Type arg0, \ + GetTypes<__VA_ARGS__>::Arg<1>::Type arg1) { \ + return LLVM_SYMBOLIZER_GET_FUNC(Function)(arg0, arg1); \ + } + +#define LLVM_SYMBOLIZER_INTERCEPTOR3(Function, ...) \ + GetTypes<__VA_ARGS__>::Result __interceptor_##Function( \ + GetTypes<__VA_ARGS__>::Arg<0>::Type, \ + GetTypes<__VA_ARGS__>::Arg<1>::Type, \ + GetTypes<__VA_ARGS__>::Arg<2>::Type) __attribute__((weak)); \ + GetTypes<__VA_ARGS__>::Result Function( \ + GetTypes<__VA_ARGS__>::Arg<0>::Type arg0, \ + GetTypes<__VA_ARGS__>::Arg<1>::Type arg1, \ + GetTypes<__VA_ARGS__>::Arg<2>::Type arg2) { \ + return LLVM_SYMBOLIZER_GET_FUNC(Function)(arg0, arg1, arg2); \ + } + +#define LLVM_SYMBOLIZER_INTERCEPTOR4(Function, ...) \ + GetTypes<__VA_ARGS__>::Result __interceptor_##Function( \ + GetTypes<__VA_ARGS__>::Arg<0>::Type, \ + GetTypes<__VA_ARGS__>::Arg<1>::Type, \ + GetTypes<__VA_ARGS__>::Arg<2>::Type, \ + GetTypes<__VA_ARGS__>::Arg<3>::Type) __attribute__((weak)); \ + GetTypes<__VA_ARGS__>::Result Function( \ + GetTypes<__VA_ARGS__>::Arg<0>::Type arg0, \ + GetTypes<__VA_ARGS__>::Arg<1>::Type arg1, \ + GetTypes<__VA_ARGS__>::Arg<2>::Type arg2, \ + GetTypes<__VA_ARGS__>::Arg<3>::Type arg3) { \ + return LLVM_SYMBOLIZER_GET_FUNC(Function)(arg0, arg1, arg2, arg3); \ + } + +} // namespace + +// C-style interface around internal sanitizer libc functions. +extern "C" { + +#define RETURN_OR_SET_ERRNO(T, res) \ + int rverrno; \ + if (__sanitizer::internal_iserror(res, &rverrno)) { \ + errno = rverrno; \ + return (T)-1; \ + } \ + return (T)res; + +int open(const char *filename, int flags, ...) { + unsigned long res; + if (flags | O_CREAT) { + va_list va; + va_start(va, flags); + unsigned mode = va_arg(va, unsigned); + va_end(va); + res = __sanitizer::internal_open(filename, flags, mode); + } else { + res = __sanitizer::internal_open(filename, flags); + } + RETURN_OR_SET_ERRNO(int, res); +} + +int close(int fd) { + unsigned long res = __sanitizer::internal_close(fd); + RETURN_OR_SET_ERRNO(int, res); +} + +#define STAT(func, arg, buf) \ + unsigned long res = __sanitizer::internal_##func(arg, buf); \ + RETURN_OR_SET_ERRNO(int, res); + +int stat(const char *path, struct stat *buf) { STAT(stat, path, buf); } + +int lstat(const char *path, struct stat *buf) { STAT(lstat, path, buf); } + +int fstat(int fd, struct stat *buf) { STAT(fstat, fd, buf); } + +// Redirect versioned stat functions to the __sanitizer::internal() as well. +int __xstat(int version, const char *path, struct stat *buf) { + STAT(stat, path, buf); +} + +int __lxstat(int version, const char *path, struct stat *buf) { + STAT(lstat, path, buf); +} + +int __fxstat(int version, int fd, struct stat *buf) { STAT(fstat, fd, buf); } + +size_t strlen(const char *s) { return __sanitizer::internal_strlen(s); } + +void *mmap(void *addr, size_t length, int prot, int flags, int fd, + off_t offset) { + unsigned long res = __sanitizer::internal_mmap( + addr, (unsigned long)length, prot, flags, fd, (unsigned long long)offset); + RETURN_OR_SET_ERRNO(void *, res); +} + +LLVM_SYMBOLIZER_INTERCEPTOR3(read, ssize_t(int, void *, size_t)) +LLVM_SYMBOLIZER_INTERCEPTOR4(pread, ssize_t(int, void *, size_t, off_t)) +LLVM_SYMBOLIZER_INTERCEPTOR4(pread64, ssize_t(int, void *, size_t, off64_t)) +LLVM_SYMBOLIZER_INTERCEPTOR2(realpath, char *(const char *, char *)) + +LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_cond_broadcast, int(pthread_cond_t *)) +LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_cond_wait, + int(pthread_cond_t *, pthread_mutex_t *)) +LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_mutex_lock, int(pthread_mutex_t *)) +LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_mutex_unlock, int(pthread_mutex_t *)) +LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_mutex_destroy, int(pthread_mutex_t *)) +LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_mutex_init, + int(pthread_mutex_t *, + const pthread_mutexattr_t *)) +LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_mutexattr_destroy, + int(pthread_mutexattr_t *)) +LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_mutexattr_init, int(pthread_mutexattr_t *)) +LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_mutexattr_settype, + int(pthread_mutexattr_t *, int)) +LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_getspecific, void *(pthread_key_t)) +LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_key_create, + int(pthread_key_t *, void (*)(void *))) +LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_once, + int(pthread_once_t *, void (*)(void))) +LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_setspecific, + int(pthread_key_t, const void *)) +LLVM_SYMBOLIZER_INTERCEPTOR3(pthread_sigmask, + int(int, const sigset_t *, sigset_t *)) + +} // extern "C" diff --git a/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh b/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh index 0c3917c6b17b..be79f1df64ba 100755 --- a/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh +++ b/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh @@ -25,15 +25,25 @@ # object file with only our entry points exposed. However, this does not work at # present, see PR30750. -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +set -x +set -e +set -u + +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) SRC_DIR=$(readlink -f $SCRIPT_DIR/..) TARGE_DIR=$(readlink -f $1) - -LLVM_SRC="${LLVM_SRC:-$SCRIPT_DIR/../../../../../..}" +COMPILER_RT_SRC=$(readlink -f ${SCRIPT_DIR}/../../../..) +LLVM_SRC=${LLVM_SRC:-${COMPILER_RT_SRC}/../llvm} LLVM_SRC=$(readlink -f $LLVM_SRC) +if [[ ! -d "${LLVM_SRC}/../llvm" ]] ; then + LLVM_SRC=$(readlink -f ${COMPILER_RT_SRC}/../../../llvm) +fi +LIBCXX_SRC=$(readlink -f ${COMPILER_RT_SRC}/../libcxx) +LIBCXXABI_SRC=$(readlink -f ${COMPILER_RT_SRC}/../libcxxabi) -if [[ ! -d "${LLVM_SRC}/projects/libcxxabi" || - ! -d "${LLVM_SRC}/projects/libcxx" ]]; then +if [[ ! -d "${LLVM_SRC}/../llvm" || + ! -d "${LIBCXX_SRC}" || + ! -d "${LIBCXXABI_SRC}" ]]; then echo "Missing or incomplete LLVM_SRC" exit 1 fi @@ -88,8 +98,13 @@ make -j${J} libz.a if [[ ! -d ${LIBCXX_BUILD} ]]; then mkdir -p ${LIBCXX_BUILD} cd ${LIBCXX_BUILD} - LIBCXX_FLAGS="${FLAGS} -Wno-macro-redefined -I${LLVM_SRC}/projects/libcxxabi/include" + LIBCXX_FLAGS="${FLAGS} -Wno-macro-redefined -I${LIBCXX_SRC}/include" + PROJECTS= + if [[ ! -d $LLVM_SRC/projects/libcxxabi ]] ; then + PROJECTS="-DLLVM_ENABLE_PROJECTS='libcxx;libcxxabi'" + fi cmake -GNinja \ + ${PROJECTS} \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER=$CC \ -DCMAKE_CXX_COMPILER=$CXX \ @@ -127,7 +142,7 @@ if [[ ! -d ${LLVM_BUILD} ]]; then $LLVM_SRC fi cd ${LLVM_BUILD} -ninja LLVMSymbolize LLVMObject LLVMBinaryFormat LLVMDebugInfoDWARF LLVMSupport LLVMDebugInfoPDB LLVMMC LLVMDemangle +ninja LLVMSymbolize LLVMObject LLVMBinaryFormat LLVMDebugInfoDWARF LLVMSupport LLVMDebugInfoPDB LLVMMC LLVMDemangle LLVMTextAPI cd ${BUILD_DIR} rm -rf ${SYMBOLIZER_BUILD} @@ -135,8 +150,8 @@ mkdir ${SYMBOLIZER_BUILD} cd ${SYMBOLIZER_BUILD} echo "Compiling..." -SYMBOLIZER_FLAGS="$LLVM_FLAGS -I${LLVM_SRC}/include -I${LLVM_BUILD}/include -std=c++11" -$CXX $SYMBOLIZER_FLAGS ${SRC_DIR}/sanitizer_symbolize.cc ${SRC_DIR}/sanitizer_wrappers.cc -c +SYMBOLIZER_FLAGS="$LLVM_FLAGS -I${LLVM_SRC}/include -I${LLVM_BUILD}/include -std=c++14" +$CXX $SYMBOLIZER_FLAGS ${SRC_DIR}/sanitizer_symbolize.cpp ${SRC_DIR}/sanitizer_wrappers.cpp -c $AR rc symbolizer.a sanitizer_symbolize.o sanitizer_wrappers.o SYMBOLIZER_API_LIST=__sanitizer_symbolize_code,__sanitizer_symbolize_data,__sanitizer_symbolize_flush,__sanitizer_symbolize_demangle @@ -152,6 +167,7 @@ $SCRIPT_DIR/ar_to_bc.sh $LIBCXX_BUILD/lib/libc++.a \ $LLVM_BUILD/lib/libLLVMDebugInfoPDB.a \ $LLVM_BUILD/lib/libLLVMDemangle.a \ $LLVM_BUILD/lib/libLLVMMC.a \ + $LLVM_BUILD/lib/libLLVMTextAPI.a \ $ZLIB_BUILD/libz.a \ symbolizer.a \ all.bc diff --git a/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt b/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt index 2a0f76b80ef4..fa42e2a01965 100644 --- a/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt +++ b/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt @@ -19,8 +19,13 @@ __interceptor_pthread_cond_broadcast w __interceptor_pthread_cond_wait w __interceptor_pthread_getspecific w __interceptor_pthread_key_create w +__interceptor_pthread_mutex_destroy w +__interceptor_pthread_mutex_init w __interceptor_pthread_mutex_lock w __interceptor_pthread_mutex_unlock w +__interceptor_pthread_mutexattr_destroy w +__interceptor_pthread_mutexattr_init w +__interceptor_pthread_mutexattr_settype w __interceptor_pthread_once w __interceptor_pthread_setspecific w __interceptor_read w @@ -70,9 +75,11 @@ getpid U getrlimit U gettimeofday U ioctl U +isalnum U isalpha U isatty U islower U +isspace U isprint U isupper U isxdigit U -- cgit v1.2.3