| author | |
| committer | |
| log | 42b4a48bc96ce22562230cd1a266f93a013c76dd |
| tree | 16a176b415131a12b72cbac682d0398fa65d9926 |
| parent | 0fd68f49e2eabb866ea1d21c4657c2a1d3c8ce53 |
220 files changed, 72299 insertions(+), 3 deletions(-)
CMakeLists.txt+1| ... | @@ -537,6 +537,7 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -537,6 +537,7 @@ set(ZIG_STAGE2_SOURCES |
| 537 | "${CMAKE_SOURCE_DIR}/src/ir.zig" | 537 | "${CMAKE_SOURCE_DIR}/src/ir.zig" |
| 538 | "${CMAKE_SOURCE_DIR}/src/libc_installation.zig" | 538 | "${CMAKE_SOURCE_DIR}/src/libc_installation.zig" |
| 539 | "${CMAKE_SOURCE_DIR}/src/libcxx.zig" | 539 | "${CMAKE_SOURCE_DIR}/src/libcxx.zig" |
| 540 | "${CMAKE_SOURCE_DIR}/src/libtsan.zig" | ||
| 540 | "${CMAKE_SOURCE_DIR}/src/libunwind.zig" | 541 | "${CMAKE_SOURCE_DIR}/src/libunwind.zig" |
| 541 | "${CMAKE_SOURCE_DIR}/src/link.zig" | 542 | "${CMAKE_SOURCE_DIR}/src/link.zig" |
| 542 | "${CMAKE_SOURCE_DIR}/src/link/C.zig" | 543 | "${CMAKE_SOURCE_DIR}/src/link/C.zig" |
lib/tsan/interception/interception.h created+304| ... | @@ -0,0 +1,304 @@ | ||
| 1 | //===-- interception.h ------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of AddressSanitizer, an address sanity checker. | ||
| 10 | // | ||
| 11 | // Machinery for providing replacements/wrappers for system functions. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef INTERCEPTION_H | ||
| 15 | #define INTERCEPTION_H | ||
| 16 | |||
| 17 | #include "sanitizer_common/sanitizer_internal_defs.h" | ||
| 18 | |||
| 19 | #if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_MAC && \ | ||
| 20 | !SANITIZER_NETBSD && !SANITIZER_OPENBSD && !SANITIZER_WINDOWS && \ | ||
| 21 | !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_SOLARIS | ||
| 22 | # error "Interception doesn't work on this operating system." | ||
| 23 | #endif | ||
| 24 | |||
| 25 | // These typedefs should be used only in the interceptor definitions to replace | ||
| 26 | // the standard system types (e.g. SSIZE_T instead of ssize_t) | ||
| 27 | typedef __sanitizer::uptr SIZE_T; | ||
| 28 | typedef __sanitizer::sptr SSIZE_T; | ||
| 29 | typedef __sanitizer::sptr PTRDIFF_T; | ||
| 30 | typedef __sanitizer::s64 INTMAX_T; | ||
| 31 | typedef __sanitizer::u64 UINTMAX_T; | ||
| 32 | typedef __sanitizer::OFF_T OFF_T; | ||
| 33 | typedef __sanitizer::OFF64_T OFF64_T; | ||
| 34 | |||
| 35 | // How to add an interceptor: | ||
| 36 | // Suppose you need to wrap/replace system function (generally, from libc): | ||
| 37 | // int foo(const char *bar, double baz); | ||
| 38 | // You'll need to: | ||
| 39 | // 1) define INTERCEPTOR(int, foo, const char *bar, double baz) { ... } in | ||
| 40 | // your source file. See the notes below for cases when | ||
| 41 | // INTERCEPTOR_WITH_SUFFIX(...) should be used instead. | ||
| 42 | // 2) Call "INTERCEPT_FUNCTION(foo)" prior to the first call of "foo". | ||
| 43 | // INTERCEPT_FUNCTION(foo) evaluates to "true" iff the function was | ||
| 44 | // intercepted successfully. | ||
| 45 | // You can access original function by calling REAL(foo)(bar, baz). | ||
| 46 | // By default, REAL(foo) will be visible only inside your interceptor, and if | ||
| 47 | // you want to use it in other parts of RTL, you'll need to: | ||
| 48 | // 3a) add DECLARE_REAL(int, foo, const char*, double) to a | ||
| 49 | // header file. | ||
| 50 | // However, if the call "INTERCEPT_FUNCTION(foo)" and definition for | ||
| 51 | // INTERCEPTOR(..., foo, ...) are in different files, you'll instead need to: | ||
| 52 | // 3b) add DECLARE_REAL_AND_INTERCEPTOR(int, foo, const char*, double) | ||
| 53 | // to a header file. | ||
| 54 | |||
| 55 | // Notes: 1. Things may not work properly if macro INTERCEPTOR(...) {...} or | ||
| 56 | // DECLARE_REAL(...) are located inside namespaces. | ||
| 57 | // 2. On Mac you can also use: "OVERRIDE_FUNCTION(foo, zoo)" to | ||
| 58 | // effectively redirect calls from "foo" to "zoo". In this case | ||
| 59 | // you aren't required to implement | ||
| 60 | // INTERCEPTOR(int, foo, const char *bar, double baz) {...} | ||
| 61 | // but instead you'll have to add | ||
| 62 | // DECLARE_REAL(int, foo, const char *bar, double baz) in your | ||
| 63 | // source file (to define a pointer to overriden function). | ||
| 64 | // 3. Some Mac functions have symbol variants discriminated by | ||
| 65 | // additional suffixes, e.g. _$UNIX2003 (see | ||
| 66 | // https://developer.apple.com/library/mac/#releasenotes/Darwin/SymbolVariantsRelNotes/index.html | ||
| 67 | // for more details). To intercept such functions you need to use the | ||
| 68 | // INTERCEPTOR_WITH_SUFFIX(...) macro. | ||
| 69 | |||
| 70 | // How it works: | ||
| 71 | // To replace system functions on Linux we just need to declare functions | ||
| 72 | // with same names in our library and then obtain the real function pointers | ||
| 73 | // using dlsym(). | ||
| 74 | // There is one complication. A user may also intercept some of the functions | ||
| 75 | // we intercept. To resolve this we declare our interceptors with __interceptor_ | ||
| 76 | // prefix, and then make actual interceptors weak aliases to __interceptor_ | ||
| 77 | // functions. | ||
| 78 | // | ||
| 79 | // This is not so on Mac OS, where the two-level namespace makes | ||
| 80 | // our replacement functions invisible to other libraries. This may be overcomed | ||
| 81 | // using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared | ||
| 82 | // libraries in Chromium were noticed when doing so. | ||
| 83 | // Instead we create a dylib containing a __DATA,__interpose section that | ||
| 84 | // associates library functions with their wrappers. When this dylib is | ||
| 85 | // preloaded before an executable using DYLD_INSERT_LIBRARIES, it routes all | ||
| 86 | // the calls to interposed functions done through stubs to the wrapper | ||
| 87 | // functions. | ||
| 88 | // As it's decided at compile time which functions are to be intercepted on Mac, | ||
| 89 | // INTERCEPT_FUNCTION() is effectively a no-op on this system. | ||
| 90 | |||
| 91 | #if SANITIZER_MAC | ||
| 92 | #include <sys/cdefs.h> // For __DARWIN_ALIAS_C(). | ||
| 93 | |||
| 94 | // Just a pair of pointers. | ||
| 95 | struct interpose_substitution { | ||
| 96 | const __sanitizer::uptr replacement; | ||
| 97 | const __sanitizer::uptr original; | ||
| 98 | }; | ||
| 99 | |||
| 100 | // For a function foo() create a global pair of pointers { wrap_foo, foo } in | ||
| 101 | // the __DATA,__interpose section. | ||
| 102 | // As a result all the calls to foo() will be routed to wrap_foo() at runtime. | ||
| 103 | #define INTERPOSER(func_name) __attribute__((used)) \ | ||
| 104 | const interpose_substitution substitution_##func_name[] \ | ||
| 105 | __attribute__((section("__DATA, __interpose"))) = { \ | ||
| 106 | { reinterpret_cast<const uptr>(WRAP(func_name)), \ | ||
| 107 | reinterpret_cast<const uptr>(func_name) } \ | ||
| 108 | } | ||
| 109 | |||
| 110 | // For a function foo() and a wrapper function bar() create a global pair | ||
| 111 | // of pointers { bar, foo } in the __DATA,__interpose section. | ||
| 112 | // As a result all the calls to foo() will be routed to bar() at runtime. | ||
| 113 | #define INTERPOSER_2(func_name, wrapper_name) __attribute__((used)) \ | ||
| 114 | const interpose_substitution substitution_##func_name[] \ | ||
| 115 | __attribute__((section("__DATA, __interpose"))) = { \ | ||
| 116 | { reinterpret_cast<const uptr>(wrapper_name), \ | ||
| 117 | reinterpret_cast<const uptr>(func_name) } \ | ||
| 118 | } | ||
| 119 | |||
| 120 | # define WRAP(x) wrap_##x | ||
| 121 | # define WRAPPER_NAME(x) "wrap_"#x | ||
| 122 | # define INTERCEPTOR_ATTRIBUTE | ||
| 123 | # define DECLARE_WRAPPER(ret_type, func, ...) | ||
| 124 | |||
| 125 | #elif SANITIZER_WINDOWS | ||
| 126 | # define WRAP(x) __asan_wrap_##x | ||
| 127 | # define WRAPPER_NAME(x) "__asan_wrap_"#x | ||
| 128 | # define INTERCEPTOR_ATTRIBUTE __declspec(dllexport) | ||
| 129 | # define DECLARE_WRAPPER(ret_type, func, ...) \ | ||
| 130 | extern "C" ret_type func(__VA_ARGS__); | ||
| 131 | # define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \ | ||
| 132 | extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__); | ||
| 133 | #elif SANITIZER_RTEMS | ||
| 134 | # define WRAP(x) x | ||
| 135 | # define WRAPPER_NAME(x) #x | ||
| 136 | # define INTERCEPTOR_ATTRIBUTE | ||
| 137 | # define DECLARE_WRAPPER(ret_type, func, ...) | ||
| 138 | #elif SANITIZER_FREEBSD || SANITIZER_NETBSD | ||
| 139 | # define WRAP(x) __interceptor_ ## x | ||
| 140 | # define WRAPPER_NAME(x) "__interceptor_" #x | ||
| 141 | # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) | ||
| 142 | // FreeBSD's dynamic linker (incompliantly) gives non-weak symbols higher | ||
| 143 | // priority than weak ones so weak aliases won't work for indirect calls | ||
| 144 | // in position-independent (-fPIC / -fPIE) mode. | ||
| 145 | # define DECLARE_WRAPPER(ret_type, func, ...) \ | ||
| 146 | extern "C" ret_type func(__VA_ARGS__) \ | ||
| 147 | __attribute__((alias("__interceptor_" #func), visibility("default"))); | ||
| 148 | #elif !SANITIZER_FUCHSIA | ||
| 149 | # define WRAP(x) __interceptor_ ## x | ||
| 150 | # define WRAPPER_NAME(x) "__interceptor_" #x | ||
| 151 | # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) | ||
| 152 | # define DECLARE_WRAPPER(ret_type, func, ...) \ | ||
| 153 | extern "C" ret_type func(__VA_ARGS__) \ | ||
| 154 | __attribute__((weak, alias("__interceptor_" #func), visibility("default"))); | ||
| 155 | #endif | ||
| 156 | |||
| 157 | #if SANITIZER_FUCHSIA | ||
| 158 | // There is no general interception at all on Fuchsia. | ||
| 159 | // Sanitizer runtimes just define functions directly to preempt them, | ||
| 160 | // and have bespoke ways to access the underlying libc functions. | ||
| 161 | # include <zircon/sanitizer.h> | ||
| 162 | # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) | ||
| 163 | # define REAL(x) __unsanitized_##x | ||
| 164 | # define DECLARE_REAL(ret_type, func, ...) | ||
| 165 | #elif SANITIZER_RTEMS | ||
| 166 | # define REAL(x) __real_ ## x | ||
| 167 | # define DECLARE_REAL(ret_type, func, ...) \ | ||
| 168 | extern "C" ret_type REAL(func)(__VA_ARGS__); | ||
| 169 | #elif !SANITIZER_MAC | ||
| 170 | # define PTR_TO_REAL(x) real_##x | ||
| 171 | # define REAL(x) __interception::PTR_TO_REAL(x) | ||
| 172 | # define FUNC_TYPE(x) x##_type | ||
| 173 | |||
| 174 | # define DECLARE_REAL(ret_type, func, ...) \ | ||
| 175 | typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ | ||
| 176 | namespace __interception { \ | ||
| 177 | extern FUNC_TYPE(func) PTR_TO_REAL(func); \ | ||
| 178 | } | ||
| 179 | # define ASSIGN_REAL(dst, src) REAL(dst) = REAL(src) | ||
| 180 | #else // SANITIZER_MAC | ||
| 181 | # define REAL(x) x | ||
| 182 | # define DECLARE_REAL(ret_type, func, ...) \ | ||
| 183 | extern "C" ret_type func(__VA_ARGS__); | ||
| 184 | # define ASSIGN_REAL(x, y) | ||
| 185 | #endif // SANITIZER_MAC | ||
| 186 | |||
| 187 | #if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS | ||
| 188 | # define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \ | ||
| 189 | DECLARE_REAL(ret_type, func, __VA_ARGS__) \ | ||
| 190 | extern "C" ret_type WRAP(func)(__VA_ARGS__); | ||
| 191 | // Declare an interceptor and its wrapper defined in a different translation | ||
| 192 | // unit (ex. asm). | ||
| 193 | # define DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(ret_type, func, ...) \ | ||
| 194 | extern "C" ret_type WRAP(func)(__VA_ARGS__); \ | ||
| 195 | extern "C" ret_type func(__VA_ARGS__); | ||
| 196 | #else | ||
| 197 | # define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) | ||
| 198 | # define DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(ret_type, func, ...) | ||
| 199 | #endif | ||
| 200 | |||
| 201 | // Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR | ||
| 202 | // macros does its job. In exceptional cases you may need to call REAL(foo) | ||
| 203 | // without defining INTERCEPTOR(..., foo, ...). For example, if you override | ||
| 204 | // foo with an interceptor for other function. | ||
| 205 | #if !SANITIZER_MAC && !SANITIZER_FUCHSIA && !SANITIZER_RTEMS | ||
| 206 | # define DEFINE_REAL(ret_type, func, ...) \ | ||
| 207 | typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ | ||
| 208 | namespace __interception { \ | ||
| 209 | FUNC_TYPE(func) PTR_TO_REAL(func); \ | ||
| 210 | } | ||
| 211 | #else | ||
| 212 | # define DEFINE_REAL(ret_type, func, ...) | ||
| 213 | #endif | ||
| 214 | |||
| 215 | #if SANITIZER_FUCHSIA | ||
| 216 | |||
| 217 | // We need to define the __interceptor_func name just to get | ||
| 218 | // sanitizer_common/scripts/gen_dynamic_list.py to export func. | ||
| 219 | // But we don't need to export __interceptor_func to get that. | ||
| 220 | #define INTERCEPTOR(ret_type, func, ...) \ | ||
| 221 | extern "C"[[ gnu::alias(#func), gnu::visibility("hidden") ]] ret_type \ | ||
| 222 | __interceptor_##func(__VA_ARGS__); \ | ||
| 223 | extern "C" INTERCEPTOR_ATTRIBUTE ret_type func(__VA_ARGS__) | ||
| 224 | |||
| 225 | #elif !SANITIZER_MAC | ||
| 226 | |||
| 227 | #define INTERCEPTOR(ret_type, func, ...) \ | ||
| 228 | DEFINE_REAL(ret_type, func, __VA_ARGS__) \ | ||
| 229 | DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \ | ||
| 230 | extern "C" \ | ||
| 231 | INTERCEPTOR_ATTRIBUTE \ | ||
| 232 | ret_type WRAP(func)(__VA_ARGS__) | ||
| 233 | |||
| 234 | // We don't need INTERCEPTOR_WITH_SUFFIX on non-Darwin for now. | ||
| 235 | #define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \ | ||
| 236 | INTERCEPTOR(ret_type, func, __VA_ARGS__) | ||
| 237 | |||
| 238 | #else // SANITIZER_MAC | ||
| 239 | |||
| 240 | #define INTERCEPTOR_ZZZ(suffix, ret_type, func, ...) \ | ||
| 241 | extern "C" ret_type func(__VA_ARGS__) suffix; \ | ||
| 242 | extern "C" ret_type WRAP(func)(__VA_ARGS__); \ | ||
| 243 | INTERPOSER(func); \ | ||
| 244 | extern "C" INTERCEPTOR_ATTRIBUTE ret_type WRAP(func)(__VA_ARGS__) | ||
| 245 | |||
| 246 | #define INTERCEPTOR(ret_type, func, ...) \ | ||
| 247 | INTERCEPTOR_ZZZ(/*no symbol variants*/, ret_type, func, __VA_ARGS__) | ||
| 248 | |||
| 249 | #define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \ | ||
| 250 | INTERCEPTOR_ZZZ(__DARWIN_ALIAS_C(func), ret_type, func, __VA_ARGS__) | ||
| 251 | |||
| 252 | // Override |overridee| with |overrider|. | ||
| 253 | #define OVERRIDE_FUNCTION(overridee, overrider) \ | ||
| 254 | INTERPOSER_2(overridee, WRAP(overrider)) | ||
| 255 | #endif | ||
| 256 | |||
| 257 | #if SANITIZER_WINDOWS | ||
| 258 | # define INTERCEPTOR_WINAPI(ret_type, func, ...) \ | ||
| 259 | typedef ret_type (__stdcall *FUNC_TYPE(func))(__VA_ARGS__); \ | ||
| 260 | namespace __interception { \ | ||
| 261 | FUNC_TYPE(func) PTR_TO_REAL(func); \ | ||
| 262 | } \ | ||
| 263 | extern "C" \ | ||
| 264 | INTERCEPTOR_ATTRIBUTE \ | ||
| 265 | ret_type __stdcall WRAP(func)(__VA_ARGS__) | ||
| 266 | #endif | ||
| 267 | |||
| 268 | // ISO C++ forbids casting between pointer-to-function and pointer-to-object, | ||
| 269 | // so we use casting via an integral type __interception::uptr, | ||
| 270 | // assuming that system is POSIX-compliant. Using other hacks seem | ||
| 271 | // challenging, as we don't even pass function type to | ||
| 272 | // INTERCEPT_FUNCTION macro, only its name. | ||
| 273 | namespace __interception { | ||
| 274 | #if defined(_WIN64) | ||
| 275 | typedef unsigned long long uptr; | ||
| 276 | #else | ||
| 277 | typedef unsigned long uptr; | ||
| 278 | #endif // _WIN64 | ||
| 279 | } // namespace __interception | ||
| 280 | |||
| 281 | #define INCLUDED_FROM_INTERCEPTION_LIB | ||
| 282 | |||
| 283 | #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ | ||
| 284 | SANITIZER_OPENBSD || SANITIZER_SOLARIS | ||
| 285 | |||
| 286 | # include "interception_linux.h" | ||
| 287 | # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) | ||
| 288 | # define INTERCEPT_FUNCTION_VER(func, symver) \ | ||
| 289 | INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) | ||
| 290 | #elif SANITIZER_MAC | ||
| 291 | # include "interception_mac.h" | ||
| 292 | # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func) | ||
| 293 | # define INTERCEPT_FUNCTION_VER(func, symver) \ | ||
| 294 | INTERCEPT_FUNCTION_VER_MAC(func, symver) | ||
| 295 | #elif SANITIZER_WINDOWS | ||
| 296 | # include "interception_win.h" | ||
| 297 | # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func) | ||
| 298 | # define INTERCEPT_FUNCTION_VER(func, symver) \ | ||
| 299 | INTERCEPT_FUNCTION_VER_WIN(func, symver) | ||
| 300 | #endif | ||
| 301 | |||
| 302 | #undef INCLUDED_FROM_INTERCEPTION_LIB | ||
| 303 | |||
| 304 | #endif // INTERCEPTION_H | ||
lib/tsan/interception/interception_linux.h created+53| ... | @@ -0,0 +1,53 @@ | ||
| 1 | //===-- interception_linux.h ------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of AddressSanitizer, an address sanity checker. | ||
| 10 | // | ||
| 11 | // Linux-specific interception methods. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ | ||
| 15 | SANITIZER_OPENBSD || SANITIZER_SOLARIS | ||
| 16 | |||
| 17 | #if !defined(INCLUDED_FROM_INTERCEPTION_LIB) | ||
| 18 | # error "interception_linux.h should be included from interception library only" | ||
| 19 | #endif | ||
| 20 | |||
| 21 | #ifndef INTERCEPTION_LINUX_H | ||
| 22 | #define INTERCEPTION_LINUX_H | ||
| 23 | |||
| 24 | namespace __interception { | ||
| 25 | bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func, | ||
| 26 | uptr wrapper); | ||
| 27 | bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real, | ||
| 28 | uptr func, uptr wrapper); | ||
| 29 | } // namespace __interception | ||
| 30 | |||
| 31 | #define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) \ | ||
| 32 | ::__interception::InterceptFunction( \ | ||
| 33 | #func, \ | ||
| 34 | (::__interception::uptr *) & REAL(func), \ | ||
| 35 | (::__interception::uptr) & (func), \ | ||
| 36 | (::__interception::uptr) & WRAP(func)) | ||
| 37 | |||
| 38 | // Android, Solaris and OpenBSD do not have dlvsym | ||
| 39 | #if !SANITIZER_ANDROID && !SANITIZER_SOLARIS && !SANITIZER_OPENBSD | ||
| 40 | #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \ | ||
| 41 | ::__interception::InterceptFunction( \ | ||
| 42 | #func, symver, \ | ||
| 43 | (::__interception::uptr *) & REAL(func), \ | ||
| 44 | (::__interception::uptr) & (func), \ | ||
| 45 | (::__interception::uptr) & WRAP(func)) | ||
| 46 | #else | ||
| 47 | #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \ | ||
| 48 | INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) | ||
| 49 | #endif // !SANITIZER_ANDROID && !SANITIZER_SOLARIS | ||
| 50 | |||
| 51 | #endif // INTERCEPTION_LINUX_H | ||
| 52 | #endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || | ||
| 53 | // SANITIZER_OPENBSD || SANITIZER_SOLARIS | ||
lib/tsan/interception/interception_mac.h created+27| ... | @@ -0,0 +1,27 @@ | ||
| 1 | //===-- interception_mac.h --------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of AddressSanitizer, an address sanity checker. | ||
| 10 | // | ||
| 11 | // Mac-specific interception methods. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #if SANITIZER_MAC | ||
| 15 | |||
| 16 | #if !defined(INCLUDED_FROM_INTERCEPTION_LIB) | ||
| 17 | # error "interception_mac.h should be included from interception.h only" | ||
| 18 | #endif | ||
| 19 | |||
| 20 | #ifndef INTERCEPTION_MAC_H | ||
| 21 | #define INTERCEPTION_MAC_H | ||
| 22 | |||
| 23 | #define INTERCEPT_FUNCTION_MAC(func) | ||
| 24 | #define INTERCEPT_FUNCTION_VER_MAC(func, symver) | ||
| 25 | |||
| 26 | #endif // INTERCEPTION_MAC_H | ||
| 27 | #endif // SANITIZER_MAC | ||
lib/tsan/interception/interception_win.h created+83| ... | @@ -0,0 +1,83 @@ | ||
| 1 | //===-- interception_linux.h ------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of AddressSanitizer, an address sanity checker. | ||
| 10 | // | ||
| 11 | // Windows-specific interception methods. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #if SANITIZER_WINDOWS | ||
| 15 | |||
| 16 | #if !defined(INCLUDED_FROM_INTERCEPTION_LIB) | ||
| 17 | # error "interception_win.h should be included from interception library only" | ||
| 18 | #endif | ||
| 19 | |||
| 20 | #ifndef INTERCEPTION_WIN_H | ||
| 21 | #define INTERCEPTION_WIN_H | ||
| 22 | |||
| 23 | namespace __interception { | ||
| 24 | // All the functions in the OverrideFunction() family return true on success, | ||
| 25 | // false on failure (including "couldn't find the function"). | ||
| 26 | |||
| 27 | // Overrides a function by its address. | ||
| 28 | bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func = 0); | ||
| 29 | |||
| 30 | // Overrides a function in a system DLL or DLL CRT by its exported name. | ||
| 31 | bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func = 0); | ||
| 32 | |||
| 33 | // Windows-only replacement for GetProcAddress. Useful for some sanitizers. | ||
| 34 | uptr InternalGetProcAddress(void *module, const char *func_name); | ||
| 35 | |||
| 36 | // Overrides a function only when it is called from a specific DLL. For example, | ||
| 37 | // this is used to override calls to HeapAlloc/HeapFree from ucrtbase without | ||
| 38 | // affecting other third party libraries. | ||
| 39 | bool OverrideImportedFunction(const char *module_to_patch, | ||
| 40 | const char *imported_module, | ||
| 41 | const char *function_name, uptr new_function, | ||
| 42 | uptr *orig_old_func); | ||
| 43 | |||
| 44 | #if !SANITIZER_WINDOWS64 | ||
| 45 | // Exposed for unittests | ||
| 46 | bool OverrideFunctionWithDetour( | ||
| 47 | uptr old_func, uptr new_func, uptr *orig_old_func); | ||
| 48 | #endif | ||
| 49 | |||
| 50 | // Exposed for unittests | ||
| 51 | bool OverrideFunctionWithRedirectJump( | ||
| 52 | uptr old_func, uptr new_func, uptr *orig_old_func); | ||
| 53 | bool OverrideFunctionWithHotPatch( | ||
| 54 | uptr old_func, uptr new_func, uptr *orig_old_func); | ||
| 55 | bool OverrideFunctionWithTrampoline( | ||
| 56 | uptr old_func, uptr new_func, uptr *orig_old_func); | ||
| 57 | |||
| 58 | // Exposed for unittests | ||
| 59 | void TestOnlyReleaseTrampolineRegions(); | ||
| 60 | |||
| 61 | } // namespace __interception | ||
| 62 | |||
| 63 | #if defined(INTERCEPTION_DYNAMIC_CRT) | ||
| 64 | #define INTERCEPT_FUNCTION_WIN(func) \ | ||
| 65 | ::__interception::OverrideFunction(#func, \ | ||
| 66 | (::__interception::uptr)WRAP(func), \ | ||
| 67 | (::__interception::uptr *)&REAL(func)) | ||
| 68 | #else | ||
| 69 | #define INTERCEPT_FUNCTION_WIN(func) \ | ||
| 70 | ::__interception::OverrideFunction((::__interception::uptr)func, \ | ||
| 71 | (::__interception::uptr)WRAP(func), \ | ||
| 72 | (::__interception::uptr *)&REAL(func)) | ||
| 73 | #endif | ||
| 74 | |||
| 75 | #define INTERCEPT_FUNCTION_VER_WIN(func, symver) INTERCEPT_FUNCTION_WIN(func) | ||
| 76 | |||
| 77 | #define INTERCEPT_FUNCTION_DLLIMPORT(user_dll, provider_dll, func) \ | ||
| 78 | ::__interception::OverrideImportedFunction( \ | ||
| 79 | user_dll, provider_dll, #func, (::__interception::uptr)WRAP(func), \ | ||
| 80 | (::__interception::uptr *)&REAL(func)) | ||
| 81 | |||
| 82 | #endif // INTERCEPTION_WIN_H | ||
| 83 | #endif // SANITIZER_WINDOWS | ||
lib/tsan/sanitizer_common/sancov_flags.h created+39| ... | @@ -0,0 +1,39 @@ | ||
| 1 | //===-- sancov_flags.h ------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Sanitizer Coverage runtime flags. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANCOV_FLAGS_H | ||
| 13 | #define SANCOV_FLAGS_H | ||
| 14 | |||
| 15 | #include "sanitizer_flag_parser.h" | ||
| 16 | #include "sanitizer_internal_defs.h" | ||
| 17 | |||
| 18 | namespace __sancov { | ||
| 19 | |||
| 20 | struct SancovFlags { | ||
| 21 | #define SANCOV_FLAG(Type, Name, DefaultValue, Description) Type Name; | ||
| 22 | #include "sancov_flags.inc" | ||
| 23 | #undef SANCOV_FLAG | ||
| 24 | |||
| 25 | void SetDefaults(); | ||
| 26 | }; | ||
| 27 | |||
| 28 | extern SancovFlags sancov_flags_dont_use_directly; | ||
| 29 | |||
| 30 | inline SancovFlags* sancov_flags() { return &sancov_flags_dont_use_directly; } | ||
| 31 | |||
| 32 | void InitializeSancovFlags(); | ||
| 33 | |||
| 34 | } // namespace __sancov | ||
| 35 | |||
| 36 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char* | ||
| 37 | __sancov_default_options(); | ||
| 38 | |||
| 39 | #endif | ||
lib/tsan/sanitizer_common/sancov_flags.inc created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | //===-- sancov_flags.inc ----------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Sanitizer Coverage runtime flags. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANCOV_FLAG | ||
| 13 | #error "Defnine SANCOV_FLAG prior to including this file!" | ||
| 14 | #endif | ||
| 15 | |||
| 16 | SANCOV_FLAG(bool, symbolize, true, | ||
| 17 | "If set, converage information will be symbolized by sancov tool " | ||
| 18 | "after dumping.") | ||
| 19 | |||
| 20 | SANCOV_FLAG(bool, help, false, "Print flags help.") | ||
lib/tsan/sanitizer_common/sanitizer_addrhashmap.h created+353| ... | @@ -0,0 +1,353 @@ | ||
| 1 | //===-- sanitizer_addrhashmap.h ---------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Concurrent uptr->T hashmap. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef SANITIZER_ADDRHASHMAP_H | ||
| 14 | #define SANITIZER_ADDRHASHMAP_H | ||
| 15 | |||
| 16 | #include "sanitizer_common.h" | ||
| 17 | #include "sanitizer_mutex.h" | ||
| 18 | #include "sanitizer_atomic.h" | ||
| 19 | #include "sanitizer_allocator_internal.h" | ||
| 20 | |||
| 21 | namespace __sanitizer { | ||
| 22 | |||
| 23 | // Concurrent uptr->T hashmap. | ||
| 24 | // T must be a POD type, kSize is preferably a prime but can be any number. | ||
| 25 | // Usage example: | ||
| 26 | // | ||
| 27 | // typedef AddrHashMap<uptr, 11> Map; | ||
| 28 | // Map m; | ||
| 29 | // { | ||
| 30 | // Map::Handle h(&m, addr); | ||
| 31 | // use h.operator->() to access the data | ||
| 32 | // if h.created() then the element was just created, and the current thread | ||
| 33 | // has exclusive access to it | ||
| 34 | // otherwise the current thread has only read access to the data | ||
| 35 | // } | ||
| 36 | // { | ||
| 37 | // Map::Handle h(&m, addr, true); | ||
| 38 | // this will remove the data from the map in Handle dtor | ||
| 39 | // the current thread has exclusive access to the data | ||
| 40 | // if !h.exists() then the element never existed | ||
| 41 | // } | ||
| 42 | template<typename T, uptr kSize> | ||
| 43 | class AddrHashMap { | ||
| 44 | private: | ||
| 45 | struct Cell { | ||
| 46 | atomic_uintptr_t addr; | ||
| 47 | T val; | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct AddBucket { | ||
| 51 | uptr cap; | ||
| 52 | uptr size; | ||
| 53 | Cell cells[1]; // variable len | ||
| 54 | }; | ||
| 55 | |||
| 56 | static const uptr kBucketSize = 3; | ||
| 57 | |||
| 58 | struct Bucket { | ||
| 59 | RWMutex mtx; | ||
| 60 | atomic_uintptr_t add; | ||
| 61 | Cell cells[kBucketSize]; | ||
| 62 | }; | ||
| 63 | |||
| 64 | public: | ||
| 65 | AddrHashMap(); | ||
| 66 | |||
| 67 | class Handle { | ||
| 68 | public: | ||
| 69 | Handle(AddrHashMap<T, kSize> *map, uptr addr); | ||
| 70 | Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove); | ||
| 71 | Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove, bool create); | ||
| 72 | |||
| 73 | ~Handle(); | ||
| 74 | T *operator->(); | ||
| 75 | T &operator*(); | ||
| 76 | const T &operator*() const; | ||
| 77 | bool created() const; | ||
| 78 | bool exists() const; | ||
| 79 | |||
| 80 | private: | ||
| 81 | friend AddrHashMap<T, kSize>; | ||
| 82 | AddrHashMap<T, kSize> *map_; | ||
| 83 | Bucket *bucket_; | ||
| 84 | Cell *cell_; | ||
| 85 | uptr addr_; | ||
| 86 | uptr addidx_; | ||
| 87 | bool created_; | ||
| 88 | bool remove_; | ||
| 89 | bool create_; | ||
| 90 | }; | ||
| 91 | |||
| 92 | private: | ||
| 93 | friend class Handle; | ||
| 94 | Bucket *table_; | ||
| 95 | |||
| 96 | void acquire(Handle *h); | ||
| 97 | void release(Handle *h); | ||
| 98 | uptr calcHash(uptr addr); | ||
| 99 | }; | ||
| 100 | |||
| 101 | template<typename T, uptr kSize> | ||
| 102 | AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr) { | ||
| 103 | map_ = map; | ||
| 104 | addr_ = addr; | ||
| 105 | remove_ = false; | ||
| 106 | create_ = true; | ||
| 107 | map_->acquire(this); | ||
| 108 | } | ||
| 109 | |||
| 110 | template<typename T, uptr kSize> | ||
| 111 | AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr, | ||
| 112 | bool remove) { | ||
| 113 | map_ = map; | ||
| 114 | addr_ = addr; | ||
| 115 | remove_ = remove; | ||
| 116 | create_ = true; | ||
| 117 | map_->acquire(this); | ||
| 118 | } | ||
| 119 | |||
| 120 | template<typename T, uptr kSize> | ||
| 121 | AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr, | ||
| 122 | bool remove, bool create) { | ||
| 123 | map_ = map; | ||
| 124 | addr_ = addr; | ||
| 125 | remove_ = remove; | ||
| 126 | create_ = create; | ||
| 127 | map_->acquire(this); | ||
| 128 | } | ||
| 129 | |||
| 130 | template<typename T, uptr kSize> | ||
| 131 | AddrHashMap<T, kSize>::Handle::~Handle() { | ||
| 132 | map_->release(this); | ||
| 133 | } | ||
| 134 | |||
| 135 | template <typename T, uptr kSize> | ||
| 136 | T *AddrHashMap<T, kSize>::Handle::operator->() { | ||
| 137 | return &cell_->val; | ||
| 138 | } | ||
| 139 | |||
| 140 | template <typename T, uptr kSize> | ||
| 141 | const T &AddrHashMap<T, kSize>::Handle::operator*() const { | ||
| 142 | return cell_->val; | ||
| 143 | } | ||
| 144 | |||
| 145 | template <typename T, uptr kSize> | ||
| 146 | T &AddrHashMap<T, kSize>::Handle::operator*() { | ||
| 147 | return cell_->val; | ||
| 148 | } | ||
| 149 | |||
| 150 | template<typename T, uptr kSize> | ||
| 151 | bool AddrHashMap<T, kSize>::Handle::created() const { | ||
| 152 | return created_; | ||
| 153 | } | ||
| 154 | |||
| 155 | template<typename T, uptr kSize> | ||
| 156 | bool AddrHashMap<T, kSize>::Handle::exists() const { | ||
| 157 | return cell_ != nullptr; | ||
| 158 | } | ||
| 159 | |||
| 160 | template<typename T, uptr kSize> | ||
| 161 | AddrHashMap<T, kSize>::AddrHashMap() { | ||
| 162 | table_ = (Bucket*)MmapOrDie(kSize * sizeof(table_[0]), "AddrHashMap"); | ||
| 163 | } | ||
| 164 | |||
| 165 | template<typename T, uptr kSize> | ||
| 166 | void AddrHashMap<T, kSize>::acquire(Handle *h) { | ||
| 167 | uptr addr = h->addr_; | ||
| 168 | uptr hash = calcHash(addr); | ||
| 169 | Bucket *b = &table_[hash]; | ||
| 170 | |||
| 171 | h->created_ = false; | ||
| 172 | h->addidx_ = -1U; | ||
| 173 | h->bucket_ = b; | ||
| 174 | h->cell_ = nullptr; | ||
| 175 | |||
| 176 | // If we want to remove the element, we need exclusive access to the bucket, | ||
| 177 | // so skip the lock-free phase. | ||
| 178 | if (h->remove_) | ||
| 179 | goto locked; | ||
| 180 | |||
| 181 | retry: | ||
| 182 | // First try to find an existing element w/o read mutex. | ||
| 183 | CHECK(!h->remove_); | ||
| 184 | // Check the embed cells. | ||
| 185 | for (uptr i = 0; i < kBucketSize; i++) { | ||
| 186 | Cell *c = &b->cells[i]; | ||
| 187 | uptr addr1 = atomic_load(&c->addr, memory_order_acquire); | ||
| 188 | if (addr1 == addr) { | ||
| 189 | h->cell_ = c; | ||
| 190 | return; | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | // Check the add cells with read lock. | ||
| 195 | if (atomic_load(&b->add, memory_order_relaxed)) { | ||
| 196 | b->mtx.ReadLock(); | ||
| 197 | AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed); | ||
| 198 | for (uptr i = 0; i < add->size; i++) { | ||
| 199 | Cell *c = &add->cells[i]; | ||
| 200 | uptr addr1 = atomic_load(&c->addr, memory_order_relaxed); | ||
| 201 | if (addr1 == addr) { | ||
| 202 | h->addidx_ = i; | ||
| 203 | h->cell_ = c; | ||
| 204 | return; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | b->mtx.ReadUnlock(); | ||
| 208 | } | ||
| 209 | |||
| 210 | locked: | ||
| 211 | // Re-check existence under write lock. | ||
| 212 | // Embed cells. | ||
| 213 | b->mtx.Lock(); | ||
| 214 | for (uptr i = 0; i < kBucketSize; i++) { | ||
| 215 | Cell *c = &b->cells[i]; | ||
| 216 | uptr addr1 = atomic_load(&c->addr, memory_order_relaxed); | ||
| 217 | if (addr1 == addr) { | ||
| 218 | if (h->remove_) { | ||
| 219 | h->cell_ = c; | ||
| 220 | return; | ||
| 221 | } | ||
| 222 | b->mtx.Unlock(); | ||
| 223 | goto retry; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | // Add cells. | ||
| 228 | AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed); | ||
| 229 | if (add) { | ||
| 230 | for (uptr i = 0; i < add->size; i++) { | ||
| 231 | Cell *c = &add->cells[i]; | ||
| 232 | uptr addr1 = atomic_load(&c->addr, memory_order_relaxed); | ||
| 233 | if (addr1 == addr) { | ||
| 234 | if (h->remove_) { | ||
| 235 | h->addidx_ = i; | ||
| 236 | h->cell_ = c; | ||
| 237 | return; | ||
| 238 | } | ||
| 239 | b->mtx.Unlock(); | ||
| 240 | goto retry; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | // The element does not exist, no need to create it if we want to remove. | ||
| 246 | if (h->remove_ || !h->create_) { | ||
| 247 | b->mtx.Unlock(); | ||
| 248 | return; | ||
| 249 | } | ||
| 250 | |||
| 251 | // Now try to create it under the mutex. | ||
| 252 | h->created_ = true; | ||
| 253 | // See if we have a free embed cell. | ||
| 254 | for (uptr i = 0; i < kBucketSize; i++) { | ||
| 255 | Cell *c = &b->cells[i]; | ||
| 256 | uptr addr1 = atomic_load(&c->addr, memory_order_relaxed); | ||
| 257 | if (addr1 == 0) { | ||
| 258 | h->cell_ = c; | ||
| 259 | return; | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | // Store in the add cells. | ||
| 264 | if (!add) { | ||
| 265 | // Allocate a new add array. | ||
| 266 | const uptr kInitSize = 64; | ||
| 267 | add = (AddBucket*)InternalAlloc(kInitSize); | ||
| 268 | internal_memset(add, 0, kInitSize); | ||
| 269 | add->cap = (kInitSize - sizeof(*add)) / sizeof(add->cells[0]) + 1; | ||
| 270 | add->size = 0; | ||
| 271 | atomic_store(&b->add, (uptr)add, memory_order_relaxed); | ||
| 272 | } | ||
| 273 | if (add->size == add->cap) { | ||
| 274 | // Grow existing add array. | ||
| 275 | uptr oldsize = sizeof(*add) + (add->cap - 1) * sizeof(add->cells[0]); | ||
| 276 | uptr newsize = oldsize * 2; | ||
| 277 | AddBucket *add1 = (AddBucket*)InternalAlloc(newsize); | ||
| 278 | internal_memset(add1, 0, newsize); | ||
| 279 | add1->cap = (newsize - sizeof(*add)) / sizeof(add->cells[0]) + 1; | ||
| 280 | add1->size = add->size; | ||
| 281 | internal_memcpy(add1->cells, add->cells, add->size * sizeof(add->cells[0])); | ||
| 282 | InternalFree(add); | ||
| 283 | atomic_store(&b->add, (uptr)add1, memory_order_relaxed); | ||
| 284 | add = add1; | ||
| 285 | } | ||
| 286 | // Store. | ||
| 287 | uptr i = add->size++; | ||
| 288 | Cell *c = &add->cells[i]; | ||
| 289 | CHECK_EQ(atomic_load(&c->addr, memory_order_relaxed), 0); | ||
| 290 | h->addidx_ = i; | ||
| 291 | h->cell_ = c; | ||
| 292 | } | ||
| 293 | |||
| 294 | template<typename T, uptr kSize> | ||
| 295 | void AddrHashMap<T, kSize>::release(Handle *h) { | ||
| 296 | if (!h->cell_) | ||
| 297 | return; | ||
| 298 | Bucket *b = h->bucket_; | ||
| 299 | Cell *c = h->cell_; | ||
| 300 | uptr addr1 = atomic_load(&c->addr, memory_order_relaxed); | ||
| 301 | if (h->created_) { | ||
| 302 | // Denote completion of insertion. | ||
| 303 | CHECK_EQ(addr1, 0); | ||
| 304 | // After the following store, the element becomes available | ||
| 305 | // for lock-free reads. | ||
| 306 | atomic_store(&c->addr, h->addr_, memory_order_release); | ||
| 307 | b->mtx.Unlock(); | ||
| 308 | } else if (h->remove_) { | ||
| 309 | // Denote that the cell is empty now. | ||
| 310 | CHECK_EQ(addr1, h->addr_); | ||
| 311 | atomic_store(&c->addr, 0, memory_order_release); | ||
| 312 | // See if we need to compact the bucket. | ||
| 313 | AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed); | ||
| 314 | if (h->addidx_ == -1U) { | ||
| 315 | // Removed from embed array, move an add element into the freed cell. | ||
| 316 | if (add && add->size != 0) { | ||
| 317 | uptr last = --add->size; | ||
| 318 | Cell *c1 = &add->cells[last]; | ||
| 319 | c->val = c1->val; | ||
| 320 | uptr addr1 = atomic_load(&c1->addr, memory_order_relaxed); | ||
| 321 | atomic_store(&c->addr, addr1, memory_order_release); | ||
| 322 | atomic_store(&c1->addr, 0, memory_order_release); | ||
| 323 | } | ||
| 324 | } else { | ||
| 325 | // Removed from add array, compact it. | ||
| 326 | uptr last = --add->size; | ||
| 327 | Cell *c1 = &add->cells[last]; | ||
| 328 | if (c != c1) { | ||
| 329 | *c = *c1; | ||
| 330 | atomic_store(&c1->addr, 0, memory_order_relaxed); | ||
| 331 | } | ||
| 332 | } | ||
| 333 | if (add && add->size == 0) { | ||
| 334 | // FIXME(dvyukov): free add? | ||
| 335 | } | ||
| 336 | b->mtx.Unlock(); | ||
| 337 | } else { | ||
| 338 | CHECK_EQ(addr1, h->addr_); | ||
| 339 | if (h->addidx_ != -1U) | ||
| 340 | b->mtx.ReadUnlock(); | ||
| 341 | } | ||
| 342 | } | ||
| 343 | |||
| 344 | template<typename T, uptr kSize> | ||
| 345 | uptr AddrHashMap<T, kSize>::calcHash(uptr addr) { | ||
| 346 | addr += addr << 10; | ||
| 347 | addr ^= addr >> 6; | ||
| 348 | return addr % kSize; | ||
| 349 | } | ||
| 350 | |||
| 351 | } // namespace __sanitizer | ||
| 352 | |||
| 353 | #endif // SANITIZER_ADDRHASHMAP_H | ||
lib/tsan/sanitizer_common/sanitizer_allocator.cpp created+267| ... | @@ -0,0 +1,267 @@ | ||
| 1 | //===-- sanitizer_allocator.cpp -------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer | ||
| 10 | // run-time libraries. | ||
| 11 | // This allocator is used inside run-times. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_allocator.h" | ||
| 15 | |||
| 16 | #include "sanitizer_allocator_checks.h" | ||
| 17 | #include "sanitizer_allocator_internal.h" | ||
| 18 | #include "sanitizer_atomic.h" | ||
| 19 | #include "sanitizer_common.h" | ||
| 20 | |||
| 21 | namespace __sanitizer { | ||
| 22 | |||
| 23 | // Default allocator names. | ||
| 24 | const char *PrimaryAllocatorName = "SizeClassAllocator"; | ||
| 25 | const char *SecondaryAllocatorName = "LargeMmapAllocator"; | ||
| 26 | |||
| 27 | // ThreadSanitizer for Go uses libc malloc/free. | ||
| 28 | #if defined(SANITIZER_USE_MALLOC) | ||
| 29 | # if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 30 | extern "C" void *__libc_malloc(uptr size); | ||
| 31 | # if !SANITIZER_GO | ||
| 32 | extern "C" void *__libc_memalign(uptr alignment, uptr size); | ||
| 33 | # endif | ||
| 34 | extern "C" void *__libc_realloc(void *ptr, uptr size); | ||
| 35 | extern "C" void __libc_free(void *ptr); | ||
| 36 | # else | ||
| 37 | # include <stdlib.h> | ||
| 38 | # define __libc_malloc malloc | ||
| 39 | # if !SANITIZER_GO | ||
| 40 | static void *__libc_memalign(uptr alignment, uptr size) { | ||
| 41 | void *p; | ||
| 42 | uptr error = posix_memalign(&p, alignment, size); | ||
| 43 | if (error) return nullptr; | ||
| 44 | return p; | ||
| 45 | } | ||
| 46 | # endif | ||
| 47 | # define __libc_realloc realloc | ||
| 48 | # define __libc_free free | ||
| 49 | # endif | ||
| 50 | |||
| 51 | static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache, | ||
| 52 | uptr alignment) { | ||
| 53 | (void)cache; | ||
| 54 | #if !SANITIZER_GO | ||
| 55 | if (alignment == 0) | ||
| 56 | return __libc_malloc(size); | ||
| 57 | else | ||
| 58 | return __libc_memalign(alignment, size); | ||
| 59 | #else | ||
| 60 | // Windows does not provide __libc_memalign/posix_memalign. It provides | ||
| 61 | // __aligned_malloc, but the allocated blocks can't be passed to free, | ||
| 62 | // they need to be passed to __aligned_free. InternalAlloc interface does | ||
| 63 | // not account for such requirement. Alignemnt does not seem to be used | ||
| 64 | // anywhere in runtime, so just call __libc_malloc for now. | ||
| 65 | DCHECK_EQ(alignment, 0); | ||
| 66 | return __libc_malloc(size); | ||
| 67 | #endif | ||
| 68 | } | ||
| 69 | |||
| 70 | static void *RawInternalRealloc(void *ptr, uptr size, | ||
| 71 | InternalAllocatorCache *cache) { | ||
| 72 | (void)cache; | ||
| 73 | return __libc_realloc(ptr, size); | ||
| 74 | } | ||
| 75 | |||
| 76 | static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) { | ||
| 77 | (void)cache; | ||
| 78 | __libc_free(ptr); | ||
| 79 | } | ||
| 80 | |||
| 81 | InternalAllocator *internal_allocator() { | ||
| 82 | return 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | #else // SANITIZER_GO || defined(SANITIZER_USE_MALLOC) | ||
| 86 | |||
| 87 | static ALIGNED(64) char internal_alloc_placeholder[sizeof(InternalAllocator)]; | ||
| 88 | static atomic_uint8_t internal_allocator_initialized; | ||
| 89 | static StaticSpinMutex internal_alloc_init_mu; | ||
| 90 | |||
| 91 | static InternalAllocatorCache internal_allocator_cache; | ||
| 92 | static StaticSpinMutex internal_allocator_cache_mu; | ||
| 93 | |||
| 94 | InternalAllocator *internal_allocator() { | ||
| 95 | InternalAllocator *internal_allocator_instance = | ||
| 96 | reinterpret_cast<InternalAllocator *>(&internal_alloc_placeholder); | ||
| 97 | if (atomic_load(&internal_allocator_initialized, memory_order_acquire) == 0) { | ||
| 98 | SpinMutexLock l(&internal_alloc_init_mu); | ||
| 99 | if (atomic_load(&internal_allocator_initialized, memory_order_relaxed) == | ||
| 100 | 0) { | ||
| 101 | internal_allocator_instance->Init(kReleaseToOSIntervalNever); | ||
| 102 | atomic_store(&internal_allocator_initialized, 1, memory_order_release); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | return internal_allocator_instance; | ||
| 106 | } | ||
| 107 | |||
| 108 | static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache, | ||
| 109 | uptr alignment) { | ||
| 110 | if (alignment == 0) alignment = 8; | ||
| 111 | if (cache == 0) { | ||
| 112 | SpinMutexLock l(&internal_allocator_cache_mu); | ||
| 113 | return internal_allocator()->Allocate(&internal_allocator_cache, size, | ||
| 114 | alignment); | ||
| 115 | } | ||
| 116 | return internal_allocator()->Allocate(cache, size, alignment); | ||
| 117 | } | ||
| 118 | |||
| 119 | static void *RawInternalRealloc(void *ptr, uptr size, | ||
| 120 | InternalAllocatorCache *cache) { | ||
| 121 | uptr alignment = 8; | ||
| 122 | if (cache == 0) { | ||
| 123 | SpinMutexLock l(&internal_allocator_cache_mu); | ||
| 124 | return internal_allocator()->Reallocate(&internal_allocator_cache, ptr, | ||
| 125 | size, alignment); | ||
| 126 | } | ||
| 127 | return internal_allocator()->Reallocate(cache, ptr, size, alignment); | ||
| 128 | } | ||
| 129 | |||
| 130 | static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) { | ||
| 131 | if (!cache) { | ||
| 132 | SpinMutexLock l(&internal_allocator_cache_mu); | ||
| 133 | return internal_allocator()->Deallocate(&internal_allocator_cache, ptr); | ||
| 134 | } | ||
| 135 | internal_allocator()->Deallocate(cache, ptr); | ||
| 136 | } | ||
| 137 | |||
| 138 | #endif // SANITIZER_GO || defined(SANITIZER_USE_MALLOC) | ||
| 139 | |||
| 140 | const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull; | ||
| 141 | |||
| 142 | static void NORETURN ReportInternalAllocatorOutOfMemory(uptr requested_size) { | ||
| 143 | SetAllocatorOutOfMemory(); | ||
| 144 | Report("FATAL: %s: internal allocator is out of memory trying to allocate " | ||
| 145 | "0x%zx bytes\n", SanitizerToolName, requested_size); | ||
| 146 | Die(); | ||
| 147 | } | ||
| 148 | |||
| 149 | void *InternalAlloc(uptr size, InternalAllocatorCache *cache, uptr alignment) { | ||
| 150 | if (size + sizeof(u64) < size) | ||
| 151 | return nullptr; | ||
| 152 | void *p = RawInternalAlloc(size + sizeof(u64), cache, alignment); | ||
| 153 | if (UNLIKELY(!p)) | ||
| 154 | ReportInternalAllocatorOutOfMemory(size + sizeof(u64)); | ||
| 155 | ((u64*)p)[0] = kBlockMagic; | ||
| 156 | return (char*)p + sizeof(u64); | ||
| 157 | } | ||
| 158 | |||
| 159 | void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) { | ||
| 160 | if (!addr) | ||
| 161 | return InternalAlloc(size, cache); | ||
| 162 | if (size + sizeof(u64) < size) | ||
| 163 | return nullptr; | ||
| 164 | addr = (char*)addr - sizeof(u64); | ||
| 165 | size = size + sizeof(u64); | ||
| 166 | CHECK_EQ(kBlockMagic, ((u64*)addr)[0]); | ||
| 167 | void *p = RawInternalRealloc(addr, size, cache); | ||
| 168 | if (UNLIKELY(!p)) | ||
| 169 | ReportInternalAllocatorOutOfMemory(size); | ||
| 170 | return (char*)p + sizeof(u64); | ||
| 171 | } | ||
| 172 | |||
| 173 | void *InternalReallocArray(void *addr, uptr count, uptr size, | ||
| 174 | InternalAllocatorCache *cache) { | ||
| 175 | if (UNLIKELY(CheckForCallocOverflow(count, size))) { | ||
| 176 | Report( | ||
| 177 | "FATAL: %s: reallocarray parameters overflow: count * size (%zd * %zd) " | ||
| 178 | "cannot be represented in type size_t\n", | ||
| 179 | SanitizerToolName, count, size); | ||
| 180 | Die(); | ||
| 181 | } | ||
| 182 | return InternalRealloc(addr, count * size, cache); | ||
| 183 | } | ||
| 184 | |||
| 185 | void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) { | ||
| 186 | if (UNLIKELY(CheckForCallocOverflow(count, size))) { | ||
| 187 | Report("FATAL: %s: calloc parameters overflow: count * size (%zd * %zd) " | ||
| 188 | "cannot be represented in type size_t\n", SanitizerToolName, count, | ||
| 189 | size); | ||
| 190 | Die(); | ||
| 191 | } | ||
| 192 | void *p = InternalAlloc(count * size, cache); | ||
| 193 | if (LIKELY(p)) | ||
| 194 | internal_memset(p, 0, count * size); | ||
| 195 | return p; | ||
| 196 | } | ||
| 197 | |||
| 198 | void InternalFree(void *addr, InternalAllocatorCache *cache) { | ||
| 199 | if (!addr) | ||
| 200 | return; | ||
| 201 | addr = (char*)addr - sizeof(u64); | ||
| 202 | CHECK_EQ(kBlockMagic, ((u64*)addr)[0]); | ||
| 203 | ((u64*)addr)[0] = 0; | ||
| 204 | RawInternalFree(addr, cache); | ||
| 205 | } | ||
| 206 | |||
| 207 | // LowLevelAllocator | ||
| 208 | constexpr uptr kLowLevelAllocatorDefaultAlignment = 8; | ||
| 209 | static uptr low_level_alloc_min_alignment = kLowLevelAllocatorDefaultAlignment; | ||
| 210 | static LowLevelAllocateCallback low_level_alloc_callback; | ||
| 211 | |||
| 212 | void *LowLevelAllocator::Allocate(uptr size) { | ||
| 213 | // Align allocation size. | ||
| 214 | size = RoundUpTo(size, low_level_alloc_min_alignment); | ||
| 215 | if (allocated_end_ - allocated_current_ < (sptr)size) { | ||
| 216 | uptr size_to_allocate = RoundUpTo(size, GetPageSizeCached()); | ||
| 217 | allocated_current_ = | ||
| 218 | (char*)MmapOrDie(size_to_allocate, __func__); | ||
| 219 | allocated_end_ = allocated_current_ + size_to_allocate; | ||
| 220 | if (low_level_alloc_callback) { | ||
| 221 | low_level_alloc_callback((uptr)allocated_current_, | ||
| 222 | size_to_allocate); | ||
| 223 | } | ||
| 224 | } | ||
| 225 | CHECK(allocated_end_ - allocated_current_ >= (sptr)size); | ||
| 226 | void *res = allocated_current_; | ||
| 227 | allocated_current_ += size; | ||
| 228 | return res; | ||
| 229 | } | ||
| 230 | |||
| 231 | void SetLowLevelAllocateMinAlignment(uptr alignment) { | ||
| 232 | CHECK(IsPowerOfTwo(alignment)); | ||
| 233 | low_level_alloc_min_alignment = Max(alignment, low_level_alloc_min_alignment); | ||
| 234 | } | ||
| 235 | |||
| 236 | void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) { | ||
| 237 | low_level_alloc_callback = callback; | ||
| 238 | } | ||
| 239 | |||
| 240 | // Allocator's OOM and other errors handling support. | ||
| 241 | |||
| 242 | static atomic_uint8_t allocator_out_of_memory = {0}; | ||
| 243 | static atomic_uint8_t allocator_may_return_null = {0}; | ||
| 244 | |||
| 245 | bool IsAllocatorOutOfMemory() { | ||
| 246 | return atomic_load_relaxed(&allocator_out_of_memory); | ||
| 247 | } | ||
| 248 | |||
| 249 | void SetAllocatorOutOfMemory() { | ||
| 250 | atomic_store_relaxed(&allocator_out_of_memory, 1); | ||
| 251 | } | ||
| 252 | |||
| 253 | bool AllocatorMayReturnNull() { | ||
| 254 | return atomic_load(&allocator_may_return_null, memory_order_relaxed); | ||
| 255 | } | ||
| 256 | |||
| 257 | void SetAllocatorMayReturnNull(bool may_return_null) { | ||
| 258 | atomic_store(&allocator_may_return_null, may_return_null, | ||
| 259 | memory_order_relaxed); | ||
| 260 | } | ||
| 261 | |||
| 262 | void PrintHintAllocatorCannotReturnNull() { | ||
| 263 | Report("HINT: if you don't care about these errors you may set " | ||
| 264 | "allocator_may_return_null=1\n"); | ||
| 265 | } | ||
| 266 | |||
| 267 | } // namespace __sanitizer | ||
lib/tsan/sanitizer_common/sanitizer_allocator.h created+81| ... | @@ -0,0 +1,81 @@ | ||
| 1 | //===-- sanitizer_allocator.h -----------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Specialized memory allocator for ThreadSanitizer, MemorySanitizer, etc. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef SANITIZER_ALLOCATOR_H | ||
| 14 | #define SANITIZER_ALLOCATOR_H | ||
| 15 | |||
| 16 | #include "sanitizer_common.h" | ||
| 17 | #include "sanitizer_internal_defs.h" | ||
| 18 | #include "sanitizer_lfstack.h" | ||
| 19 | #include "sanitizer_libc.h" | ||
| 20 | #include "sanitizer_list.h" | ||
| 21 | #include "sanitizer_local_address_space_view.h" | ||
| 22 | #include "sanitizer_mutex.h" | ||
| 23 | #include "sanitizer_procmaps.h" | ||
| 24 | #include "sanitizer_type_traits.h" | ||
| 25 | |||
| 26 | namespace __sanitizer { | ||
| 27 | |||
| 28 | // Allows the tools to name their allocations appropriately. | ||
| 29 | extern const char *PrimaryAllocatorName; | ||
| 30 | extern const char *SecondaryAllocatorName; | ||
| 31 | |||
| 32 | // Since flags are immutable and allocator behavior can be changed at runtime | ||
| 33 | // (unit tests or ASan on Android are some examples), allocator_may_return_null | ||
| 34 | // flag value is cached here and can be altered later. | ||
| 35 | bool AllocatorMayReturnNull(); | ||
| 36 | void SetAllocatorMayReturnNull(bool may_return_null); | ||
| 37 | |||
| 38 | // Returns true if allocator detected OOM condition. Can be used to avoid memory | ||
| 39 | // hungry operations. | ||
| 40 | bool IsAllocatorOutOfMemory(); | ||
| 41 | // Should be called by a particular allocator when OOM is detected. | ||
| 42 | void SetAllocatorOutOfMemory(); | ||
| 43 | |||
| 44 | void PrintHintAllocatorCannotReturnNull(); | ||
| 45 | |||
| 46 | // Allocators call these callbacks on mmap/munmap. | ||
| 47 | struct NoOpMapUnmapCallback { | ||
| 48 | void OnMap(uptr p, uptr size) const { } | ||
| 49 | void OnUnmap(uptr p, uptr size) const { } | ||
| 50 | }; | ||
| 51 | |||
| 52 | // Callback type for iterating over chunks. | ||
| 53 | typedef void (*ForEachChunkCallback)(uptr chunk, void *arg); | ||
| 54 | |||
| 55 | INLINE u32 Rand(u32 *state) { // ANSI C linear congruential PRNG. | ||
| 56 | return (*state = *state * 1103515245 + 12345) >> 16; | ||
| 57 | } | ||
| 58 | |||
| 59 | INLINE u32 RandN(u32 *state, u32 n) { return Rand(state) % n; } // [0, n) | ||
| 60 | |||
| 61 | template<typename T> | ||
| 62 | INLINE void RandomShuffle(T *a, u32 n, u32 *rand_state) { | ||
| 63 | if (n <= 1) return; | ||
| 64 | u32 state = *rand_state; | ||
| 65 | for (u32 i = n - 1; i > 0; i--) | ||
| 66 | Swap(a[i], a[RandN(&state, i + 1)]); | ||
| 67 | *rand_state = state; | ||
| 68 | } | ||
| 69 | |||
| 70 | #include "sanitizer_allocator_size_class_map.h" | ||
| 71 | #include "sanitizer_allocator_stats.h" | ||
| 72 | #include "sanitizer_allocator_primary64.h" | ||
| 73 | #include "sanitizer_allocator_bytemap.h" | ||
| 74 | #include "sanitizer_allocator_primary32.h" | ||
| 75 | #include "sanitizer_allocator_local_cache.h" | ||
| 76 | #include "sanitizer_allocator_secondary.h" | ||
| 77 | #include "sanitizer_allocator_combined.h" | ||
| 78 | |||
| 79 | } // namespace __sanitizer | ||
| 80 | |||
| 81 | #endif // SANITIZER_ALLOCATOR_H | ||
lib/tsan/sanitizer_common/sanitizer_allocator_bytemap.h created+107| ... | @@ -0,0 +1,107 @@ | ||
| 1 | //===-- sanitizer_allocator_bytemap.h ---------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Part of the Sanitizer Allocator. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_ALLOCATOR_H | ||
| 13 | #error This file must be included inside sanitizer_allocator.h | ||
| 14 | #endif | ||
| 15 | |||
| 16 | // Maps integers in rage [0, kSize) to u8 values. | ||
| 17 | template <u64 kSize, typename AddressSpaceViewTy = LocalAddressSpaceView> | ||
| 18 | class FlatByteMap { | ||
| 19 | public: | ||
| 20 | using AddressSpaceView = AddressSpaceViewTy; | ||
| 21 | void Init() { | ||
| 22 | internal_memset(map_, 0, sizeof(map_)); | ||
| 23 | } | ||
| 24 | |||
| 25 | void set(uptr idx, u8 val) { | ||
| 26 | CHECK_LT(idx, kSize); | ||
| 27 | CHECK_EQ(0U, map_[idx]); | ||
| 28 | map_[idx] = val; | ||
| 29 | } | ||
| 30 | u8 operator[] (uptr idx) { | ||
| 31 | CHECK_LT(idx, kSize); | ||
| 32 | // FIXME: CHECK may be too expensive here. | ||
| 33 | return map_[idx]; | ||
| 34 | } | ||
| 35 | private: | ||
| 36 | u8 map_[kSize]; | ||
| 37 | }; | ||
| 38 | |||
| 39 | // TwoLevelByteMap maps integers in range [0, kSize1*kSize2) to u8 values. | ||
| 40 | // It is implemented as a two-dimensional array: array of kSize1 pointers | ||
| 41 | // to kSize2-byte arrays. The secondary arrays are mmaped on demand. | ||
| 42 | // Each value is initially zero and can be set to something else only once. | ||
| 43 | // Setting and getting values from multiple threads is safe w/o extra locking. | ||
| 44 | template <u64 kSize1, u64 kSize2, | ||
| 45 | typename AddressSpaceViewTy = LocalAddressSpaceView, | ||
| 46 | class MapUnmapCallback = NoOpMapUnmapCallback> | ||
| 47 | class TwoLevelByteMap { | ||
| 48 | public: | ||
| 49 | using AddressSpaceView = AddressSpaceViewTy; | ||
| 50 | void Init() { | ||
| 51 | internal_memset(map1_, 0, sizeof(map1_)); | ||
| 52 | mu_.Init(); | ||
| 53 | } | ||
| 54 | |||
| 55 | void TestOnlyUnmap() { | ||
| 56 | for (uptr i = 0; i < kSize1; i++) { | ||
| 57 | u8 *p = Get(i); | ||
| 58 | if (!p) continue; | ||
| 59 | MapUnmapCallback().OnUnmap(reinterpret_cast<uptr>(p), kSize2); | ||
| 60 | UnmapOrDie(p, kSize2); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | uptr size() const { return kSize1 * kSize2; } | ||
| 65 | uptr size1() const { return kSize1; } | ||
| 66 | uptr size2() const { return kSize2; } | ||
| 67 | |||
| 68 | void set(uptr idx, u8 val) { | ||
| 69 | CHECK_LT(idx, kSize1 * kSize2); | ||
| 70 | u8 *map2 = GetOrCreate(idx / kSize2); | ||
| 71 | CHECK_EQ(0U, map2[idx % kSize2]); | ||
| 72 | map2[idx % kSize2] = val; | ||
| 73 | } | ||
| 74 | |||
| 75 | u8 operator[] (uptr idx) const { | ||
| 76 | CHECK_LT(idx, kSize1 * kSize2); | ||
| 77 | u8 *map2 = Get(idx / kSize2); | ||
| 78 | if (!map2) return 0; | ||
| 79 | auto value_ptr = AddressSpaceView::Load(&map2[idx % kSize2]); | ||
| 80 | return *value_ptr; | ||
| 81 | } | ||
| 82 | |||
| 83 | private: | ||
| 84 | u8 *Get(uptr idx) const { | ||
| 85 | CHECK_LT(idx, kSize1); | ||
| 86 | return reinterpret_cast<u8 *>( | ||
| 87 | atomic_load(&map1_[idx], memory_order_acquire)); | ||
| 88 | } | ||
| 89 | |||
| 90 | u8 *GetOrCreate(uptr idx) { | ||
| 91 | u8 *res = Get(idx); | ||
| 92 | if (!res) { | ||
| 93 | SpinMutexLock l(&mu_); | ||
| 94 | if (!(res = Get(idx))) { | ||
| 95 | res = (u8*)MmapOrDie(kSize2, "TwoLevelByteMap"); | ||
| 96 | MapUnmapCallback().OnMap(reinterpret_cast<uptr>(res), kSize2); | ||
| 97 | atomic_store(&map1_[idx], reinterpret_cast<uptr>(res), | ||
| 98 | memory_order_release); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | return res; | ||
| 102 | } | ||
| 103 | |||
| 104 | atomic_uintptr_t map1_[kSize1]; | ||
| 105 | StaticSpinMutex mu_; | ||
| 106 | }; | ||
| 107 | |||
lib/tsan/sanitizer_common/sanitizer_allocator_checks.h created+76| ... | @@ -0,0 +1,76 @@ | ||
| 1 | //===-- sanitizer_allocator_checks.h ----------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Various checks shared between ThreadSanitizer, MemorySanitizer, etc. memory | ||
| 10 | // allocators. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_ALLOCATOR_CHECKS_H | ||
| 15 | #define SANITIZER_ALLOCATOR_CHECKS_H | ||
| 16 | |||
| 17 | #include "sanitizer_internal_defs.h" | ||
| 18 | #include "sanitizer_common.h" | ||
| 19 | #include "sanitizer_platform.h" | ||
| 20 | |||
| 21 | namespace __sanitizer { | ||
| 22 | |||
| 23 | // The following is defined in a separate compilation unit to avoid pulling in | ||
| 24 | // sanitizer_errno.h in this header, which leads to conflicts when other system | ||
| 25 | // headers include errno.h. This is usually the result of an unlikely event, | ||
| 26 | // and as such we do not care as much about having it inlined. | ||
| 27 | void SetErrnoToENOMEM(); | ||
| 28 | |||
| 29 | // A common errno setting logic shared by almost all sanitizer allocator APIs. | ||
| 30 | INLINE void *SetErrnoOnNull(void *ptr) { | ||
| 31 | if (UNLIKELY(!ptr)) | ||
| 32 | SetErrnoToENOMEM(); | ||
| 33 | return ptr; | ||
| 34 | } | ||
| 35 | |||
| 36 | // In case of the check failure, the caller of the following Check... functions | ||
| 37 | // should "return POLICY::OnBadRequest();" where POLICY is the current allocator | ||
| 38 | // failure handling policy. | ||
| 39 | |||
| 40 | // Checks aligned_alloc() parameters, verifies that the alignment is a power of | ||
| 41 | // two and that the size is a multiple of alignment for POSIX implementation, | ||
| 42 | // and a bit relaxed requirement for non-POSIX ones, that the size is a multiple | ||
| 43 | // of alignment. | ||
| 44 | INLINE bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) { | ||
| 45 | #if SANITIZER_POSIX | ||
| 46 | return alignment != 0 && IsPowerOfTwo(alignment) && | ||
| 47 | (size & (alignment - 1)) == 0; | ||
| 48 | #else | ||
| 49 | return alignment != 0 && size % alignment == 0; | ||
| 50 | #endif | ||
| 51 | } | ||
| 52 | |||
| 53 | // Checks posix_memalign() parameters, verifies that alignment is a power of two | ||
| 54 | // and a multiple of sizeof(void *). | ||
| 55 | INLINE bool CheckPosixMemalignAlignment(uptr alignment) { | ||
| 56 | return alignment != 0 && IsPowerOfTwo(alignment) && | ||
| 57 | (alignment % sizeof(void *)) == 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | // Returns true if calloc(size, n) call overflows on size*n calculation. | ||
| 61 | INLINE bool CheckForCallocOverflow(uptr size, uptr n) { | ||
| 62 | if (!size) | ||
| 63 | return false; | ||
| 64 | uptr max = (uptr)-1L; | ||
| 65 | return (max / size) < n; | ||
| 66 | } | ||
| 67 | |||
| 68 | // Returns true if the size passed to pvalloc overflows when rounded to the next | ||
| 69 | // multiple of page_size. | ||
| 70 | INLINE bool CheckForPvallocOverflow(uptr size, uptr page_size) { | ||
| 71 | return RoundUpTo(size, page_size) < size; | ||
| 72 | } | ||
| 73 | |||
| 74 | } // namespace __sanitizer | ||
| 75 | |||
| 76 | #endif // SANITIZER_ALLOCATOR_CHECKS_H | ||
lib/tsan/sanitizer_common/sanitizer_allocator_combined.h created+201| ... | @@ -0,0 +1,201 @@ | ||
| 1 | //===-- sanitizer_allocator_combined.h --------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Part of the Sanitizer Allocator. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_ALLOCATOR_H | ||
| 13 | #error This file must be included inside sanitizer_allocator.h | ||
| 14 | #endif | ||
| 15 | |||
| 16 | // This class implements a complete memory allocator by using two | ||
| 17 | // internal allocators: | ||
| 18 | // PrimaryAllocator is efficient, but may not allocate some sizes (alignments). | ||
| 19 | // When allocating 2^x bytes it should return 2^x aligned chunk. | ||
| 20 | // PrimaryAllocator is used via a local AllocatorCache. | ||
| 21 | // SecondaryAllocator can allocate anything, but is not efficient. | ||
| 22 | template <class PrimaryAllocator, | ||
| 23 | class LargeMmapAllocatorPtrArray = DefaultLargeMmapAllocatorPtrArray> | ||
| 24 | class CombinedAllocator { | ||
| 25 | public: | ||
| 26 | using AllocatorCache = typename PrimaryAllocator::AllocatorCache; | ||
| 27 | using SecondaryAllocator = | ||
| 28 | LargeMmapAllocator<typename PrimaryAllocator::MapUnmapCallback, | ||
| 29 | LargeMmapAllocatorPtrArray, | ||
| 30 | typename PrimaryAllocator::AddressSpaceView>; | ||
| 31 | |||
| 32 | void InitLinkerInitialized(s32 release_to_os_interval_ms) { | ||
| 33 | stats_.InitLinkerInitialized(); | ||
| 34 | primary_.Init(release_to_os_interval_ms); | ||
| 35 | secondary_.InitLinkerInitialized(); | ||
| 36 | } | ||
| 37 | |||
| 38 | void Init(s32 release_to_os_interval_ms) { | ||
| 39 | stats_.Init(); | ||
| 40 | primary_.Init(release_to_os_interval_ms); | ||
| 41 | secondary_.Init(); | ||
| 42 | } | ||
| 43 | |||
| 44 | void *Allocate(AllocatorCache *cache, uptr size, uptr alignment) { | ||
| 45 | // Returning 0 on malloc(0) may break a lot of code. | ||
| 46 | if (size == 0) | ||
| 47 | size = 1; | ||
| 48 | if (size + alignment < size) { | ||
| 49 | Report("WARNING: %s: CombinedAllocator allocation overflow: " | ||
| 50 | "0x%zx bytes with 0x%zx alignment requested\n", | ||
| 51 | SanitizerToolName, size, alignment); | ||
| 52 | return nullptr; | ||
| 53 | } | ||
| 54 | uptr original_size = size; | ||
| 55 | // If alignment requirements are to be fulfilled by the frontend allocator | ||
| 56 | // rather than by the primary or secondary, passing an alignment lower than | ||
| 57 | // or equal to 8 will prevent any further rounding up, as well as the later | ||
| 58 | // alignment check. | ||
| 59 | if (alignment > 8) | ||
| 60 | size = RoundUpTo(size, alignment); | ||
| 61 | // The primary allocator should return a 2^x aligned allocation when | ||
| 62 | // requested 2^x bytes, hence using the rounded up 'size' when being | ||
| 63 | // serviced by the primary (this is no longer true when the primary is | ||
| 64 | // using a non-fixed base address). The secondary takes care of the | ||
| 65 | // alignment without such requirement, and allocating 'size' would use | ||
| 66 | // extraneous memory, so we employ 'original_size'. | ||
| 67 | void *res; | ||
| 68 | if (primary_.CanAllocate(size, alignment)) | ||
| 69 | res = cache->Allocate(&primary_, primary_.ClassID(size)); | ||
| 70 | else | ||
| 71 | res = secondary_.Allocate(&stats_, original_size, alignment); | ||
| 72 | if (alignment > 8) | ||
| 73 | CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0); | ||
| 74 | return res; | ||
| 75 | } | ||
| 76 | |||
| 77 | s32 ReleaseToOSIntervalMs() const { | ||
| 78 | return primary_.ReleaseToOSIntervalMs(); | ||
| 79 | } | ||
| 80 | |||
| 81 | void SetReleaseToOSIntervalMs(s32 release_to_os_interval_ms) { | ||
| 82 | primary_.SetReleaseToOSIntervalMs(release_to_os_interval_ms); | ||
| 83 | } | ||
| 84 | |||
| 85 | void ForceReleaseToOS() { | ||
| 86 | primary_.ForceReleaseToOS(); | ||
| 87 | } | ||
| 88 | |||
| 89 | void Deallocate(AllocatorCache *cache, void *p) { | ||
| 90 | if (!p) return; | ||
| 91 | if (primary_.PointerIsMine(p)) | ||
| 92 | cache->Deallocate(&primary_, primary_.GetSizeClass(p), p); | ||
| 93 | else | ||
| 94 | secondary_.Deallocate(&stats_, p); | ||
| 95 | } | ||
| 96 | |||
| 97 | void *Reallocate(AllocatorCache *cache, void *p, uptr new_size, | ||
| 98 | uptr alignment) { | ||
| 99 | if (!p) | ||
| 100 | return Allocate(cache, new_size, alignment); | ||
| 101 | if (!new_size) { | ||
| 102 | Deallocate(cache, p); | ||
| 103 | return nullptr; | ||
| 104 | } | ||
| 105 | CHECK(PointerIsMine(p)); | ||
| 106 | uptr old_size = GetActuallyAllocatedSize(p); | ||
| 107 | uptr memcpy_size = Min(new_size, old_size); | ||
| 108 | void *new_p = Allocate(cache, new_size, alignment); | ||
| 109 | if (new_p) | ||
| 110 | internal_memcpy(new_p, p, memcpy_size); | ||
| 111 | Deallocate(cache, p); | ||
| 112 | return new_p; | ||
| 113 | } | ||
| 114 | |||
| 115 | bool PointerIsMine(void *p) { | ||
| 116 | if (primary_.PointerIsMine(p)) | ||
| 117 | return true; | ||
| 118 | return secondary_.PointerIsMine(p); | ||
| 119 | } | ||
| 120 | |||
| 121 | bool FromPrimary(void *p) { | ||
| 122 | return primary_.PointerIsMine(p); | ||
| 123 | } | ||
| 124 | |||
| 125 | void *GetMetaData(const void *p) { | ||
| 126 | if (primary_.PointerIsMine(p)) | ||
| 127 | return primary_.GetMetaData(p); | ||
| 128 | return secondary_.GetMetaData(p); | ||
| 129 | } | ||
| 130 | |||
| 131 | void *GetBlockBegin(const void *p) { | ||
| 132 | if (primary_.PointerIsMine(p)) | ||
| 133 | return primary_.GetBlockBegin(p); | ||
| 134 | return secondary_.GetBlockBegin(p); | ||
| 135 | } | ||
| 136 | |||
| 137 | // This function does the same as GetBlockBegin, but is much faster. | ||
| 138 | // Must be called with the allocator locked. | ||
| 139 | void *GetBlockBeginFastLocked(void *p) { | ||
| 140 | if (primary_.PointerIsMine(p)) | ||
| 141 | return primary_.GetBlockBegin(p); | ||
| 142 | return secondary_.GetBlockBeginFastLocked(p); | ||
| 143 | } | ||
| 144 | |||
| 145 | uptr GetActuallyAllocatedSize(void *p) { | ||
| 146 | if (primary_.PointerIsMine(p)) | ||
| 147 | return primary_.GetActuallyAllocatedSize(p); | ||
| 148 | return secondary_.GetActuallyAllocatedSize(p); | ||
| 149 | } | ||
| 150 | |||
| 151 | uptr TotalMemoryUsed() { | ||
| 152 | return primary_.TotalMemoryUsed() + secondary_.TotalMemoryUsed(); | ||
| 153 | } | ||
| 154 | |||
| 155 | void TestOnlyUnmap() { primary_.TestOnlyUnmap(); } | ||
| 156 | |||
| 157 | void InitCache(AllocatorCache *cache) { | ||
| 158 | cache->Init(&stats_); | ||
| 159 | } | ||
| 160 | |||
| 161 | void DestroyCache(AllocatorCache *cache) { | ||
| 162 | cache->Destroy(&primary_, &stats_); | ||
| 163 | } | ||
| 164 | |||
| 165 | void SwallowCache(AllocatorCache *cache) { | ||
| 166 | cache->Drain(&primary_); | ||
| 167 | } | ||
| 168 | |||
| 169 | void GetStats(AllocatorStatCounters s) const { | ||
| 170 | stats_.Get(s); | ||
| 171 | } | ||
| 172 | |||
| 173 | void PrintStats() { | ||
| 174 | primary_.PrintStats(); | ||
| 175 | secondary_.PrintStats(); | ||
| 176 | } | ||
| 177 | |||
| 178 | // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone | ||
| 179 | // introspection API. | ||
| 180 | void ForceLock() { | ||
| 181 | primary_.ForceLock(); | ||
| 182 | secondary_.ForceLock(); | ||
| 183 | } | ||
| 184 | |||
| 185 | void ForceUnlock() { | ||
| 186 | secondary_.ForceUnlock(); | ||
| 187 | primary_.ForceUnlock(); | ||
| 188 | } | ||
| 189 | |||
| 190 | // Iterate over all existing chunks. | ||
| 191 | // The allocator must be locked when calling this function. | ||
| 192 | void ForEachChunk(ForEachChunkCallback callback, void *arg) { | ||
| 193 | primary_.ForEachChunk(callback, arg); | ||
| 194 | secondary_.ForEachChunk(callback, arg); | ||
| 195 | } | ||
| 196 | |||
| 197 | private: | ||
| 198 | PrimaryAllocator primary_; | ||
| 199 | SecondaryAllocator secondary_; | ||
| 200 | AllocatorGlobalStats stats_; | ||
| 201 | }; | ||
lib/tsan/sanitizer_common/sanitizer_allocator_interface.h created+47| ... | @@ -0,0 +1,47 @@ | ||
| 1 | //===-- sanitizer_allocator_interface.h ------------------------- C++ -----===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Re-declaration of functions from public sanitizer allocator interface. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef SANITIZER_ALLOCATOR_INTERFACE_H | ||
| 14 | #define SANITIZER_ALLOCATOR_INTERFACE_H | ||
| 15 | |||
| 16 | #include "sanitizer_internal_defs.h" | ||
| 17 | |||
| 18 | using __sanitizer::uptr; | ||
| 19 | |||
| 20 | extern "C" { | ||
| 21 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 22 | uptr __sanitizer_get_estimated_allocated_size(uptr size); | ||
| 23 | SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_get_ownership(const void *p); | ||
| 24 | SANITIZER_INTERFACE_ATTRIBUTE uptr | ||
| 25 | __sanitizer_get_allocated_size(const void *p); | ||
| 26 | SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_current_allocated_bytes(); | ||
| 27 | SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_heap_size(); | ||
| 28 | SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_free_bytes(); | ||
| 29 | SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_unmapped_bytes(); | ||
| 30 | |||
| 31 | SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_install_malloc_and_free_hooks( | ||
| 32 | void (*malloc_hook)(const void *, uptr), | ||
| 33 | void (*free_hook)(const void *)); | ||
| 34 | |||
| 35 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 36 | void __sanitizer_malloc_hook(void *ptr, uptr size); | ||
| 37 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 38 | void __sanitizer_free_hook(void *ptr); | ||
| 39 | |||
| 40 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void | ||
| 41 | __sanitizer_purge_allocator(); | ||
| 42 | |||
| 43 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void | ||
| 44 | __sanitizer_print_memory_profile(uptr top_percent, uptr max_number_of_contexts); | ||
| 45 | } // extern "C" | ||
| 46 | |||
| 47 | #endif // SANITIZER_ALLOCATOR_INTERFACE_H | ||
lib/tsan/sanitizer_common/sanitizer_allocator_internal.h created+55| ... | @@ -0,0 +1,55 @@ | ||
| 1 | //===-- sanitizer_allocator_internal.h --------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This allocator is used inside run-times. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef SANITIZER_ALLOCATOR_INTERNAL_H | ||
| 14 | #define SANITIZER_ALLOCATOR_INTERNAL_H | ||
| 15 | |||
| 16 | #include "sanitizer_allocator.h" | ||
| 17 | #include "sanitizer_internal_defs.h" | ||
| 18 | |||
| 19 | namespace __sanitizer { | ||
| 20 | |||
| 21 | // FIXME: Check if we may use even more compact size class map for internal | ||
| 22 | // purposes. | ||
| 23 | typedef CompactSizeClassMap InternalSizeClassMap; | ||
| 24 | |||
| 25 | struct AP32 { | ||
| 26 | static const uptr kSpaceBeg = 0; | ||
| 27 | static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; | ||
| 28 | static const uptr kMetadataSize = 0; | ||
| 29 | typedef InternalSizeClassMap SizeClassMap; | ||
| 30 | static const uptr kRegionSizeLog = 20; | ||
| 31 | using AddressSpaceView = LocalAddressSpaceView; | ||
| 32 | typedef NoOpMapUnmapCallback MapUnmapCallback; | ||
| 33 | static const uptr kFlags = 0; | ||
| 34 | }; | ||
| 35 | typedef SizeClassAllocator32<AP32> PrimaryInternalAllocator; | ||
| 36 | |||
| 37 | typedef CombinedAllocator<PrimaryInternalAllocator, | ||
| 38 | LargeMmapAllocatorPtrArrayStatic> | ||
| 39 | InternalAllocator; | ||
| 40 | typedef InternalAllocator::AllocatorCache InternalAllocatorCache; | ||
| 41 | |||
| 42 | void *InternalAlloc(uptr size, InternalAllocatorCache *cache = nullptr, | ||
| 43 | uptr alignment = 0); | ||
| 44 | void *InternalRealloc(void *p, uptr size, | ||
| 45 | InternalAllocatorCache *cache = nullptr); | ||
| 46 | void *InternalReallocArray(void *p, uptr count, uptr size, | ||
| 47 | InternalAllocatorCache *cache = nullptr); | ||
| 48 | void *InternalCalloc(uptr count, uptr size, | ||
| 49 | InternalAllocatorCache *cache = nullptr); | ||
| 50 | void InternalFree(void *p, InternalAllocatorCache *cache = nullptr); | ||
| 51 | InternalAllocator *internal_allocator(); | ||
| 52 | |||
| 53 | } // namespace __sanitizer | ||
| 54 | |||
| 55 | #endif // SANITIZER_ALLOCATOR_INTERNAL_H | ||
lib/tsan/sanitizer_common/sanitizer_allocator_local_cache.h created+264| ... | @@ -0,0 +1,264 @@ | ||
| 1 | //===-- sanitizer_allocator_local_cache.h -----------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Part of the Sanitizer Allocator. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_ALLOCATOR_H | ||
| 13 | #error This file must be included inside sanitizer_allocator.h | ||
| 14 | #endif | ||
| 15 | |||
| 16 | // Cache used by SizeClassAllocator64. | ||
| 17 | template <class SizeClassAllocator> | ||
| 18 | struct SizeClassAllocator64LocalCache { | ||
| 19 | typedef SizeClassAllocator Allocator; | ||
| 20 | |||
| 21 | void Init(AllocatorGlobalStats *s) { | ||
| 22 | stats_.Init(); | ||
| 23 | if (s) | ||
| 24 | s->Register(&stats_); | ||
| 25 | } | ||
| 26 | |||
| 27 | void Destroy(SizeClassAllocator *allocator, AllocatorGlobalStats *s) { | ||
| 28 | Drain(allocator); | ||
| 29 | if (s) | ||
| 30 | s->Unregister(&stats_); | ||
| 31 | } | ||
| 32 | |||
| 33 | void *Allocate(SizeClassAllocator *allocator, uptr class_id) { | ||
| 34 | CHECK_NE(class_id, 0UL); | ||
| 35 | CHECK_LT(class_id, kNumClasses); | ||
| 36 | PerClass *c = &per_class_[class_id]; | ||
| 37 | if (UNLIKELY(c->count == 0)) { | ||
| 38 | if (UNLIKELY(!Refill(c, allocator, class_id))) | ||
| 39 | return nullptr; | ||
| 40 | DCHECK_GT(c->count, 0); | ||
| 41 | } | ||
| 42 | CompactPtrT chunk = c->chunks[--c->count]; | ||
| 43 | stats_.Add(AllocatorStatAllocated, c->class_size); | ||
| 44 | return reinterpret_cast<void *>(allocator->CompactPtrToPointer( | ||
| 45 | allocator->GetRegionBeginBySizeClass(class_id), chunk)); | ||
| 46 | } | ||
| 47 | |||
| 48 | void Deallocate(SizeClassAllocator *allocator, uptr class_id, void *p) { | ||
| 49 | CHECK_NE(class_id, 0UL); | ||
| 50 | CHECK_LT(class_id, kNumClasses); | ||
| 51 | // If the first allocator call on a new thread is a deallocation, then | ||
| 52 | // max_count will be zero, leading to check failure. | ||
| 53 | PerClass *c = &per_class_[class_id]; | ||
| 54 | InitCache(c); | ||
| 55 | if (UNLIKELY(c->count == c->max_count)) | ||
| 56 | Drain(c, allocator, class_id, c->max_count / 2); | ||
| 57 | CompactPtrT chunk = allocator->PointerToCompactPtr( | ||
| 58 | allocator->GetRegionBeginBySizeClass(class_id), | ||
| 59 | reinterpret_cast<uptr>(p)); | ||
| 60 | c->chunks[c->count++] = chunk; | ||
| 61 | stats_.Sub(AllocatorStatAllocated, c->class_size); | ||
| 62 | } | ||
| 63 | |||
| 64 | void Drain(SizeClassAllocator *allocator) { | ||
| 65 | for (uptr i = 1; i < kNumClasses; i++) { | ||
| 66 | PerClass *c = &per_class_[i]; | ||
| 67 | while (c->count > 0) | ||
| 68 | Drain(c, allocator, i, c->count); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | private: | ||
| 73 | typedef typename Allocator::SizeClassMapT SizeClassMap; | ||
| 74 | static const uptr kNumClasses = SizeClassMap::kNumClasses; | ||
| 75 | typedef typename Allocator::CompactPtrT CompactPtrT; | ||
| 76 | |||
| 77 | struct PerClass { | ||
| 78 | u32 count; | ||
| 79 | u32 max_count; | ||
| 80 | uptr class_size; | ||
| 81 | CompactPtrT chunks[2 * SizeClassMap::kMaxNumCachedHint]; | ||
| 82 | }; | ||
| 83 | PerClass per_class_[kNumClasses]; | ||
| 84 | AllocatorStats stats_; | ||
| 85 | |||
| 86 | void InitCache(PerClass *c) { | ||
| 87 | if (LIKELY(c->max_count)) | ||
| 88 | return; | ||
| 89 | for (uptr i = 1; i < kNumClasses; i++) { | ||
| 90 | PerClass *c = &per_class_[i]; | ||
| 91 | const uptr size = Allocator::ClassIdToSize(i); | ||
| 92 | c->max_count = 2 * SizeClassMap::MaxCachedHint(size); | ||
| 93 | c->class_size = size; | ||
| 94 | } | ||
| 95 | DCHECK_NE(c->max_count, 0UL); | ||
| 96 | } | ||
| 97 | |||
| 98 | NOINLINE bool Refill(PerClass *c, SizeClassAllocator *allocator, | ||
| 99 | uptr class_id) { | ||
| 100 | InitCache(c); | ||
| 101 | const uptr num_requested_chunks = c->max_count / 2; | ||
| 102 | if (UNLIKELY(!allocator->GetFromAllocator(&stats_, class_id, c->chunks, | ||
| 103 | num_requested_chunks))) | ||
| 104 | return false; | ||
| 105 | c->count = num_requested_chunks; | ||
| 106 | return true; | ||
| 107 | } | ||
| 108 | |||
| 109 | NOINLINE void Drain(PerClass *c, SizeClassAllocator *allocator, uptr class_id, | ||
| 110 | uptr count) { | ||
| 111 | CHECK_GE(c->count, count); | ||
| 112 | const uptr first_idx_to_drain = c->count - count; | ||
| 113 | c->count -= count; | ||
| 114 | allocator->ReturnToAllocator(&stats_, class_id, | ||
| 115 | &c->chunks[first_idx_to_drain], count); | ||
| 116 | } | ||
| 117 | }; | ||
| 118 | |||
| 119 | // Cache used by SizeClassAllocator32. | ||
| 120 | template <class SizeClassAllocator> | ||
| 121 | struct SizeClassAllocator32LocalCache { | ||
| 122 | typedef SizeClassAllocator Allocator; | ||
| 123 | typedef typename Allocator::TransferBatch TransferBatch; | ||
| 124 | |||
| 125 | void Init(AllocatorGlobalStats *s) { | ||
| 126 | stats_.Init(); | ||
| 127 | if (s) | ||
| 128 | s->Register(&stats_); | ||
| 129 | } | ||
| 130 | |||
| 131 | // Returns a TransferBatch suitable for class_id. | ||
| 132 | TransferBatch *CreateBatch(uptr class_id, SizeClassAllocator *allocator, | ||
| 133 | TransferBatch *b) { | ||
| 134 | if (uptr batch_class_id = per_class_[class_id].batch_class_id) | ||
| 135 | return (TransferBatch*)Allocate(allocator, batch_class_id); | ||
| 136 | return b; | ||
| 137 | } | ||
| 138 | |||
| 139 | // Destroys TransferBatch b. | ||
| 140 | void DestroyBatch(uptr class_id, SizeClassAllocator *allocator, | ||
| 141 | TransferBatch *b) { | ||
| 142 | if (uptr batch_class_id = per_class_[class_id].batch_class_id) | ||
| 143 | Deallocate(allocator, batch_class_id, b); | ||
| 144 | } | ||
| 145 | |||
| 146 | void Destroy(SizeClassAllocator *allocator, AllocatorGlobalStats *s) { | ||
| 147 | Drain(allocator); | ||
| 148 | if (s) | ||
| 149 | s->Unregister(&stats_); | ||
| 150 | } | ||
| 151 | |||
| 152 | void *Allocate(SizeClassAllocator *allocator, uptr class_id) { | ||
| 153 | CHECK_NE(class_id, 0UL); | ||
| 154 | CHECK_LT(class_id, kNumClasses); | ||
| 155 | PerClass *c = &per_class_[class_id]; | ||
| 156 | if (UNLIKELY(c->count == 0)) { | ||
| 157 | if (UNLIKELY(!Refill(c, allocator, class_id))) | ||
| 158 | return nullptr; | ||
| 159 | DCHECK_GT(c->count, 0); | ||
| 160 | } | ||
| 161 | void *res = c->batch[--c->count]; | ||
| 162 | PREFETCH(c->batch[c->count - 1]); | ||
| 163 | stats_.Add(AllocatorStatAllocated, c->class_size); | ||
| 164 | return res; | ||
| 165 | } | ||
| 166 | |||
| 167 | void Deallocate(SizeClassAllocator *allocator, uptr class_id, void *p) { | ||
| 168 | CHECK_NE(class_id, 0UL); | ||
| 169 | CHECK_LT(class_id, kNumClasses); | ||
| 170 | // If the first allocator call on a new thread is a deallocation, then | ||
| 171 | // max_count will be zero, leading to check failure. | ||
| 172 | PerClass *c = &per_class_[class_id]; | ||
| 173 | InitCache(c); | ||
| 174 | if (UNLIKELY(c->count == c->max_count)) | ||
| 175 | Drain(c, allocator, class_id); | ||
| 176 | c->batch[c->count++] = p; | ||
| 177 | stats_.Sub(AllocatorStatAllocated, c->class_size); | ||
| 178 | } | ||
| 179 | |||
| 180 | void Drain(SizeClassAllocator *allocator) { | ||
| 181 | for (uptr i = 1; i < kNumClasses; i++) { | ||
| 182 | PerClass *c = &per_class_[i]; | ||
| 183 | while (c->count > 0) | ||
| 184 | Drain(c, allocator, i); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | private: | ||
| 189 | typedef typename Allocator::SizeClassMapT SizeClassMap; | ||
| 190 | static const uptr kBatchClassID = SizeClassMap::kBatchClassID; | ||
| 191 | static const uptr kNumClasses = SizeClassMap::kNumClasses; | ||
| 192 | // If kUseSeparateSizeClassForBatch is true, all TransferBatch objects are | ||
| 193 | // allocated from kBatchClassID size class (except for those that are needed | ||
| 194 | // for kBatchClassID itself). The goal is to have TransferBatches in a totally | ||
| 195 | // different region of RAM to improve security. | ||
| 196 | static const bool kUseSeparateSizeClassForBatch = | ||
| 197 | Allocator::kUseSeparateSizeClassForBatch; | ||
| 198 | |||
| 199 | struct PerClass { | ||
| 200 | uptr count; | ||
| 201 | uptr max_count; | ||
| 202 | uptr class_size; | ||
| 203 | uptr batch_class_id; | ||
| 204 | void *batch[2 * TransferBatch::kMaxNumCached]; | ||
| 205 | }; | ||
| 206 | PerClass per_class_[kNumClasses]; | ||
| 207 | AllocatorStats stats_; | ||
| 208 | |||
| 209 | void InitCache(PerClass *c) { | ||
| 210 | if (LIKELY(c->max_count)) | ||
| 211 | return; | ||
| 212 | const uptr batch_class_id = SizeClassMap::ClassID(sizeof(TransferBatch)); | ||
| 213 | for (uptr i = 1; i < kNumClasses; i++) { | ||
| 214 | PerClass *c = &per_class_[i]; | ||
| 215 | const uptr size = Allocator::ClassIdToSize(i); | ||
| 216 | const uptr max_cached = TransferBatch::MaxCached(size); | ||
| 217 | c->max_count = 2 * max_cached; | ||
| 218 | c->class_size = size; | ||
| 219 | // Precompute the class id to use to store batches for the current class | ||
| 220 | // id. 0 means the class size is large enough to store a batch within one | ||
| 221 | // of the chunks. If using a separate size class, it will always be | ||
| 222 | // kBatchClassID, except for kBatchClassID itself. | ||
| 223 | if (kUseSeparateSizeClassForBatch) { | ||
| 224 | c->batch_class_id = (i == kBatchClassID) ? 0 : kBatchClassID; | ||
| 225 | } else { | ||
| 226 | c->batch_class_id = (size < | ||
| 227 | TransferBatch::AllocationSizeRequiredForNElements(max_cached)) ? | ||
| 228 | batch_class_id : 0; | ||
| 229 | } | ||
| 230 | } | ||
| 231 | DCHECK_NE(c->max_count, 0UL); | ||
| 232 | } | ||
| 233 | |||
| 234 | NOINLINE bool Refill(PerClass *c, SizeClassAllocator *allocator, | ||
| 235 | uptr class_id) { | ||
| 236 | InitCache(c); | ||
| 237 | TransferBatch *b = allocator->AllocateBatch(&stats_, this, class_id); | ||
| 238 | if (UNLIKELY(!b)) | ||
| 239 | return false; | ||
| 240 | CHECK_GT(b->Count(), 0); | ||
| 241 | b->CopyToArray(c->batch); | ||
| 242 | c->count = b->Count(); | ||
| 243 | DestroyBatch(class_id, allocator, b); | ||
| 244 | return true; | ||
| 245 | } | ||
| 246 | |||
| 247 | NOINLINE void Drain(PerClass *c, SizeClassAllocator *allocator, | ||
| 248 | uptr class_id) { | ||
| 249 | const uptr count = Min(c->max_count / 2, c->count); | ||
| 250 | const uptr first_idx_to_drain = c->count - count; | ||
| 251 | TransferBatch *b = CreateBatch( | ||
| 252 | class_id, allocator, (TransferBatch *)c->batch[first_idx_to_drain]); | ||
| 253 | // Failure to allocate a batch while releasing memory is non recoverable. | ||
| 254 | // TODO(alekseys): Figure out how to do it without allocating a new batch. | ||
| 255 | if (UNLIKELY(!b)) { | ||
| 256 | Report("FATAL: Internal error: %s's allocator failed to allocate a " | ||
| 257 | "transfer batch.\n", SanitizerToolName); | ||
| 258 | Die(); | ||
| 259 | } | ||
| 260 | b->SetFromArray(&c->batch[first_idx_to_drain], count); | ||
| 261 | c->count -= count; | ||
| 262 | allocator->DeallocateBatch(&stats_, class_id, b); | ||
| 263 | } | ||
| 264 | }; | ||
lib/tsan/sanitizer_common/sanitizer_allocator_primary32.h created+380| ... | @@ -0,0 +1,380 @@ | ||
| 1 | //===-- sanitizer_allocator_primary32.h -------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Part of the Sanitizer Allocator. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_ALLOCATOR_H | ||
| 13 | #error This file must be included inside sanitizer_allocator.h | ||
| 14 | #endif | ||
| 15 | |||
| 16 | template<class SizeClassAllocator> struct SizeClassAllocator32LocalCache; | ||
| 17 | |||
| 18 | // SizeClassAllocator32 -- allocator for 32-bit address space. | ||
| 19 | // This allocator can theoretically be used on 64-bit arch, but there it is less | ||
| 20 | // efficient than SizeClassAllocator64. | ||
| 21 | // | ||
| 22 | // [kSpaceBeg, kSpaceBeg + kSpaceSize) is the range of addresses which can | ||
| 23 | // be returned by MmapOrDie(). | ||
| 24 | // | ||
| 25 | // Region: | ||
| 26 | // a result of a single call to MmapAlignedOrDieOnFatalError(kRegionSize, | ||
| 27 | // kRegionSize). | ||
| 28 | // Since the regions are aligned by kRegionSize, there are exactly | ||
| 29 | // kNumPossibleRegions possible regions in the address space and so we keep | ||
| 30 | // a ByteMap possible_regions to store the size classes of each Region. | ||
| 31 | // 0 size class means the region is not used by the allocator. | ||
| 32 | // | ||
| 33 | // One Region is used to allocate chunks of a single size class. | ||
| 34 | // A Region looks like this: | ||
| 35 | // UserChunk1 .. UserChunkN <gap> MetaChunkN .. MetaChunk1 | ||
| 36 | // | ||
| 37 | // In order to avoid false sharing the objects of this class should be | ||
| 38 | // chache-line aligned. | ||
| 39 | |||
| 40 | struct SizeClassAllocator32FlagMasks { // Bit masks. | ||
| 41 | enum { | ||
| 42 | kRandomShuffleChunks = 1, | ||
| 43 | kUseSeparateSizeClassForBatch = 2, | ||
| 44 | }; | ||
| 45 | }; | ||
| 46 | |||
| 47 | template <class Params> | ||
| 48 | class SizeClassAllocator32 { | ||
| 49 | private: | ||
| 50 | static const u64 kTwoLevelByteMapSize1 = | ||
| 51 | (Params::kSpaceSize >> Params::kRegionSizeLog) >> 12; | ||
| 52 | static const u64 kMinFirstMapSizeTwoLevelByteMap = 4; | ||
| 53 | |||
| 54 | public: | ||
| 55 | using AddressSpaceView = typename Params::AddressSpaceView; | ||
| 56 | static const uptr kSpaceBeg = Params::kSpaceBeg; | ||
| 57 | static const u64 kSpaceSize = Params::kSpaceSize; | ||
| 58 | static const uptr kMetadataSize = Params::kMetadataSize; | ||
| 59 | typedef typename Params::SizeClassMap SizeClassMap; | ||
| 60 | static const uptr kRegionSizeLog = Params::kRegionSizeLog; | ||
| 61 | typedef typename Params::MapUnmapCallback MapUnmapCallback; | ||
| 62 | using ByteMap = typename conditional< | ||
| 63 | (kTwoLevelByteMapSize1 < kMinFirstMapSizeTwoLevelByteMap), | ||
| 64 | FlatByteMap<(Params::kSpaceSize >> Params::kRegionSizeLog), | ||
| 65 | AddressSpaceView>, | ||
| 66 | TwoLevelByteMap<kTwoLevelByteMapSize1, 1 << 12, AddressSpaceView>>::type; | ||
| 67 | |||
| 68 | COMPILER_CHECK(!SANITIZER_SIGN_EXTENDED_ADDRESSES || | ||
| 69 | (kSpaceSize & (kSpaceSize - 1)) == 0); | ||
| 70 | |||
| 71 | static const bool kRandomShuffleChunks = Params::kFlags & | ||
| 72 | SizeClassAllocator32FlagMasks::kRandomShuffleChunks; | ||
| 73 | static const bool kUseSeparateSizeClassForBatch = Params::kFlags & | ||
| 74 | SizeClassAllocator32FlagMasks::kUseSeparateSizeClassForBatch; | ||
| 75 | |||
| 76 | struct TransferBatch { | ||
| 77 | static const uptr kMaxNumCached = SizeClassMap::kMaxNumCachedHint - 2; | ||
| 78 | void SetFromArray(void *batch[], uptr count) { | ||
| 79 | DCHECK_LE(count, kMaxNumCached); | ||
| 80 | count_ = count; | ||
| 81 | for (uptr i = 0; i < count; i++) | ||
| 82 | batch_[i] = batch[i]; | ||
| 83 | } | ||
| 84 | uptr Count() const { return count_; } | ||
| 85 | void Clear() { count_ = 0; } | ||
| 86 | void Add(void *ptr) { | ||
| 87 | batch_[count_++] = ptr; | ||
| 88 | DCHECK_LE(count_, kMaxNumCached); | ||
| 89 | } | ||
| 90 | void CopyToArray(void *to_batch[]) const { | ||
| 91 | for (uptr i = 0, n = Count(); i < n; i++) | ||
| 92 | to_batch[i] = batch_[i]; | ||
| 93 | } | ||
| 94 | |||
| 95 | // How much memory do we need for a batch containing n elements. | ||
| 96 | static uptr AllocationSizeRequiredForNElements(uptr n) { | ||
| 97 | return sizeof(uptr) * 2 + sizeof(void *) * n; | ||
| 98 | } | ||
| 99 | static uptr MaxCached(uptr size) { | ||
| 100 | return Min(kMaxNumCached, SizeClassMap::MaxCachedHint(size)); | ||
| 101 | } | ||
| 102 | |||
| 103 | TransferBatch *next; | ||
| 104 | |||
| 105 | private: | ||
| 106 | uptr count_; | ||
| 107 | void *batch_[kMaxNumCached]; | ||
| 108 | }; | ||
| 109 | |||
| 110 | static const uptr kBatchSize = sizeof(TransferBatch); | ||
| 111 | COMPILER_CHECK((kBatchSize & (kBatchSize - 1)) == 0); | ||
| 112 | COMPILER_CHECK(kBatchSize == SizeClassMap::kMaxNumCachedHint * sizeof(uptr)); | ||
| 113 | |||
| 114 | static uptr ClassIdToSize(uptr class_id) { | ||
| 115 | return (class_id == SizeClassMap::kBatchClassID) ? | ||
| 116 | kBatchSize : SizeClassMap::Size(class_id); | ||
| 117 | } | ||
| 118 | |||
| 119 | typedef SizeClassAllocator32<Params> ThisT; | ||
| 120 | typedef SizeClassAllocator32LocalCache<ThisT> AllocatorCache; | ||
| 121 | |||
| 122 | void Init(s32 release_to_os_interval_ms) { | ||
| 123 | possible_regions.Init(); | ||
| 124 | internal_memset(size_class_info_array, 0, sizeof(size_class_info_array)); | ||
| 125 | } | ||
| 126 | |||
| 127 | s32 ReleaseToOSIntervalMs() const { | ||
| 128 | return kReleaseToOSIntervalNever; | ||
| 129 | } | ||
| 130 | |||
| 131 | void SetReleaseToOSIntervalMs(s32 release_to_os_interval_ms) { | ||
| 132 | // This is empty here. Currently only implemented in 64-bit allocator. | ||
| 133 | } | ||
| 134 | |||
| 135 | void ForceReleaseToOS() { | ||
| 136 | // Currently implemented in 64-bit allocator only. | ||
| 137 | } | ||
| 138 | |||
| 139 | void *MapWithCallback(uptr size) { | ||
| 140 | void *res = MmapOrDie(size, PrimaryAllocatorName); | ||
| 141 | MapUnmapCallback().OnMap((uptr)res, size); | ||
| 142 | return res; | ||
| 143 | } | ||
| 144 | |||
| 145 | void UnmapWithCallback(uptr beg, uptr size) { | ||
| 146 | MapUnmapCallback().OnUnmap(beg, size); | ||
| 147 | UnmapOrDie(reinterpret_cast<void *>(beg), size); | ||
| 148 | } | ||
| 149 | |||
| 150 | static bool CanAllocate(uptr size, uptr alignment) { | ||
| 151 | return size <= SizeClassMap::kMaxSize && | ||
| 152 | alignment <= SizeClassMap::kMaxSize; | ||
| 153 | } | ||
| 154 | |||
| 155 | void *GetMetaData(const void *p) { | ||
| 156 | CHECK(PointerIsMine(p)); | ||
| 157 | uptr mem = reinterpret_cast<uptr>(p); | ||
| 158 | uptr beg = ComputeRegionBeg(mem); | ||
| 159 | uptr size = ClassIdToSize(GetSizeClass(p)); | ||
| 160 | u32 offset = mem - beg; | ||
| 161 | uptr n = offset / (u32)size; // 32-bit division | ||
| 162 | uptr meta = (beg + kRegionSize) - (n + 1) * kMetadataSize; | ||
| 163 | return reinterpret_cast<void*>(meta); | ||
| 164 | } | ||
| 165 | |||
| 166 | NOINLINE TransferBatch *AllocateBatch(AllocatorStats *stat, AllocatorCache *c, | ||
| 167 | uptr class_id) { | ||
| 168 | DCHECK_LT(class_id, kNumClasses); | ||
| 169 | SizeClassInfo *sci = GetSizeClassInfo(class_id); | ||
| 170 | SpinMutexLock l(&sci->mutex); | ||
| 171 | if (sci->free_list.empty()) { | ||
| 172 | if (UNLIKELY(!PopulateFreeList(stat, c, sci, class_id))) | ||
| 173 | return nullptr; | ||
| 174 | DCHECK(!sci->free_list.empty()); | ||
| 175 | } | ||
| 176 | TransferBatch *b = sci->free_list.front(); | ||
| 177 | sci->free_list.pop_front(); | ||
| 178 | return b; | ||
| 179 | } | ||
| 180 | |||
| 181 | NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id, | ||
| 182 | TransferBatch *b) { | ||
| 183 | DCHECK_LT(class_id, kNumClasses); | ||
| 184 | CHECK_GT(b->Count(), 0); | ||
| 185 | SizeClassInfo *sci = GetSizeClassInfo(class_id); | ||
| 186 | SpinMutexLock l(&sci->mutex); | ||
| 187 | sci->free_list.push_front(b); | ||
| 188 | } | ||
| 189 | |||
| 190 | bool PointerIsMine(const void *p) { | ||
| 191 | uptr mem = reinterpret_cast<uptr>(p); | ||
| 192 | if (SANITIZER_SIGN_EXTENDED_ADDRESSES) | ||
| 193 | mem &= (kSpaceSize - 1); | ||
| 194 | if (mem < kSpaceBeg || mem >= kSpaceBeg + kSpaceSize) | ||
| 195 | return false; | ||
| 196 | return GetSizeClass(p) != 0; | ||
| 197 | } | ||
| 198 | |||
| 199 | uptr GetSizeClass(const void *p) { | ||
| 200 | return possible_regions[ComputeRegionId(reinterpret_cast<uptr>(p))]; | ||
| 201 | } | ||
| 202 | |||
| 203 | void *GetBlockBegin(const void *p) { | ||
| 204 | CHECK(PointerIsMine(p)); | ||
| 205 | uptr mem = reinterpret_cast<uptr>(p); | ||
| 206 | uptr beg = ComputeRegionBeg(mem); | ||
| 207 | uptr size = ClassIdToSize(GetSizeClass(p)); | ||
| 208 | u32 offset = mem - beg; | ||
| 209 | u32 n = offset / (u32)size; // 32-bit division | ||
| 210 | uptr res = beg + (n * (u32)size); | ||
| 211 | return reinterpret_cast<void*>(res); | ||
| 212 | } | ||
| 213 | |||
| 214 | uptr GetActuallyAllocatedSize(void *p) { | ||
| 215 | CHECK(PointerIsMine(p)); | ||
| 216 | return ClassIdToSize(GetSizeClass(p)); | ||
| 217 | } | ||
| 218 | |||
| 219 | static uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); } | ||
| 220 | |||
| 221 | uptr TotalMemoryUsed() { | ||
| 222 | // No need to lock here. | ||
| 223 | uptr res = 0; | ||
| 224 | for (uptr i = 0; i < kNumPossibleRegions; i++) | ||
| 225 | if (possible_regions[i]) | ||
| 226 | res += kRegionSize; | ||
| 227 | return res; | ||
| 228 | } | ||
| 229 | |||
| 230 | void TestOnlyUnmap() { | ||
| 231 | for (uptr i = 0; i < kNumPossibleRegions; i++) | ||
| 232 | if (possible_regions[i]) | ||
| 233 | UnmapWithCallback((i * kRegionSize), kRegionSize); | ||
| 234 | } | ||
| 235 | |||
| 236 | // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone | ||
| 237 | // introspection API. | ||
| 238 | void ForceLock() { | ||
| 239 | for (uptr i = 0; i < kNumClasses; i++) { | ||
| 240 | GetSizeClassInfo(i)->mutex.Lock(); | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | void ForceUnlock() { | ||
| 245 | for (int i = kNumClasses - 1; i >= 0; i--) { | ||
| 246 | GetSizeClassInfo(i)->mutex.Unlock(); | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | // Iterate over all existing chunks. | ||
| 251 | // The allocator must be locked when calling this function. | ||
| 252 | void ForEachChunk(ForEachChunkCallback callback, void *arg) { | ||
| 253 | for (uptr region = 0; region < kNumPossibleRegions; region++) | ||
| 254 | if (possible_regions[region]) { | ||
| 255 | uptr chunk_size = ClassIdToSize(possible_regions[region]); | ||
| 256 | uptr max_chunks_in_region = kRegionSize / (chunk_size + kMetadataSize); | ||
| 257 | uptr region_beg = region * kRegionSize; | ||
| 258 | for (uptr chunk = region_beg; | ||
| 259 | chunk < region_beg + max_chunks_in_region * chunk_size; | ||
| 260 | chunk += chunk_size) { | ||
| 261 | // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk)); | ||
| 262 | callback(chunk, arg); | ||
| 263 | } | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | void PrintStats() {} | ||
| 268 | |||
| 269 | static uptr AdditionalSize() { return 0; } | ||
| 270 | |||
| 271 | typedef SizeClassMap SizeClassMapT; | ||
| 272 | static const uptr kNumClasses = SizeClassMap::kNumClasses; | ||
| 273 | |||
| 274 | private: | ||
| 275 | static const uptr kRegionSize = 1 << kRegionSizeLog; | ||
| 276 | static const uptr kNumPossibleRegions = kSpaceSize / kRegionSize; | ||
| 277 | |||
| 278 | struct ALIGNED(SANITIZER_CACHE_LINE_SIZE) SizeClassInfo { | ||
| 279 | StaticSpinMutex mutex; | ||
| 280 | IntrusiveList<TransferBatch> free_list; | ||
| 281 | u32 rand_state; | ||
| 282 | }; | ||
| 283 | COMPILER_CHECK(sizeof(SizeClassInfo) % kCacheLineSize == 0); | ||
| 284 | |||
| 285 | uptr ComputeRegionId(uptr mem) const { | ||
| 286 | if (SANITIZER_SIGN_EXTENDED_ADDRESSES) | ||
| 287 | mem &= (kSpaceSize - 1); | ||
| 288 | const uptr res = mem >> kRegionSizeLog; | ||
| 289 | CHECK_LT(res, kNumPossibleRegions); | ||
| 290 | return res; | ||
| 291 | } | ||
| 292 | |||
| 293 | uptr ComputeRegionBeg(uptr mem) { | ||
| 294 | return mem & ~(kRegionSize - 1); | ||
| 295 | } | ||
| 296 | |||
| 297 | uptr AllocateRegion(AllocatorStats *stat, uptr class_id) { | ||
| 298 | DCHECK_LT(class_id, kNumClasses); | ||
| 299 | const uptr res = reinterpret_cast<uptr>(MmapAlignedOrDieOnFatalError( | ||
| 300 | kRegionSize, kRegionSize, PrimaryAllocatorName)); | ||
| 301 | if (UNLIKELY(!res)) | ||
| 302 | return 0; | ||
| 303 | MapUnmapCallback().OnMap(res, kRegionSize); | ||
| 304 | stat->Add(AllocatorStatMapped, kRegionSize); | ||
| 305 | CHECK(IsAligned(res, kRegionSize)); | ||
| 306 | possible_regions.set(ComputeRegionId(res), static_cast<u8>(class_id)); | ||
| 307 | return res; | ||
| 308 | } | ||
| 309 | |||
| 310 | SizeClassInfo *GetSizeClassInfo(uptr class_id) { | ||
| 311 | DCHECK_LT(class_id, kNumClasses); | ||
| 312 | return &size_class_info_array[class_id]; | ||
| 313 | } | ||
| 314 | |||
| 315 | bool PopulateBatches(AllocatorCache *c, SizeClassInfo *sci, uptr class_id, | ||
| 316 | TransferBatch **current_batch, uptr max_count, | ||
| 317 | uptr *pointers_array, uptr count) { | ||
| 318 | // If using a separate class for batches, we do not need to shuffle it. | ||
| 319 | if (kRandomShuffleChunks && (!kUseSeparateSizeClassForBatch || | ||
| 320 | class_id != SizeClassMap::kBatchClassID)) | ||
| 321 | RandomShuffle(pointers_array, count, &sci->rand_state); | ||
| 322 | TransferBatch *b = *current_batch; | ||
| 323 | for (uptr i = 0; i < count; i++) { | ||
| 324 | if (!b) { | ||
| 325 | b = c->CreateBatch(class_id, this, (TransferBatch*)pointers_array[i]); | ||
| 326 | if (UNLIKELY(!b)) | ||
| 327 | return false; | ||
| 328 | b->Clear(); | ||
| 329 | } | ||
| 330 | b->Add((void*)pointers_array[i]); | ||
| 331 | if (b->Count() == max_count) { | ||
| 332 | sci->free_list.push_back(b); | ||
| 333 | b = nullptr; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | *current_batch = b; | ||
| 337 | return true; | ||
| 338 | } | ||
| 339 | |||
| 340 | bool PopulateFreeList(AllocatorStats *stat, AllocatorCache *c, | ||
| 341 | SizeClassInfo *sci, uptr class_id) { | ||
| 342 | const uptr region = AllocateRegion(stat, class_id); | ||
| 343 | if (UNLIKELY(!region)) | ||
| 344 | return false; | ||
| 345 | if (kRandomShuffleChunks) | ||
| 346 | if (UNLIKELY(sci->rand_state == 0)) | ||
| 347 | // The random state is initialized from ASLR (PIE) and time. | ||
| 348 | sci->rand_state = reinterpret_cast<uptr>(sci) ^ NanoTime(); | ||
| 349 | const uptr size = ClassIdToSize(class_id); | ||
| 350 | const uptr n_chunks = kRegionSize / (size + kMetadataSize); | ||
| 351 | const uptr max_count = TransferBatch::MaxCached(size); | ||
| 352 | DCHECK_GT(max_count, 0); | ||
| 353 | TransferBatch *b = nullptr; | ||
| 354 | constexpr uptr kShuffleArraySize = 48; | ||
| 355 | uptr shuffle_array[kShuffleArraySize]; | ||
| 356 | uptr count = 0; | ||
| 357 | for (uptr i = region; i < region + n_chunks * size; i += size) { | ||
| 358 | shuffle_array[count++] = i; | ||
| 359 | if (count == kShuffleArraySize) { | ||
| 360 | if (UNLIKELY(!PopulateBatches(c, sci, class_id, &b, max_count, | ||
| 361 | shuffle_array, count))) | ||
| 362 | return false; | ||
| 363 | count = 0; | ||
| 364 | } | ||
| 365 | } | ||
| 366 | if (count) { | ||
| 367 | if (UNLIKELY(!PopulateBatches(c, sci, class_id, &b, max_count, | ||
| 368 | shuffle_array, count))) | ||
| 369 | return false; | ||
| 370 | } | ||
| 371 | if (b) { | ||
| 372 | CHECK_GT(b->Count(), 0); | ||
| 373 | sci->free_list.push_back(b); | ||
| 374 | } | ||
| 375 | return true; | ||
| 376 | } | ||
| 377 | |||
| 378 | ByteMap possible_regions; | ||
| 379 | SizeClassInfo size_class_info_array[kNumClasses]; | ||
| 380 | }; | ||
lib/tsan/sanitizer_common/sanitizer_allocator_primary64.h created+863| ... | @@ -0,0 +1,863 @@ | ||
| 1 | //===-- sanitizer_allocator_primary64.h -------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Part of the Sanitizer Allocator. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_ALLOCATOR_H | ||
| 13 | #error This file must be included inside sanitizer_allocator.h | ||
| 14 | #endif | ||
| 15 | |||
| 16 | template<class SizeClassAllocator> struct SizeClassAllocator64LocalCache; | ||
| 17 | |||
| 18 | // SizeClassAllocator64 -- allocator for 64-bit address space. | ||
| 19 | // The template parameter Params is a class containing the actual parameters. | ||
| 20 | // | ||
| 21 | // Space: a portion of address space of kSpaceSize bytes starting at SpaceBeg. | ||
| 22 | // If kSpaceBeg is ~0 then SpaceBeg is chosen dynamically my mmap. | ||
| 23 | // Otherwise SpaceBeg=kSpaceBeg (fixed address). | ||
| 24 | // kSpaceSize is a power of two. | ||
| 25 | // At the beginning the entire space is mprotect-ed, then small parts of it | ||
| 26 | // are mapped on demand. | ||
| 27 | // | ||
| 28 | // Region: a part of Space dedicated to a single size class. | ||
| 29 | // There are kNumClasses Regions of equal size. | ||
| 30 | // | ||
| 31 | // UserChunk: a piece of memory returned to user. | ||
| 32 | // MetaChunk: kMetadataSize bytes of metadata associated with a UserChunk. | ||
| 33 | |||
| 34 | // FreeArray is an array free-d chunks (stored as 4-byte offsets) | ||
| 35 | // | ||
| 36 | // A Region looks like this: | ||
| 37 | // UserChunk1 ... UserChunkN <gap> MetaChunkN ... MetaChunk1 FreeArray | ||
| 38 | |||
| 39 | struct SizeClassAllocator64FlagMasks { // Bit masks. | ||
| 40 | enum { | ||
| 41 | kRandomShuffleChunks = 1, | ||
| 42 | }; | ||
| 43 | }; | ||
| 44 | |||
| 45 | template <class Params> | ||
| 46 | class SizeClassAllocator64 { | ||
| 47 | public: | ||
| 48 | using AddressSpaceView = typename Params::AddressSpaceView; | ||
| 49 | static const uptr kSpaceBeg = Params::kSpaceBeg; | ||
| 50 | static const uptr kSpaceSize = Params::kSpaceSize; | ||
| 51 | static const uptr kMetadataSize = Params::kMetadataSize; | ||
| 52 | typedef typename Params::SizeClassMap SizeClassMap; | ||
| 53 | typedef typename Params::MapUnmapCallback MapUnmapCallback; | ||
| 54 | |||
| 55 | static const bool kRandomShuffleChunks = | ||
| 56 | Params::kFlags & SizeClassAllocator64FlagMasks::kRandomShuffleChunks; | ||
| 57 | |||
| 58 | typedef SizeClassAllocator64<Params> ThisT; | ||
| 59 | typedef SizeClassAllocator64LocalCache<ThisT> AllocatorCache; | ||
| 60 | |||
| 61 | // When we know the size class (the region base) we can represent a pointer | ||
| 62 | // as a 4-byte integer (offset from the region start shifted right by 4). | ||
| 63 | typedef u32 CompactPtrT; | ||
| 64 | static const uptr kCompactPtrScale = 4; | ||
| 65 | CompactPtrT PointerToCompactPtr(uptr base, uptr ptr) const { | ||
| 66 | return static_cast<CompactPtrT>((ptr - base) >> kCompactPtrScale); | ||
| 67 | } | ||
| 68 | uptr CompactPtrToPointer(uptr base, CompactPtrT ptr32) const { | ||
| 69 | return base + (static_cast<uptr>(ptr32) << kCompactPtrScale); | ||
| 70 | } | ||
| 71 | |||
| 72 | void Init(s32 release_to_os_interval_ms) { | ||
| 73 | uptr TotalSpaceSize = kSpaceSize + AdditionalSize(); | ||
| 74 | if (kUsingConstantSpaceBeg) { | ||
| 75 | CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize)); | ||
| 76 | CHECK_EQ(kSpaceBeg, address_range.Init(TotalSpaceSize, | ||
| 77 | PrimaryAllocatorName, kSpaceBeg)); | ||
| 78 | } else { | ||
| 79 | // Combined allocator expects that an 2^N allocation is always aligned to | ||
| 80 | // 2^N. For this to work, the start of the space needs to be aligned as | ||
| 81 | // high as the largest size class (which also needs to be a power of 2). | ||
| 82 | NonConstSpaceBeg = address_range.InitAligned( | ||
| 83 | TotalSpaceSize, SizeClassMap::kMaxSize, PrimaryAllocatorName); | ||
| 84 | CHECK_NE(NonConstSpaceBeg, ~(uptr)0); | ||
| 85 | } | ||
| 86 | SetReleaseToOSIntervalMs(release_to_os_interval_ms); | ||
| 87 | MapWithCallbackOrDie(SpaceEnd(), AdditionalSize(), | ||
| 88 | "SizeClassAllocator: region info"); | ||
| 89 | // Check that the RegionInfo array is aligned on the CacheLine size. | ||
| 90 | DCHECK_EQ(SpaceEnd() % kCacheLineSize, 0); | ||
| 91 | } | ||
| 92 | |||
| 93 | s32 ReleaseToOSIntervalMs() const { | ||
| 94 | return atomic_load(&release_to_os_interval_ms_, memory_order_relaxed); | ||
| 95 | } | ||
| 96 | |||
| 97 | void SetReleaseToOSIntervalMs(s32 release_to_os_interval_ms) { | ||
| 98 | atomic_store(&release_to_os_interval_ms_, release_to_os_interval_ms, | ||
| 99 | memory_order_relaxed); | ||
| 100 | } | ||
| 101 | |||
| 102 | void ForceReleaseToOS() { | ||
| 103 | for (uptr class_id = 1; class_id < kNumClasses; class_id++) { | ||
| 104 | BlockingMutexLock l(&GetRegionInfo(class_id)->mutex); | ||
| 105 | MaybeReleaseToOS(class_id, true /*force*/); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | static bool CanAllocate(uptr size, uptr alignment) { | ||
| 110 | return size <= SizeClassMap::kMaxSize && | ||
| 111 | alignment <= SizeClassMap::kMaxSize; | ||
| 112 | } | ||
| 113 | |||
| 114 | NOINLINE void ReturnToAllocator(AllocatorStats *stat, uptr class_id, | ||
| 115 | const CompactPtrT *chunks, uptr n_chunks) { | ||
| 116 | RegionInfo *region = GetRegionInfo(class_id); | ||
| 117 | uptr region_beg = GetRegionBeginBySizeClass(class_id); | ||
| 118 | CompactPtrT *free_array = GetFreeArray(region_beg); | ||
| 119 | |||
| 120 | BlockingMutexLock l(&region->mutex); | ||
| 121 | uptr old_num_chunks = region->num_freed_chunks; | ||
| 122 | uptr new_num_freed_chunks = old_num_chunks + n_chunks; | ||
| 123 | // Failure to allocate free array space while releasing memory is non | ||
| 124 | // recoverable. | ||
| 125 | if (UNLIKELY(!EnsureFreeArraySpace(region, region_beg, | ||
| 126 | new_num_freed_chunks))) { | ||
| 127 | Report("FATAL: Internal error: %s's allocator exhausted the free list " | ||
| 128 | "space for size class %zd (%zd bytes).\n", SanitizerToolName, | ||
| 129 | class_id, ClassIdToSize(class_id)); | ||
| 130 | Die(); | ||
| 131 | } | ||
| 132 | for (uptr i = 0; i < n_chunks; i++) | ||
| 133 | free_array[old_num_chunks + i] = chunks[i]; | ||
| 134 | region->num_freed_chunks = new_num_freed_chunks; | ||
| 135 | region->stats.n_freed += n_chunks; | ||
| 136 | |||
| 137 | MaybeReleaseToOS(class_id, false /*force*/); | ||
| 138 | } | ||
| 139 | |||
| 140 | NOINLINE bool GetFromAllocator(AllocatorStats *stat, uptr class_id, | ||
| 141 | CompactPtrT *chunks, uptr n_chunks) { | ||
| 142 | RegionInfo *region = GetRegionInfo(class_id); | ||
| 143 | uptr region_beg = GetRegionBeginBySizeClass(class_id); | ||
| 144 | CompactPtrT *free_array = GetFreeArray(region_beg); | ||
| 145 | |||
| 146 | BlockingMutexLock l(&region->mutex); | ||
| 147 | if (UNLIKELY(region->num_freed_chunks < n_chunks)) { | ||
| 148 | if (UNLIKELY(!PopulateFreeArray(stat, class_id, region, | ||
| 149 | n_chunks - region->num_freed_chunks))) | ||
| 150 | return false; | ||
| 151 | CHECK_GE(region->num_freed_chunks, n_chunks); | ||
| 152 | } | ||
| 153 | region->num_freed_chunks -= n_chunks; | ||
| 154 | uptr base_idx = region->num_freed_chunks; | ||
| 155 | for (uptr i = 0; i < n_chunks; i++) | ||
| 156 | chunks[i] = free_array[base_idx + i]; | ||
| 157 | region->stats.n_allocated += n_chunks; | ||
| 158 | return true; | ||
| 159 | } | ||
| 160 | |||
| 161 | bool PointerIsMine(const void *p) const { | ||
| 162 | uptr P = reinterpret_cast<uptr>(p); | ||
| 163 | if (kUsingConstantSpaceBeg && (kSpaceBeg % kSpaceSize) == 0) | ||
| 164 | return P / kSpaceSize == kSpaceBeg / kSpaceSize; | ||
| 165 | return P >= SpaceBeg() && P < SpaceEnd(); | ||
| 166 | } | ||
| 167 | |||
| 168 | uptr GetRegionBegin(const void *p) { | ||
| 169 | if (kUsingConstantSpaceBeg) | ||
| 170 | return reinterpret_cast<uptr>(p) & ~(kRegionSize - 1); | ||
| 171 | uptr space_beg = SpaceBeg(); | ||
| 172 | return ((reinterpret_cast<uptr>(p) - space_beg) & ~(kRegionSize - 1)) + | ||
| 173 | space_beg; | ||
| 174 | } | ||
| 175 | |||
| 176 | uptr GetRegionBeginBySizeClass(uptr class_id) const { | ||
| 177 | return SpaceBeg() + kRegionSize * class_id; | ||
| 178 | } | ||
| 179 | |||
| 180 | uptr GetSizeClass(const void *p) { | ||
| 181 | if (kUsingConstantSpaceBeg && (kSpaceBeg % kSpaceSize) == 0) | ||
| 182 | return ((reinterpret_cast<uptr>(p)) / kRegionSize) % kNumClassesRounded; | ||
| 183 | return ((reinterpret_cast<uptr>(p) - SpaceBeg()) / kRegionSize) % | ||
| 184 | kNumClassesRounded; | ||
| 185 | } | ||
| 186 | |||
| 187 | void *GetBlockBegin(const void *p) { | ||
| 188 | uptr class_id = GetSizeClass(p); | ||
| 189 | uptr size = ClassIdToSize(class_id); | ||
| 190 | if (!size) return nullptr; | ||
| 191 | uptr chunk_idx = GetChunkIdx((uptr)p, size); | ||
| 192 | uptr reg_beg = GetRegionBegin(p); | ||
| 193 | uptr beg = chunk_idx * size; | ||
| 194 | uptr next_beg = beg + size; | ||
| 195 | if (class_id >= kNumClasses) return nullptr; | ||
| 196 | const RegionInfo *region = AddressSpaceView::Load(GetRegionInfo(class_id)); | ||
| 197 | if (region->mapped_user >= next_beg) | ||
| 198 | return reinterpret_cast<void*>(reg_beg + beg); | ||
| 199 | return nullptr; | ||
| 200 | } | ||
| 201 | |||
| 202 | uptr GetActuallyAllocatedSize(void *p) { | ||
| 203 | CHECK(PointerIsMine(p)); | ||
| 204 | return ClassIdToSize(GetSizeClass(p)); | ||
| 205 | } | ||
| 206 | |||
| 207 | static uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); } | ||
| 208 | |||
| 209 | void *GetMetaData(const void *p) { | ||
| 210 | uptr class_id = GetSizeClass(p); | ||
| 211 | uptr size = ClassIdToSize(class_id); | ||
| 212 | uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), size); | ||
| 213 | uptr region_beg = GetRegionBeginBySizeClass(class_id); | ||
| 214 | return reinterpret_cast<void *>(GetMetadataEnd(region_beg) - | ||
| 215 | (1 + chunk_idx) * kMetadataSize); | ||
| 216 | } | ||
| 217 | |||
| 218 | uptr TotalMemoryUsed() { | ||
| 219 | uptr res = 0; | ||
| 220 | for (uptr i = 0; i < kNumClasses; i++) | ||
| 221 | res += GetRegionInfo(i)->allocated_user; | ||
| 222 | return res; | ||
| 223 | } | ||
| 224 | |||
| 225 | // Test-only. | ||
| 226 | void TestOnlyUnmap() { | ||
| 227 | UnmapWithCallbackOrDie((uptr)address_range.base(), address_range.size()); | ||
| 228 | } | ||
| 229 | |||
| 230 | static void FillMemoryProfile(uptr start, uptr rss, bool file, uptr *stats, | ||
| 231 | uptr stats_size) { | ||
| 232 | for (uptr class_id = 0; class_id < stats_size; class_id++) | ||
| 233 | if (stats[class_id] == start) | ||
| 234 | stats[class_id] = rss; | ||
| 235 | } | ||
| 236 | |||
| 237 | void PrintStats(uptr class_id, uptr rss) { | ||
| 238 | RegionInfo *region = GetRegionInfo(class_id); | ||
| 239 | if (region->mapped_user == 0) return; | ||
| 240 | uptr in_use = region->stats.n_allocated - region->stats.n_freed; | ||
| 241 | uptr avail_chunks = region->allocated_user / ClassIdToSize(class_id); | ||
| 242 | Printf( | ||
| 243 | "%s %02zd (%6zd): mapped: %6zdK allocs: %7zd frees: %7zd inuse: %6zd " | ||
| 244 | "num_freed_chunks %7zd avail: %6zd rss: %6zdK releases: %6zd " | ||
| 245 | "last released: %6zdK region: 0x%zx\n", | ||
| 246 | region->exhausted ? "F" : " ", class_id, ClassIdToSize(class_id), | ||
| 247 | region->mapped_user >> 10, region->stats.n_allocated, | ||
| 248 | region->stats.n_freed, in_use, region->num_freed_chunks, avail_chunks, | ||
| 249 | rss >> 10, region->rtoi.num_releases, | ||
| 250 | region->rtoi.last_released_bytes >> 10, | ||
| 251 | SpaceBeg() + kRegionSize * class_id); | ||
| 252 | } | ||
| 253 | |||
| 254 | void PrintStats() { | ||
| 255 | uptr rss_stats[kNumClasses]; | ||
| 256 | for (uptr class_id = 0; class_id < kNumClasses; class_id++) | ||
| 257 | rss_stats[class_id] = SpaceBeg() + kRegionSize * class_id; | ||
| 258 | GetMemoryProfile(FillMemoryProfile, rss_stats, kNumClasses); | ||
| 259 | |||
| 260 | uptr total_mapped = 0; | ||
| 261 | uptr total_rss = 0; | ||
| 262 | uptr n_allocated = 0; | ||
| 263 | uptr n_freed = 0; | ||
| 264 | for (uptr class_id = 1; class_id < kNumClasses; class_id++) { | ||
| 265 | RegionInfo *region = GetRegionInfo(class_id); | ||
| 266 | if (region->mapped_user != 0) { | ||
| 267 | total_mapped += region->mapped_user; | ||
| 268 | total_rss += rss_stats[class_id]; | ||
| 269 | } | ||
| 270 | n_allocated += region->stats.n_allocated; | ||
| 271 | n_freed += region->stats.n_freed; | ||
| 272 | } | ||
| 273 | |||
| 274 | Printf("Stats: SizeClassAllocator64: %zdM mapped (%zdM rss) in " | ||
| 275 | "%zd allocations; remains %zd\n", total_mapped >> 20, | ||
| 276 | total_rss >> 20, n_allocated, n_allocated - n_freed); | ||
| 277 | for (uptr class_id = 1; class_id < kNumClasses; class_id++) | ||
| 278 | PrintStats(class_id, rss_stats[class_id]); | ||
| 279 | } | ||
| 280 | |||
| 281 | // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone | ||
| 282 | // introspection API. | ||
| 283 | void ForceLock() { | ||
| 284 | for (uptr i = 0; i < kNumClasses; i++) { | ||
| 285 | GetRegionInfo(i)->mutex.Lock(); | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 289 | void ForceUnlock() { | ||
| 290 | for (int i = (int)kNumClasses - 1; i >= 0; i--) { | ||
| 291 | GetRegionInfo(i)->mutex.Unlock(); | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 295 | // Iterate over all existing chunks. | ||
| 296 | // The allocator must be locked when calling this function. | ||
| 297 | void ForEachChunk(ForEachChunkCallback callback, void *arg) { | ||
| 298 | for (uptr class_id = 1; class_id < kNumClasses; class_id++) { | ||
| 299 | RegionInfo *region = GetRegionInfo(class_id); | ||
| 300 | uptr chunk_size = ClassIdToSize(class_id); | ||
| 301 | uptr region_beg = SpaceBeg() + class_id * kRegionSize; | ||
| 302 | uptr region_allocated_user_size = | ||
| 303 | AddressSpaceView::Load(region)->allocated_user; | ||
| 304 | for (uptr chunk = region_beg; | ||
| 305 | chunk < region_beg + region_allocated_user_size; | ||
| 306 | chunk += chunk_size) { | ||
| 307 | // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk)); | ||
| 308 | callback(chunk, arg); | ||
| 309 | } | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | static uptr ClassIdToSize(uptr class_id) { | ||
| 314 | return SizeClassMap::Size(class_id); | ||
| 315 | } | ||
| 316 | |||
| 317 | static uptr AdditionalSize() { | ||
| 318 | return RoundUpTo(sizeof(RegionInfo) * kNumClassesRounded, | ||
| 319 | GetPageSizeCached()); | ||
| 320 | } | ||
| 321 | |||
| 322 | typedef SizeClassMap SizeClassMapT; | ||
| 323 | static const uptr kNumClasses = SizeClassMap::kNumClasses; | ||
| 324 | static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded; | ||
| 325 | |||
| 326 | // A packed array of counters. Each counter occupies 2^n bits, enough to store | ||
| 327 | // counter's max_value. Ctor will try to allocate the required buffer via | ||
| 328 | // mapper->MapPackedCounterArrayBuffer and the caller is expected to check | ||
| 329 | // whether the initialization was successful by checking IsAllocated() result. | ||
| 330 | // For the performance sake, none of the accessors check the validity of the | ||
| 331 | // arguments, it is assumed that index is always in [0, n) range and the value | ||
| 332 | // is not incremented past max_value. | ||
| 333 | template<class MemoryMapperT> | ||
| 334 | class PackedCounterArray { | ||
| 335 | public: | ||
| 336 | PackedCounterArray(u64 num_counters, u64 max_value, MemoryMapperT *mapper) | ||
| 337 | : n(num_counters), memory_mapper(mapper) { | ||
| 338 | CHECK_GT(num_counters, 0); | ||
| 339 | CHECK_GT(max_value, 0); | ||
| 340 | constexpr u64 kMaxCounterBits = sizeof(*buffer) * 8ULL; | ||
| 341 | // Rounding counter storage size up to the power of two allows for using | ||
| 342 | // bit shifts calculating particular counter's index and offset. | ||
| 343 | uptr counter_size_bits = | ||
| 344 | RoundUpToPowerOfTwo(MostSignificantSetBitIndex(max_value) + 1); | ||
| 345 | CHECK_LE(counter_size_bits, kMaxCounterBits); | ||
| 346 | counter_size_bits_log = Log2(counter_size_bits); | ||
| 347 | counter_mask = ~0ULL >> (kMaxCounterBits - counter_size_bits); | ||
| 348 | |||
| 349 | uptr packing_ratio = kMaxCounterBits >> counter_size_bits_log; | ||
| 350 | CHECK_GT(packing_ratio, 0); | ||
| 351 | packing_ratio_log = Log2(packing_ratio); | ||
| 352 | bit_offset_mask = packing_ratio - 1; | ||
| 353 | |||
| 354 | buffer_size = | ||
| 355 | (RoundUpTo(n, 1ULL << packing_ratio_log) >> packing_ratio_log) * | ||
| 356 | sizeof(*buffer); | ||
| 357 | buffer = reinterpret_cast<u64*>( | ||
| 358 | memory_mapper->MapPackedCounterArrayBuffer(buffer_size)); | ||
| 359 | } | ||
| 360 | ~PackedCounterArray() { | ||
| 361 | if (buffer) { | ||
| 362 | memory_mapper->UnmapPackedCounterArrayBuffer( | ||
| 363 | reinterpret_cast<uptr>(buffer), buffer_size); | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | bool IsAllocated() const { | ||
| 368 | return !!buffer; | ||
| 369 | } | ||
| 370 | |||
| 371 | u64 GetCount() const { | ||
| 372 | return n; | ||
| 373 | } | ||
| 374 | |||
| 375 | uptr Get(uptr i) const { | ||
| 376 | DCHECK_LT(i, n); | ||
| 377 | uptr index = i >> packing_ratio_log; | ||
| 378 | uptr bit_offset = (i & bit_offset_mask) << counter_size_bits_log; | ||
| 379 | return (buffer[index] >> bit_offset) & counter_mask; | ||
| 380 | } | ||
| 381 | |||
| 382 | void Inc(uptr i) const { | ||
| 383 | DCHECK_LT(Get(i), counter_mask); | ||
| 384 | uptr index = i >> packing_ratio_log; | ||
| 385 | uptr bit_offset = (i & bit_offset_mask) << counter_size_bits_log; | ||
| 386 | buffer[index] += 1ULL << bit_offset; | ||
| 387 | } | ||
| 388 | |||
| 389 | void IncRange(uptr from, uptr to) const { | ||
| 390 | DCHECK_LE(from, to); | ||
| 391 | for (uptr i = from; i <= to; i++) | ||
| 392 | Inc(i); | ||
| 393 | } | ||
| 394 | |||
| 395 | private: | ||
| 396 | const u64 n; | ||
| 397 | u64 counter_size_bits_log; | ||
| 398 | u64 counter_mask; | ||
| 399 | u64 packing_ratio_log; | ||
| 400 | u64 bit_offset_mask; | ||
| 401 | |||
| 402 | MemoryMapperT* const memory_mapper; | ||
| 403 | u64 buffer_size; | ||
| 404 | u64* buffer; | ||
| 405 | }; | ||
| 406 | |||
| 407 | template<class MemoryMapperT> | ||
| 408 | class FreePagesRangeTracker { | ||
| 409 | public: | ||
| 410 | explicit FreePagesRangeTracker(MemoryMapperT* mapper) | ||
| 411 | : memory_mapper(mapper), | ||
| 412 | page_size_scaled_log(Log2(GetPageSizeCached() >> kCompactPtrScale)), | ||
| 413 | in_the_range(false), current_page(0), current_range_start_page(0) {} | ||
| 414 | |||
| 415 | void NextPage(bool freed) { | ||
| 416 | if (freed) { | ||
| 417 | if (!in_the_range) { | ||
| 418 | current_range_start_page = current_page; | ||
| 419 | in_the_range = true; | ||
| 420 | } | ||
| 421 | } else { | ||
| 422 | CloseOpenedRange(); | ||
| 423 | } | ||
| 424 | current_page++; | ||
| 425 | } | ||
| 426 | |||
| 427 | void Done() { | ||
| 428 | CloseOpenedRange(); | ||
| 429 | } | ||
| 430 | |||
| 431 | private: | ||
| 432 | void CloseOpenedRange() { | ||
| 433 | if (in_the_range) { | ||
| 434 | memory_mapper->ReleasePageRangeToOS( | ||
| 435 | current_range_start_page << page_size_scaled_log, | ||
| 436 | current_page << page_size_scaled_log); | ||
| 437 | in_the_range = false; | ||
| 438 | } | ||
| 439 | } | ||
| 440 | |||
| 441 | MemoryMapperT* const memory_mapper; | ||
| 442 | const uptr page_size_scaled_log; | ||
| 443 | bool in_the_range; | ||
| 444 | uptr current_page; | ||
| 445 | uptr current_range_start_page; | ||
| 446 | }; | ||
| 447 | |||
| 448 | // Iterates over the free_array to identify memory pages containing freed | ||
| 449 | // chunks only and returns these pages back to OS. | ||
| 450 | // allocated_pages_count is the total number of pages allocated for the | ||
| 451 | // current bucket. | ||
| 452 | template<class MemoryMapperT> | ||
| 453 | static void ReleaseFreeMemoryToOS(CompactPtrT *free_array, | ||
| 454 | uptr free_array_count, uptr chunk_size, | ||
| 455 | uptr allocated_pages_count, | ||
| 456 | MemoryMapperT *memory_mapper) { | ||
| 457 | const uptr page_size = GetPageSizeCached(); | ||
| 458 | |||
| 459 | // Figure out the number of chunks per page and whether we can take a fast | ||
| 460 | // path (the number of chunks per page is the same for all pages). | ||
| 461 | uptr full_pages_chunk_count_max; | ||
| 462 | bool same_chunk_count_per_page; | ||
| 463 | if (chunk_size <= page_size && page_size % chunk_size == 0) { | ||
| 464 | // Same number of chunks per page, no cross overs. | ||
| 465 | full_pages_chunk_count_max = page_size / chunk_size; | ||
| 466 | same_chunk_count_per_page = true; | ||
| 467 | } else if (chunk_size <= page_size && page_size % chunk_size != 0 && | ||
| 468 | chunk_size % (page_size % chunk_size) == 0) { | ||
| 469 | // Some chunks are crossing page boundaries, which means that the page | ||
| 470 | // contains one or two partial chunks, but all pages contain the same | ||
| 471 | // number of chunks. | ||
| 472 | full_pages_chunk_count_max = page_size / chunk_size + 1; | ||
| 473 | same_chunk_count_per_page = true; | ||
| 474 | } else if (chunk_size <= page_size) { | ||
| 475 | // Some chunks are crossing page boundaries, which means that the page | ||
| 476 | // contains one or two partial chunks. | ||
| 477 | full_pages_chunk_count_max = page_size / chunk_size + 2; | ||
| 478 | same_chunk_count_per_page = false; | ||
| 479 | } else if (chunk_size > page_size && chunk_size % page_size == 0) { | ||
| 480 | // One chunk covers multiple pages, no cross overs. | ||
| 481 | full_pages_chunk_count_max = 1; | ||
| 482 | same_chunk_count_per_page = true; | ||
| 483 | } else if (chunk_size > page_size) { | ||
| 484 | // One chunk covers multiple pages, Some chunks are crossing page | ||
| 485 | // boundaries. Some pages contain one chunk, some contain two. | ||
| 486 | full_pages_chunk_count_max = 2; | ||
| 487 | same_chunk_count_per_page = false; | ||
| 488 | } else { | ||
| 489 | UNREACHABLE("All chunk_size/page_size ratios must be handled."); | ||
| 490 | } | ||
| 491 | |||
| 492 | PackedCounterArray<MemoryMapperT> counters(allocated_pages_count, | ||
| 493 | full_pages_chunk_count_max, | ||
| 494 | memory_mapper); | ||
| 495 | if (!counters.IsAllocated()) | ||
| 496 | return; | ||
| 497 | |||
| 498 | const uptr chunk_size_scaled = chunk_size >> kCompactPtrScale; | ||
| 499 | const uptr page_size_scaled = page_size >> kCompactPtrScale; | ||
| 500 | const uptr page_size_scaled_log = Log2(page_size_scaled); | ||
| 501 | |||
| 502 | // Iterate over free chunks and count how many free chunks affect each | ||
| 503 | // allocated page. | ||
| 504 | if (chunk_size <= page_size && page_size % chunk_size == 0) { | ||
| 505 | // Each chunk affects one page only. | ||
| 506 | for (uptr i = 0; i < free_array_count; i++) | ||
| 507 | counters.Inc(free_array[i] >> page_size_scaled_log); | ||
| 508 | } else { | ||
| 509 | // In all other cases chunks might affect more than one page. | ||
| 510 | for (uptr i = 0; i < free_array_count; i++) { | ||
| 511 | counters.IncRange( | ||
| 512 | free_array[i] >> page_size_scaled_log, | ||
| 513 | (free_array[i] + chunk_size_scaled - 1) >> page_size_scaled_log); | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | // Iterate over pages detecting ranges of pages with chunk counters equal | ||
| 518 | // to the expected number of chunks for the particular page. | ||
| 519 | FreePagesRangeTracker<MemoryMapperT> range_tracker(memory_mapper); | ||
| 520 | if (same_chunk_count_per_page) { | ||
| 521 | // Fast path, every page has the same number of chunks affecting it. | ||
| 522 | for (uptr i = 0; i < counters.GetCount(); i++) | ||
| 523 | range_tracker.NextPage(counters.Get(i) == full_pages_chunk_count_max); | ||
| 524 | } else { | ||
| 525 | // Show path, go through the pages keeping count how many chunks affect | ||
| 526 | // each page. | ||
| 527 | const uptr pn = | ||
| 528 | chunk_size < page_size ? page_size_scaled / chunk_size_scaled : 1; | ||
| 529 | const uptr pnc = pn * chunk_size_scaled; | ||
| 530 | // The idea is to increment the current page pointer by the first chunk | ||
| 531 | // size, middle portion size (the portion of the page covered by chunks | ||
| 532 | // except the first and the last one) and then the last chunk size, adding | ||
| 533 | // up the number of chunks on the current page and checking on every step | ||
| 534 | // whether the page boundary was crossed. | ||
| 535 | uptr prev_page_boundary = 0; | ||
| 536 | uptr current_boundary = 0; | ||
| 537 | for (uptr i = 0; i < counters.GetCount(); i++) { | ||
| 538 | uptr page_boundary = prev_page_boundary + page_size_scaled; | ||
| 539 | uptr chunks_per_page = pn; | ||
| 540 | if (current_boundary < page_boundary) { | ||
| 541 | if (current_boundary > prev_page_boundary) | ||
| 542 | chunks_per_page++; | ||
| 543 | current_boundary += pnc; | ||
| 544 | if (current_boundary < page_boundary) { | ||
| 545 | chunks_per_page++; | ||
| 546 | current_boundary += chunk_size_scaled; | ||
| 547 | } | ||
| 548 | } | ||
| 549 | prev_page_boundary = page_boundary; | ||
| 550 | |||
| 551 | range_tracker.NextPage(counters.Get(i) == chunks_per_page); | ||
| 552 | } | ||
| 553 | } | ||
| 554 | range_tracker.Done(); | ||
| 555 | } | ||
| 556 | |||
| 557 | private: | ||
| 558 | friend class MemoryMapper; | ||
| 559 | |||
| 560 | ReservedAddressRange address_range; | ||
| 561 | |||
| 562 | static const uptr kRegionSize = kSpaceSize / kNumClassesRounded; | ||
| 563 | // FreeArray is the array of free-d chunks (stored as 4-byte offsets). | ||
| 564 | // In the worst case it may reguire kRegionSize/SizeClassMap::kMinSize | ||
| 565 | // elements, but in reality this will not happen. For simplicity we | ||
| 566 | // dedicate 1/8 of the region's virtual space to FreeArray. | ||
| 567 | static const uptr kFreeArraySize = kRegionSize / 8; | ||
| 568 | |||
| 569 | static const bool kUsingConstantSpaceBeg = kSpaceBeg != ~(uptr)0; | ||
| 570 | uptr NonConstSpaceBeg; | ||
| 571 | uptr SpaceBeg() const { | ||
| 572 | return kUsingConstantSpaceBeg ? kSpaceBeg : NonConstSpaceBeg; | ||
| 573 | } | ||
| 574 | uptr SpaceEnd() const { return SpaceBeg() + kSpaceSize; } | ||
| 575 | // kRegionSize must be >= 2^32. | ||
| 576 | COMPILER_CHECK((kRegionSize) >= (1ULL << (SANITIZER_WORDSIZE / 2))); | ||
| 577 | // kRegionSize must be <= 2^36, see CompactPtrT. | ||
| 578 | COMPILER_CHECK((kRegionSize) <= (1ULL << (SANITIZER_WORDSIZE / 2 + 4))); | ||
| 579 | // Call mmap for user memory with at least this size. | ||
| 580 | static const uptr kUserMapSize = 1 << 16; | ||
| 581 | // Call mmap for metadata memory with at least this size. | ||
| 582 | static const uptr kMetaMapSize = 1 << 16; | ||
| 583 | // Call mmap for free array memory with at least this size. | ||
| 584 | static const uptr kFreeArrayMapSize = 1 << 16; | ||
| 585 | |||
| 586 | atomic_sint32_t release_to_os_interval_ms_; | ||
| 587 | |||
| 588 | struct Stats { | ||
| 589 | uptr n_allocated; | ||
| 590 | uptr n_freed; | ||
| 591 | }; | ||
| 592 | |||
| 593 | struct ReleaseToOsInfo { | ||
| 594 | uptr n_freed_at_last_release; | ||
| 595 | uptr num_releases; | ||
| 596 | u64 last_release_at_ns; | ||
| 597 | u64 last_released_bytes; | ||
| 598 | }; | ||
| 599 | |||
| 600 | struct ALIGNED(SANITIZER_CACHE_LINE_SIZE) RegionInfo { | ||
| 601 | BlockingMutex mutex; | ||
| 602 | uptr num_freed_chunks; // Number of elements in the freearray. | ||
| 603 | uptr mapped_free_array; // Bytes mapped for freearray. | ||
| 604 | uptr allocated_user; // Bytes allocated for user memory. | ||
| 605 | uptr allocated_meta; // Bytes allocated for metadata. | ||
| 606 | uptr mapped_user; // Bytes mapped for user memory. | ||
| 607 | uptr mapped_meta; // Bytes mapped for metadata. | ||
| 608 | u32 rand_state; // Seed for random shuffle, used if kRandomShuffleChunks. | ||
| 609 | bool exhausted; // Whether region is out of space for new chunks. | ||
| 610 | Stats stats; | ||
| 611 | ReleaseToOsInfo rtoi; | ||
| 612 | }; | ||
| 613 | COMPILER_CHECK(sizeof(RegionInfo) % kCacheLineSize == 0); | ||
| 614 | |||
| 615 | RegionInfo *GetRegionInfo(uptr class_id) const { | ||
| 616 | DCHECK_LT(class_id, kNumClasses); | ||
| 617 | RegionInfo *regions = reinterpret_cast<RegionInfo *>(SpaceEnd()); | ||
| 618 | return &regions[class_id]; | ||
| 619 | } | ||
| 620 | |||
| 621 | uptr GetMetadataEnd(uptr region_beg) const { | ||
| 622 | return region_beg + kRegionSize - kFreeArraySize; | ||
| 623 | } | ||
| 624 | |||
| 625 | uptr GetChunkIdx(uptr chunk, uptr size) const { | ||
| 626 | if (!kUsingConstantSpaceBeg) | ||
| 627 | chunk -= SpaceBeg(); | ||
| 628 | |||
| 629 | uptr offset = chunk % kRegionSize; | ||
| 630 | // Here we divide by a non-constant. This is costly. | ||
| 631 | // size always fits into 32-bits. If the offset fits too, use 32-bit div. | ||
| 632 | if (offset >> (SANITIZER_WORDSIZE / 2)) | ||
| 633 | return offset / size; | ||
| 634 | return (u32)offset / (u32)size; | ||
| 635 | } | ||
| 636 | |||
| 637 | CompactPtrT *GetFreeArray(uptr region_beg) const { | ||
| 638 | return reinterpret_cast<CompactPtrT *>(GetMetadataEnd(region_beg)); | ||
| 639 | } | ||
| 640 | |||
| 641 | bool MapWithCallback(uptr beg, uptr size, const char *name) { | ||
| 642 | uptr mapped = address_range.Map(beg, size, name); | ||
| 643 | if (UNLIKELY(!mapped)) | ||
| 644 | return false; | ||
| 645 | CHECK_EQ(beg, mapped); | ||
| 646 | MapUnmapCallback().OnMap(beg, size); | ||
| 647 | return true; | ||
| 648 | } | ||
| 649 | |||
| 650 | void MapWithCallbackOrDie(uptr beg, uptr size, const char *name) { | ||
| 651 | CHECK_EQ(beg, address_range.MapOrDie(beg, size, name)); | ||
| 652 | MapUnmapCallback().OnMap(beg, size); | ||
| 653 | } | ||
| 654 | |||
| 655 | void UnmapWithCallbackOrDie(uptr beg, uptr size) { | ||
| 656 | MapUnmapCallback().OnUnmap(beg, size); | ||
| 657 | address_range.Unmap(beg, size); | ||
| 658 | } | ||
| 659 | |||
| 660 | bool EnsureFreeArraySpace(RegionInfo *region, uptr region_beg, | ||
| 661 | uptr num_freed_chunks) { | ||
| 662 | uptr needed_space = num_freed_chunks * sizeof(CompactPtrT); | ||
| 663 | if (region->mapped_free_array < needed_space) { | ||
| 664 | uptr new_mapped_free_array = RoundUpTo(needed_space, kFreeArrayMapSize); | ||
| 665 | CHECK_LE(new_mapped_free_array, kFreeArraySize); | ||
| 666 | uptr current_map_end = reinterpret_cast<uptr>(GetFreeArray(region_beg)) + | ||
| 667 | region->mapped_free_array; | ||
| 668 | uptr new_map_size = new_mapped_free_array - region->mapped_free_array; | ||
| 669 | if (UNLIKELY(!MapWithCallback(current_map_end, new_map_size, | ||
| 670 | "SizeClassAllocator: freearray"))) | ||
| 671 | return false; | ||
| 672 | region->mapped_free_array = new_mapped_free_array; | ||
| 673 | } | ||
| 674 | return true; | ||
| 675 | } | ||
| 676 | |||
| 677 | // Check whether this size class is exhausted. | ||
| 678 | bool IsRegionExhausted(RegionInfo *region, uptr class_id, | ||
| 679 | uptr additional_map_size) { | ||
| 680 | if (LIKELY(region->mapped_user + region->mapped_meta + | ||
| 681 | additional_map_size <= kRegionSize - kFreeArraySize)) | ||
| 682 | return false; | ||
| 683 | if (!region->exhausted) { | ||
| 684 | region->exhausted = true; | ||
| 685 | Printf("%s: Out of memory. ", SanitizerToolName); | ||
| 686 | Printf("The process has exhausted %zuMB for size class %zu.\n", | ||
| 687 | kRegionSize >> 20, ClassIdToSize(class_id)); | ||
| 688 | } | ||
| 689 | return true; | ||
| 690 | } | ||
| 691 | |||
| 692 | NOINLINE bool PopulateFreeArray(AllocatorStats *stat, uptr class_id, | ||
| 693 | RegionInfo *region, uptr requested_count) { | ||
| 694 | // region->mutex is held. | ||
| 695 | const uptr region_beg = GetRegionBeginBySizeClass(class_id); | ||
| 696 | const uptr size = ClassIdToSize(class_id); | ||
| 697 | |||
| 698 | const uptr total_user_bytes = | ||
| 699 | region->allocated_user + requested_count * size; | ||
| 700 | // Map more space for chunks, if necessary. | ||
| 701 | if (LIKELY(total_user_bytes > region->mapped_user)) { | ||
| 702 | if (UNLIKELY(region->mapped_user == 0)) { | ||
| 703 | if (!kUsingConstantSpaceBeg && kRandomShuffleChunks) | ||
| 704 | // The random state is initialized from ASLR. | ||
| 705 | region->rand_state = static_cast<u32>(region_beg >> 12); | ||
| 706 | // Postpone the first release to OS attempt for ReleaseToOSIntervalMs, | ||
| 707 | // preventing just allocated memory from being released sooner than | ||
| 708 | // necessary and also preventing extraneous ReleaseMemoryPagesToOS calls | ||
| 709 | // for short lived processes. | ||
| 710 | // Do it only when the feature is turned on, to avoid a potentially | ||
| 711 | // extraneous syscall. | ||
| 712 | if (ReleaseToOSIntervalMs() >= 0) | ||
| 713 | region->rtoi.last_release_at_ns = MonotonicNanoTime(); | ||
| 714 | } | ||
| 715 | // Do the mmap for the user memory. | ||
| 716 | const uptr user_map_size = | ||
| 717 | RoundUpTo(total_user_bytes - region->mapped_user, kUserMapSize); | ||
| 718 | if (UNLIKELY(IsRegionExhausted(region, class_id, user_map_size))) | ||
| 719 | return false; | ||
| 720 | if (UNLIKELY(!MapWithCallback(region_beg + region->mapped_user, | ||
| 721 | user_map_size, | ||
| 722 | "SizeClassAllocator: region data"))) | ||
| 723 | return false; | ||
| 724 | stat->Add(AllocatorStatMapped, user_map_size); | ||
| 725 | region->mapped_user += user_map_size; | ||
| 726 | } | ||
| 727 | const uptr new_chunks_count = | ||
| 728 | (region->mapped_user - region->allocated_user) / size; | ||
| 729 | |||
| 730 | if (kMetadataSize) { | ||
| 731 | // Calculate the required space for metadata. | ||
| 732 | const uptr total_meta_bytes = | ||
| 733 | region->allocated_meta + new_chunks_count * kMetadataSize; | ||
| 734 | const uptr meta_map_size = (total_meta_bytes > region->mapped_meta) ? | ||
| 735 | RoundUpTo(total_meta_bytes - region->mapped_meta, kMetaMapSize) : 0; | ||
| 736 | // Map more space for metadata, if necessary. | ||
| 737 | if (meta_map_size) { | ||
| 738 | if (UNLIKELY(IsRegionExhausted(region, class_id, meta_map_size))) | ||
| 739 | return false; | ||
| 740 | if (UNLIKELY(!MapWithCallback( | ||
| 741 | GetMetadataEnd(region_beg) - region->mapped_meta - meta_map_size, | ||
| 742 | meta_map_size, "SizeClassAllocator: region metadata"))) | ||
| 743 | return false; | ||
| 744 | region->mapped_meta += meta_map_size; | ||
| 745 | } | ||
| 746 | } | ||
| 747 | |||
| 748 | // If necessary, allocate more space for the free array and populate it with | ||
| 749 | // newly allocated chunks. | ||
| 750 | const uptr total_freed_chunks = region->num_freed_chunks + new_chunks_count; | ||
| 751 | if (UNLIKELY(!EnsureFreeArraySpace(region, region_beg, total_freed_chunks))) | ||
| 752 | return false; | ||
| 753 | CompactPtrT *free_array = GetFreeArray(region_beg); | ||
| 754 | for (uptr i = 0, chunk = region->allocated_user; i < new_chunks_count; | ||
| 755 | i++, chunk += size) | ||
| 756 | free_array[total_freed_chunks - 1 - i] = PointerToCompactPtr(0, chunk); | ||
| 757 | if (kRandomShuffleChunks) | ||
| 758 | RandomShuffle(&free_array[region->num_freed_chunks], new_chunks_count, | ||
| 759 | &region->rand_state); | ||
| 760 | |||
| 761 | // All necessary memory is mapped and now it is safe to advance all | ||
| 762 | // 'allocated_*' counters. | ||
| 763 | region->num_freed_chunks += new_chunks_count; | ||
| 764 | region->allocated_user += new_chunks_count * size; | ||
| 765 | CHECK_LE(region->allocated_user, region->mapped_user); | ||
| 766 | region->allocated_meta += new_chunks_count * kMetadataSize; | ||
| 767 | CHECK_LE(region->allocated_meta, region->mapped_meta); | ||
| 768 | region->exhausted = false; | ||
| 769 | |||
| 770 | // TODO(alekseyshl): Consider bumping last_release_at_ns here to prevent | ||
| 771 | // MaybeReleaseToOS from releasing just allocated pages or protect these | ||
| 772 | // not yet used chunks some other way. | ||
| 773 | |||
| 774 | return true; | ||
| 775 | } | ||
| 776 | |||
| 777 | class MemoryMapper { | ||
| 778 | public: | ||
| 779 | MemoryMapper(const ThisT& base_allocator, uptr class_id) | ||
| 780 | : allocator(base_allocator), | ||
| 781 | region_base(base_allocator.GetRegionBeginBySizeClass(class_id)), | ||
| 782 | released_ranges_count(0), | ||
| 783 | released_bytes(0) { | ||
| 784 | } | ||
| 785 | |||
| 786 | uptr GetReleasedRangesCount() const { | ||
| 787 | return released_ranges_count; | ||
| 788 | } | ||
| 789 | |||
| 790 | uptr GetReleasedBytes() const { | ||
| 791 | return released_bytes; | ||
| 792 | } | ||
| 793 | |||
| 794 | uptr MapPackedCounterArrayBuffer(uptr buffer_size) { | ||
| 795 | // TODO(alekseyshl): The idea to explore is to check if we have enough | ||
| 796 | // space between num_freed_chunks*sizeof(CompactPtrT) and | ||
| 797 | // mapped_free_array to fit buffer_size bytes and use that space instead | ||
| 798 | // of mapping a temporary one. | ||
| 799 | return reinterpret_cast<uptr>( | ||
| 800 | MmapOrDieOnFatalError(buffer_size, "ReleaseToOSPageCounters")); | ||
| 801 | } | ||
| 802 | |||
| 803 | void UnmapPackedCounterArrayBuffer(uptr buffer, uptr buffer_size) { | ||
| 804 | UnmapOrDie(reinterpret_cast<void *>(buffer), buffer_size); | ||
| 805 | } | ||
| 806 | |||
| 807 | // Releases [from, to) range of pages back to OS. | ||
| 808 | void ReleasePageRangeToOS(CompactPtrT from, CompactPtrT to) { | ||
| 809 | const uptr from_page = allocator.CompactPtrToPointer(region_base, from); | ||
| 810 | const uptr to_page = allocator.CompactPtrToPointer(region_base, to); | ||
| 811 | ReleaseMemoryPagesToOS(from_page, to_page); | ||
| 812 | released_ranges_count++; | ||
| 813 | released_bytes += to_page - from_page; | ||
| 814 | } | ||
| 815 | |||
| 816 | private: | ||
| 817 | const ThisT& allocator; | ||
| 818 | const uptr region_base; | ||
| 819 | uptr released_ranges_count; | ||
| 820 | uptr released_bytes; | ||
| 821 | }; | ||
| 822 | |||
| 823 | // Attempts to release RAM occupied by freed chunks back to OS. The region is | ||
| 824 | // expected to be locked. | ||
| 825 | void MaybeReleaseToOS(uptr class_id, bool force) { | ||
| 826 | RegionInfo *region = GetRegionInfo(class_id); | ||
| 827 | const uptr chunk_size = ClassIdToSize(class_id); | ||
| 828 | const uptr page_size = GetPageSizeCached(); | ||
| 829 | |||
| 830 | uptr n = region->num_freed_chunks; | ||
| 831 | if (n * chunk_size < page_size) | ||
| 832 | return; // No chance to release anything. | ||
| 833 | if ((region->stats.n_freed - | ||
| 834 | region->rtoi.n_freed_at_last_release) * chunk_size < page_size) { | ||
| 835 | return; // Nothing new to release. | ||
| 836 | } | ||
| 837 | |||
| 838 | if (!force) { | ||
| 839 | s32 interval_ms = ReleaseToOSIntervalMs(); | ||
| 840 | if (interval_ms < 0) | ||
| 841 | return; | ||
| 842 | |||
| 843 | if (region->rtoi.last_release_at_ns + interval_ms * 1000000ULL > | ||
| 844 | MonotonicNanoTime()) { | ||
| 845 | return; // Memory was returned recently. | ||
| 846 | } | ||
| 847 | } | ||
| 848 | |||
| 849 | MemoryMapper memory_mapper(*this, class_id); | ||
| 850 | |||
| 851 | ReleaseFreeMemoryToOS<MemoryMapper>( | ||
| 852 | GetFreeArray(GetRegionBeginBySizeClass(class_id)), n, chunk_size, | ||
| 853 | RoundUpTo(region->allocated_user, page_size) / page_size, | ||
| 854 | &memory_mapper); | ||
| 855 | |||
| 856 | if (memory_mapper.GetReleasedRangesCount() > 0) { | ||
| 857 | region->rtoi.n_freed_at_last_release = region->stats.n_freed; | ||
| 858 | region->rtoi.num_releases += memory_mapper.GetReleasedRangesCount(); | ||
| 859 | region->rtoi.last_released_bytes = memory_mapper.GetReleasedBytes(); | ||
| 860 | } | ||
| 861 | region->rtoi.last_release_at_ns = MonotonicNanoTime(); | ||
| 862 | } | ||
| 863 | }; | ||
lib/tsan/sanitizer_common/sanitizer_allocator_report.h created+39| ... | @@ -0,0 +1,39 @@ | ||
| 1 | //===-- sanitizer_allocator_report.h ----------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | /// | ||
| 9 | /// \file | ||
| 10 | /// Shared allocator error reporting for ThreadSanitizer, MemorySanitizer, etc. | ||
| 11 | /// | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_ALLOCATOR_REPORT_H | ||
| 15 | #define SANITIZER_ALLOCATOR_REPORT_H | ||
| 16 | |||
| 17 | #include "sanitizer_internal_defs.h" | ||
| 18 | #include "sanitizer_stacktrace.h" | ||
| 19 | |||
| 20 | namespace __sanitizer { | ||
| 21 | |||
| 22 | void NORETURN ReportCallocOverflow(uptr count, uptr size, | ||
| 23 | const StackTrace *stack); | ||
| 24 | void NORETURN ReportReallocArrayOverflow(uptr count, uptr size, | ||
| 25 | const StackTrace *stack); | ||
| 26 | void NORETURN ReportPvallocOverflow(uptr size, const StackTrace *stack); | ||
| 27 | void NORETURN ReportInvalidAllocationAlignment(uptr alignment, | ||
| 28 | const StackTrace *stack); | ||
| 29 | void NORETURN ReportInvalidAlignedAllocAlignment(uptr size, uptr alignment, | ||
| 30 | const StackTrace *stack); | ||
| 31 | void NORETURN ReportInvalidPosixMemalignAlignment(uptr alignment, | ||
| 32 | const StackTrace *stack); | ||
| 33 | void NORETURN ReportAllocationSizeTooBig(uptr user_size, uptr max_size, | ||
| 34 | const StackTrace *stack); | ||
| 35 | void NORETURN ReportOutOfMemory(uptr requested_size, const StackTrace *stack); | ||
| 36 | |||
| 37 | } // namespace __sanitizer | ||
| 38 | |||
| 39 | #endif // SANITIZER_ALLOCATOR_REPORT_H | ||
lib/tsan/sanitizer_common/sanitizer_allocator_secondary.h created+326| ... | @@ -0,0 +1,326 @@ | ||
| 1 | //===-- sanitizer_allocator_secondary.h -------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Part of the Sanitizer Allocator. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_ALLOCATOR_H | ||
| 13 | #error This file must be included inside sanitizer_allocator.h | ||
| 14 | #endif | ||
| 15 | |||
| 16 | // Fixed array to store LargeMmapAllocator chunks list, limited to 32K total | ||
| 17 | // allocated chunks. To be used in memory constrained or not memory hungry cases | ||
| 18 | // (currently, 32 bits and internal allocator). | ||
| 19 | class LargeMmapAllocatorPtrArrayStatic { | ||
| 20 | public: | ||
| 21 | INLINE void *Init() { return &p_[0]; } | ||
| 22 | INLINE void EnsureSpace(uptr n) { CHECK_LT(n, kMaxNumChunks); } | ||
| 23 | private: | ||
| 24 | static const int kMaxNumChunks = 1 << 15; | ||
| 25 | uptr p_[kMaxNumChunks]; | ||
| 26 | }; | ||
| 27 | |||
| 28 | // Much less restricted LargeMmapAllocator chunks list (comparing to | ||
| 29 | // PtrArrayStatic). Backed by mmaped memory region and can hold up to 1M chunks. | ||
| 30 | // ReservedAddressRange was used instead of just MAP_NORESERVE to achieve the | ||
| 31 | // same functionality in Fuchsia case, which does not support MAP_NORESERVE. | ||
| 32 | class LargeMmapAllocatorPtrArrayDynamic { | ||
| 33 | public: | ||
| 34 | INLINE void *Init() { | ||
| 35 | uptr p = address_range_.Init(kMaxNumChunks * sizeof(uptr), | ||
| 36 | SecondaryAllocatorName); | ||
| 37 | CHECK(p); | ||
| 38 | return reinterpret_cast<void*>(p); | ||
| 39 | } | ||
| 40 | |||
| 41 | INLINE void EnsureSpace(uptr n) { | ||
| 42 | CHECK_LT(n, kMaxNumChunks); | ||
| 43 | DCHECK(n <= n_reserved_); | ||
| 44 | if (UNLIKELY(n == n_reserved_)) { | ||
| 45 | address_range_.MapOrDie( | ||
| 46 | reinterpret_cast<uptr>(address_range_.base()) + | ||
| 47 | n_reserved_ * sizeof(uptr), | ||
| 48 | kChunksBlockCount * sizeof(uptr)); | ||
| 49 | n_reserved_ += kChunksBlockCount; | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | private: | ||
| 54 | static const int kMaxNumChunks = 1 << 20; | ||
| 55 | static const int kChunksBlockCount = 1 << 14; | ||
| 56 | ReservedAddressRange address_range_; | ||
| 57 | uptr n_reserved_; | ||
| 58 | }; | ||
| 59 | |||
| 60 | #if SANITIZER_WORDSIZE == 32 | ||
| 61 | typedef LargeMmapAllocatorPtrArrayStatic DefaultLargeMmapAllocatorPtrArray; | ||
| 62 | #else | ||
| 63 | typedef LargeMmapAllocatorPtrArrayDynamic DefaultLargeMmapAllocatorPtrArray; | ||
| 64 | #endif | ||
| 65 | |||
| 66 | // This class can (de)allocate only large chunks of memory using mmap/unmap. | ||
| 67 | // The main purpose of this allocator is to cover large and rare allocation | ||
| 68 | // sizes not covered by more efficient allocators (e.g. SizeClassAllocator64). | ||
| 69 | template <class MapUnmapCallback = NoOpMapUnmapCallback, | ||
| 70 | class PtrArrayT = DefaultLargeMmapAllocatorPtrArray, | ||
| 71 | class AddressSpaceViewTy = LocalAddressSpaceView> | ||
| 72 | class LargeMmapAllocator { | ||
| 73 | public: | ||
| 74 | using AddressSpaceView = AddressSpaceViewTy; | ||
| 75 | void InitLinkerInitialized() { | ||
| 76 | page_size_ = GetPageSizeCached(); | ||
| 77 | chunks_ = reinterpret_cast<Header**>(ptr_array_.Init()); | ||
| 78 | } | ||
| 79 | |||
| 80 | void Init() { | ||
| 81 | internal_memset(this, 0, sizeof(*this)); | ||
| 82 | InitLinkerInitialized(); | ||
| 83 | } | ||
| 84 | |||
| 85 | void *Allocate(AllocatorStats *stat, uptr size, uptr alignment) { | ||
| 86 | CHECK(IsPowerOfTwo(alignment)); | ||
| 87 | uptr map_size = RoundUpMapSize(size); | ||
| 88 | if (alignment > page_size_) | ||
| 89 | map_size += alignment; | ||
| 90 | // Overflow. | ||
| 91 | if (map_size < size) { | ||
| 92 | Report("WARNING: %s: LargeMmapAllocator allocation overflow: " | ||
| 93 | "0x%zx bytes with 0x%zx alignment requested\n", | ||
| 94 | SanitizerToolName, map_size, alignment); | ||
| 95 | return nullptr; | ||
| 96 | } | ||
| 97 | uptr map_beg = reinterpret_cast<uptr>( | ||
| 98 | MmapOrDieOnFatalError(map_size, SecondaryAllocatorName)); | ||
| 99 | if (!map_beg) | ||
| 100 | return nullptr; | ||
| 101 | CHECK(IsAligned(map_beg, page_size_)); | ||
| 102 | MapUnmapCallback().OnMap(map_beg, map_size); | ||
| 103 | uptr map_end = map_beg + map_size; | ||
| 104 | uptr res = map_beg + page_size_; | ||
| 105 | if (res & (alignment - 1)) // Align. | ||
| 106 | res += alignment - (res & (alignment - 1)); | ||
| 107 | CHECK(IsAligned(res, alignment)); | ||
| 108 | CHECK(IsAligned(res, page_size_)); | ||
| 109 | CHECK_GE(res + size, map_beg); | ||
| 110 | CHECK_LE(res + size, map_end); | ||
| 111 | Header *h = GetHeader(res); | ||
| 112 | h->size = size; | ||
| 113 | h->map_beg = map_beg; | ||
| 114 | h->map_size = map_size; | ||
| 115 | uptr size_log = MostSignificantSetBitIndex(map_size); | ||
| 116 | CHECK_LT(size_log, ARRAY_SIZE(stats.by_size_log)); | ||
| 117 | { | ||
| 118 | SpinMutexLock l(&mutex_); | ||
| 119 | ptr_array_.EnsureSpace(n_chunks_); | ||
| 120 | uptr idx = n_chunks_++; | ||
| 121 | h->chunk_idx = idx; | ||
| 122 | chunks_[idx] = h; | ||
| 123 | chunks_sorted_ = false; | ||
| 124 | stats.n_allocs++; | ||
| 125 | stats.currently_allocated += map_size; | ||
| 126 | stats.max_allocated = Max(stats.max_allocated, stats.currently_allocated); | ||
| 127 | stats.by_size_log[size_log]++; | ||
| 128 | stat->Add(AllocatorStatAllocated, map_size); | ||
| 129 | stat->Add(AllocatorStatMapped, map_size); | ||
| 130 | } | ||
| 131 | return reinterpret_cast<void*>(res); | ||
| 132 | } | ||
| 133 | |||
| 134 | void Deallocate(AllocatorStats *stat, void *p) { | ||
| 135 | Header *h = GetHeader(p); | ||
| 136 | { | ||
| 137 | SpinMutexLock l(&mutex_); | ||
| 138 | uptr idx = h->chunk_idx; | ||
| 139 | CHECK_EQ(chunks_[idx], h); | ||
| 140 | CHECK_LT(idx, n_chunks_); | ||
| 141 | chunks_[idx] = chunks_[--n_chunks_]; | ||
| 142 | chunks_[idx]->chunk_idx = idx; | ||
| 143 | chunks_sorted_ = false; | ||
| 144 | stats.n_frees++; | ||
| 145 | stats.currently_allocated -= h->map_size; | ||
| 146 | stat->Sub(AllocatorStatAllocated, h->map_size); | ||
| 147 | stat->Sub(AllocatorStatMapped, h->map_size); | ||
| 148 | } | ||
| 149 | MapUnmapCallback().OnUnmap(h->map_beg, h->map_size); | ||
| 150 | UnmapOrDie(reinterpret_cast<void*>(h->map_beg), h->map_size); | ||
| 151 | } | ||
| 152 | |||
| 153 | uptr TotalMemoryUsed() { | ||
| 154 | SpinMutexLock l(&mutex_); | ||
| 155 | uptr res = 0; | ||
| 156 | for (uptr i = 0; i < n_chunks_; i++) { | ||
| 157 | Header *h = chunks_[i]; | ||
| 158 | CHECK_EQ(h->chunk_idx, i); | ||
| 159 | res += RoundUpMapSize(h->size); | ||
| 160 | } | ||
| 161 | return res; | ||
| 162 | } | ||
| 163 | |||
| 164 | bool PointerIsMine(const void *p) { | ||
| 165 | return GetBlockBegin(p) != nullptr; | ||
| 166 | } | ||
| 167 | |||
| 168 | uptr GetActuallyAllocatedSize(void *p) { | ||
| 169 | return RoundUpTo(GetHeader(p)->size, page_size_); | ||
| 170 | } | ||
| 171 | |||
| 172 | // At least page_size_/2 metadata bytes is available. | ||
| 173 | void *GetMetaData(const void *p) { | ||
| 174 | // Too slow: CHECK_EQ(p, GetBlockBegin(p)); | ||
| 175 | if (!IsAligned(reinterpret_cast<uptr>(p), page_size_)) { | ||
| 176 | Printf("%s: bad pointer %p\n", SanitizerToolName, p); | ||
| 177 | CHECK(IsAligned(reinterpret_cast<uptr>(p), page_size_)); | ||
| 178 | } | ||
| 179 | return GetHeader(p) + 1; | ||
| 180 | } | ||
| 181 | |||
| 182 | void *GetBlockBegin(const void *ptr) { | ||
| 183 | uptr p = reinterpret_cast<uptr>(ptr); | ||
| 184 | SpinMutexLock l(&mutex_); | ||
| 185 | uptr nearest_chunk = 0; | ||
| 186 | Header *const *chunks = AddressSpaceView::Load(chunks_, n_chunks_); | ||
| 187 | // Cache-friendly linear search. | ||
| 188 | for (uptr i = 0; i < n_chunks_; i++) { | ||
| 189 | uptr ch = reinterpret_cast<uptr>(chunks[i]); | ||
| 190 | if (p < ch) continue; // p is at left to this chunk, skip it. | ||
| 191 | if (p - ch < p - nearest_chunk) | ||
| 192 | nearest_chunk = ch; | ||
| 193 | } | ||
| 194 | if (!nearest_chunk) | ||
| 195 | return nullptr; | ||
| 196 | const Header *h = | ||
| 197 | AddressSpaceView::Load(reinterpret_cast<Header *>(nearest_chunk)); | ||
| 198 | Header *h_ptr = reinterpret_cast<Header *>(nearest_chunk); | ||
| 199 | CHECK_GE(nearest_chunk, h->map_beg); | ||
| 200 | CHECK_LT(nearest_chunk, h->map_beg + h->map_size); | ||
| 201 | CHECK_LE(nearest_chunk, p); | ||
| 202 | if (h->map_beg + h->map_size <= p) | ||
| 203 | return nullptr; | ||
| 204 | return GetUser(h_ptr); | ||
| 205 | } | ||
| 206 | |||
| 207 | void EnsureSortedChunks() { | ||
| 208 | if (chunks_sorted_) return; | ||
| 209 | Header **chunks = AddressSpaceView::LoadWritable(chunks_, n_chunks_); | ||
| 210 | Sort(reinterpret_cast<uptr *>(chunks), n_chunks_); | ||
| 211 | for (uptr i = 0; i < n_chunks_; i++) | ||
| 212 | AddressSpaceView::LoadWritable(chunks[i])->chunk_idx = i; | ||
| 213 | chunks_sorted_ = true; | ||
| 214 | } | ||
| 215 | |||
| 216 | // This function does the same as GetBlockBegin, but is much faster. | ||
| 217 | // Must be called with the allocator locked. | ||
| 218 | void *GetBlockBeginFastLocked(void *ptr) { | ||
| 219 | mutex_.CheckLocked(); | ||
| 220 | uptr p = reinterpret_cast<uptr>(ptr); | ||
| 221 | uptr n = n_chunks_; | ||
| 222 | if (!n) return nullptr; | ||
| 223 | EnsureSortedChunks(); | ||
| 224 | Header *const *chunks = AddressSpaceView::Load(chunks_, n_chunks_); | ||
| 225 | auto min_mmap_ = reinterpret_cast<uptr>(chunks[0]); | ||
| 226 | auto max_mmap_ = reinterpret_cast<uptr>(chunks[n - 1]) + | ||
| 227 | AddressSpaceView::Load(chunks[n - 1])->map_size; | ||
| 228 | if (p < min_mmap_ || p >= max_mmap_) | ||
| 229 | return nullptr; | ||
| 230 | uptr beg = 0, end = n - 1; | ||
| 231 | // This loop is a log(n) lower_bound. It does not check for the exact match | ||
| 232 | // to avoid expensive cache-thrashing loads. | ||
| 233 | while (end - beg >= 2) { | ||
| 234 | uptr mid = (beg + end) / 2; // Invariant: mid >= beg + 1 | ||
| 235 | if (p < reinterpret_cast<uptr>(chunks[mid])) | ||
| 236 | end = mid - 1; // We are not interested in chunks[mid]. | ||
| 237 | else | ||
| 238 | beg = mid; // chunks[mid] may still be what we want. | ||
| 239 | } | ||
| 240 | |||
| 241 | if (beg < end) { | ||
| 242 | CHECK_EQ(beg + 1, end); | ||
| 243 | // There are 2 chunks left, choose one. | ||
| 244 | if (p >= reinterpret_cast<uptr>(chunks[end])) | ||
| 245 | beg = end; | ||
| 246 | } | ||
| 247 | |||
| 248 | const Header *h = AddressSpaceView::Load(chunks[beg]); | ||
| 249 | Header *h_ptr = chunks[beg]; | ||
| 250 | if (h->map_beg + h->map_size <= p || p < h->map_beg) | ||
| 251 | return nullptr; | ||
| 252 | return GetUser(h_ptr); | ||
| 253 | } | ||
| 254 | |||
| 255 | void PrintStats() { | ||
| 256 | Printf("Stats: LargeMmapAllocator: allocated %zd times, " | ||
| 257 | "remains %zd (%zd K) max %zd M; by size logs: ", | ||
| 258 | stats.n_allocs, stats.n_allocs - stats.n_frees, | ||
| 259 | stats.currently_allocated >> 10, stats.max_allocated >> 20); | ||
| 260 | for (uptr i = 0; i < ARRAY_SIZE(stats.by_size_log); i++) { | ||
| 261 | uptr c = stats.by_size_log[i]; | ||
| 262 | if (!c) continue; | ||
| 263 | Printf("%zd:%zd; ", i, c); | ||
| 264 | } | ||
| 265 | Printf("\n"); | ||
| 266 | } | ||
| 267 | |||
| 268 | // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone | ||
| 269 | // introspection API. | ||
| 270 | void ForceLock() { | ||
| 271 | mutex_.Lock(); | ||
| 272 | } | ||
| 273 | |||
| 274 | void ForceUnlock() { | ||
| 275 | mutex_.Unlock(); | ||
| 276 | } | ||
| 277 | |||
| 278 | // Iterate over all existing chunks. | ||
| 279 | // The allocator must be locked when calling this function. | ||
| 280 | void ForEachChunk(ForEachChunkCallback callback, void *arg) { | ||
| 281 | EnsureSortedChunks(); // Avoid doing the sort while iterating. | ||
| 282 | const Header *const *chunks = AddressSpaceView::Load(chunks_, n_chunks_); | ||
| 283 | for (uptr i = 0; i < n_chunks_; i++) { | ||
| 284 | const Header *t = chunks[i]; | ||
| 285 | callback(reinterpret_cast<uptr>(GetUser(t)), arg); | ||
| 286 | // Consistency check: verify that the array did not change. | ||
| 287 | CHECK_EQ(chunks[i], t); | ||
| 288 | CHECK_EQ(AddressSpaceView::Load(chunks[i])->chunk_idx, i); | ||
| 289 | } | ||
| 290 | } | ||
| 291 | |||
| 292 | private: | ||
| 293 | struct Header { | ||
| 294 | uptr map_beg; | ||
| 295 | uptr map_size; | ||
| 296 | uptr size; | ||
| 297 | uptr chunk_idx; | ||
| 298 | }; | ||
| 299 | |||
| 300 | Header *GetHeader(uptr p) { | ||
| 301 | CHECK(IsAligned(p, page_size_)); | ||
| 302 | return reinterpret_cast<Header*>(p - page_size_); | ||
| 303 | } | ||
| 304 | Header *GetHeader(const void *p) { | ||
| 305 | return GetHeader(reinterpret_cast<uptr>(p)); | ||
| 306 | } | ||
| 307 | |||
| 308 | void *GetUser(const Header *h) { | ||
| 309 | CHECK(IsAligned((uptr)h, page_size_)); | ||
| 310 | return reinterpret_cast<void*>(reinterpret_cast<uptr>(h) + page_size_); | ||
| 311 | } | ||
| 312 | |||
| 313 | uptr RoundUpMapSize(uptr size) { | ||
| 314 | return RoundUpTo(size, page_size_) + page_size_; | ||
| 315 | } | ||
| 316 | |||
| 317 | uptr page_size_; | ||
| 318 | Header **chunks_; | ||
| 319 | PtrArrayT ptr_array_; | ||
| 320 | uptr n_chunks_; | ||
| 321 | bool chunks_sorted_; | ||
| 322 | struct Stats { | ||
| 323 | uptr n_allocs, n_frees, currently_allocated, max_allocated, by_size_log[64]; | ||
| 324 | } stats; | ||
| 325 | StaticSpinMutex mutex_; | ||
| 326 | }; | ||
lib/tsan/sanitizer_common/sanitizer_allocator_size_class_map.h created+241| ... | @@ -0,0 +1,241 @@ | ||
| 1 | //===-- sanitizer_allocator_size_class_map.h --------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Part of the Sanitizer Allocator. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_ALLOCATOR_H | ||
| 13 | #error This file must be included inside sanitizer_allocator.h | ||
| 14 | #endif | ||
| 15 | |||
| 16 | // SizeClassMap maps allocation sizes into size classes and back. | ||
| 17 | // Class 0 always corresponds to size 0. | ||
| 18 | // The other sizes are controlled by the template parameters: | ||
| 19 | // kMinSizeLog: defines the class 1 as 2^kMinSizeLog. | ||
| 20 | // kMaxSizeLog: defines the last class as 2^kMaxSizeLog. | ||
| 21 | // kMidSizeLog: the classes starting from 1 increase with step | ||
| 22 | // 2^kMinSizeLog until 2^kMidSizeLog. | ||
| 23 | // kNumBits: the number of non-zero bits in sizes after 2^kMidSizeLog. | ||
| 24 | // E.g. with kNumBits==3 all size classes after 2^kMidSizeLog | ||
| 25 | // look like 0b1xx0..0, where x is either 0 or 1. | ||
| 26 | // | ||
| 27 | // Example: kNumBits=3, kMidSizeLog=4, kMidSizeLog=8, kMaxSizeLog=17: | ||
| 28 | // | ||
| 29 | // Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16). | ||
| 30 | // Next 4 classes: 256 + i * 64 (i = 1 to 4). | ||
| 31 | // Next 4 classes: 512 + i * 128 (i = 1 to 4). | ||
| 32 | // ... | ||
| 33 | // Next 4 classes: 2^k + i * 2^(k-2) (i = 1 to 4). | ||
| 34 | // Last class corresponds to kMaxSize = 1 << kMaxSizeLog. | ||
| 35 | // | ||
| 36 | // This structure of the size class map gives us: | ||
| 37 | // - Efficient table-free class-to-size and size-to-class functions. | ||
| 38 | // - Difference between two consequent size classes is between 14% and 25% | ||
| 39 | // | ||
| 40 | // This class also gives a hint to a thread-caching allocator about the amount | ||
| 41 | // of chunks that need to be cached per-thread: | ||
| 42 | // - kMaxNumCachedHint is a hint for maximal number of chunks per size class. | ||
| 43 | // The actual number is computed in TransferBatch. | ||
| 44 | // - (1 << kMaxBytesCachedLog) is the maximal number of bytes per size class. | ||
| 45 | // | ||
| 46 | // Part of output of SizeClassMap::Print(): | ||
| 47 | // c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0 | ||
| 48 | // c01 => s: 16 diff: +16 00% l 4 cached: 256 4096; id 1 | ||
| 49 | // c02 => s: 32 diff: +16 100% l 5 cached: 256 8192; id 2 | ||
| 50 | // c03 => s: 48 diff: +16 50% l 5 cached: 256 12288; id 3 | ||
| 51 | // c04 => s: 64 diff: +16 33% l 6 cached: 256 16384; id 4 | ||
| 52 | // c05 => s: 80 diff: +16 25% l 6 cached: 256 20480; id 5 | ||
| 53 | // c06 => s: 96 diff: +16 20% l 6 cached: 256 24576; id 6 | ||
| 54 | // c07 => s: 112 diff: +16 16% l 6 cached: 256 28672; id 7 | ||
| 55 | // | ||
| 56 | // c08 => s: 128 diff: +16 14% l 7 cached: 256 32768; id 8 | ||
| 57 | // c09 => s: 144 diff: +16 12% l 7 cached: 256 36864; id 9 | ||
| 58 | // c10 => s: 160 diff: +16 11% l 7 cached: 256 40960; id 10 | ||
| 59 | // c11 => s: 176 diff: +16 10% l 7 cached: 256 45056; id 11 | ||
| 60 | // c12 => s: 192 diff: +16 09% l 7 cached: 256 49152; id 12 | ||
| 61 | // c13 => s: 208 diff: +16 08% l 7 cached: 256 53248; id 13 | ||
| 62 | // c14 => s: 224 diff: +16 07% l 7 cached: 256 57344; id 14 | ||
| 63 | // c15 => s: 240 diff: +16 07% l 7 cached: 256 61440; id 15 | ||
| 64 | // | ||
| 65 | // c16 => s: 256 diff: +16 06% l 8 cached: 256 65536; id 16 | ||
| 66 | // c17 => s: 320 diff: +64 25% l 8 cached: 204 65280; id 17 | ||
| 67 | // c18 => s: 384 diff: +64 20% l 8 cached: 170 65280; id 18 | ||
| 68 | // c19 => s: 448 diff: +64 16% l 8 cached: 146 65408; id 19 | ||
| 69 | // | ||
| 70 | // c20 => s: 512 diff: +64 14% l 9 cached: 128 65536; id 20 | ||
| 71 | // c21 => s: 640 diff: +128 25% l 9 cached: 102 65280; id 21 | ||
| 72 | // c22 => s: 768 diff: +128 20% l 9 cached: 85 65280; id 22 | ||
| 73 | // c23 => s: 896 diff: +128 16% l 9 cached: 73 65408; id 23 | ||
| 74 | // | ||
| 75 | // c24 => s: 1024 diff: +128 14% l 10 cached: 64 65536; id 24 | ||
| 76 | // c25 => s: 1280 diff: +256 25% l 10 cached: 51 65280; id 25 | ||
| 77 | // c26 => s: 1536 diff: +256 20% l 10 cached: 42 64512; id 26 | ||
| 78 | // c27 => s: 1792 diff: +256 16% l 10 cached: 36 64512; id 27 | ||
| 79 | // | ||
| 80 | // ... | ||
| 81 | // | ||
| 82 | // c48 => s: 65536 diff: +8192 14% l 16 cached: 1 65536; id 48 | ||
| 83 | // c49 => s: 81920 diff: +16384 25% l 16 cached: 1 81920; id 49 | ||
| 84 | // c50 => s: 98304 diff: +16384 20% l 16 cached: 1 98304; id 50 | ||
| 85 | // c51 => s: 114688 diff: +16384 16% l 16 cached: 1 114688; id 51 | ||
| 86 | // | ||
| 87 | // c52 => s: 131072 diff: +16384 14% l 17 cached: 1 131072; id 52 | ||
| 88 | // | ||
| 89 | // | ||
| 90 | // Another example (kNumBits=2): | ||
| 91 | // c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0 | ||
| 92 | // c01 => s: 32 diff: +32 00% l 5 cached: 64 2048; id 1 | ||
| 93 | // c02 => s: 64 diff: +32 100% l 6 cached: 64 4096; id 2 | ||
| 94 | // c03 => s: 96 diff: +32 50% l 6 cached: 64 6144; id 3 | ||
| 95 | // c04 => s: 128 diff: +32 33% l 7 cached: 64 8192; id 4 | ||
| 96 | // c05 => s: 160 diff: +32 25% l 7 cached: 64 10240; id 5 | ||
| 97 | // c06 => s: 192 diff: +32 20% l 7 cached: 64 12288; id 6 | ||
| 98 | // c07 => s: 224 diff: +32 16% l 7 cached: 64 14336; id 7 | ||
| 99 | // c08 => s: 256 diff: +32 14% l 8 cached: 64 16384; id 8 | ||
| 100 | // c09 => s: 384 diff: +128 50% l 8 cached: 42 16128; id 9 | ||
| 101 | // c10 => s: 512 diff: +128 33% l 9 cached: 32 16384; id 10 | ||
| 102 | // c11 => s: 768 diff: +256 50% l 9 cached: 21 16128; id 11 | ||
| 103 | // c12 => s: 1024 diff: +256 33% l 10 cached: 16 16384; id 12 | ||
| 104 | // c13 => s: 1536 diff: +512 50% l 10 cached: 10 15360; id 13 | ||
| 105 | // c14 => s: 2048 diff: +512 33% l 11 cached: 8 16384; id 14 | ||
| 106 | // c15 => s: 3072 diff: +1024 50% l 11 cached: 5 15360; id 15 | ||
| 107 | // c16 => s: 4096 diff: +1024 33% l 12 cached: 4 16384; id 16 | ||
| 108 | // c17 => s: 6144 diff: +2048 50% l 12 cached: 2 12288; id 17 | ||
| 109 | // c18 => s: 8192 diff: +2048 33% l 13 cached: 2 16384; id 18 | ||
| 110 | // c19 => s: 12288 diff: +4096 50% l 13 cached: 1 12288; id 19 | ||
| 111 | // c20 => s: 16384 diff: +4096 33% l 14 cached: 1 16384; id 20 | ||
| 112 | // c21 => s: 24576 diff: +8192 50% l 14 cached: 1 24576; id 21 | ||
| 113 | // c22 => s: 32768 diff: +8192 33% l 15 cached: 1 32768; id 22 | ||
| 114 | // c23 => s: 49152 diff: +16384 50% l 15 cached: 1 49152; id 23 | ||
| 115 | // c24 => s: 65536 diff: +16384 33% l 16 cached: 1 65536; id 24 | ||
| 116 | // c25 => s: 98304 diff: +32768 50% l 16 cached: 1 98304; id 25 | ||
| 117 | // c26 => s: 131072 diff: +32768 33% l 17 cached: 1 131072; id 26 | ||
| 118 | |||
| 119 | template <uptr kNumBits, uptr kMinSizeLog, uptr kMidSizeLog, uptr kMaxSizeLog, | ||
| 120 | uptr kMaxNumCachedHintT, uptr kMaxBytesCachedLog> | ||
| 121 | class SizeClassMap { | ||
| 122 | static const uptr kMinSize = 1 << kMinSizeLog; | ||
| 123 | static const uptr kMidSize = 1 << kMidSizeLog; | ||
| 124 | static const uptr kMidClass = kMidSize / kMinSize; | ||
| 125 | static const uptr S = kNumBits - 1; | ||
| 126 | static const uptr M = (1 << S) - 1; | ||
| 127 | |||
| 128 | public: | ||
| 129 | // kMaxNumCachedHintT is a power of two. It serves as a hint | ||
| 130 | // for the size of TransferBatch, the actual size could be a bit smaller. | ||
| 131 | static const uptr kMaxNumCachedHint = kMaxNumCachedHintT; | ||
| 132 | COMPILER_CHECK((kMaxNumCachedHint & (kMaxNumCachedHint - 1)) == 0); | ||
| 133 | |||
| 134 | static const uptr kMaxSize = 1UL << kMaxSizeLog; | ||
| 135 | static const uptr kNumClasses = | ||
| 136 | kMidClass + ((kMaxSizeLog - kMidSizeLog) << S) + 1 + 1; | ||
| 137 | static const uptr kLargestClassID = kNumClasses - 2; | ||
| 138 | static const uptr kBatchClassID = kNumClasses - 1; | ||
| 139 | COMPILER_CHECK(kNumClasses >= 16 && kNumClasses <= 256); | ||
| 140 | static const uptr kNumClassesRounded = | ||
| 141 | kNumClasses <= 32 ? 32 : | ||
| 142 | kNumClasses <= 64 ? 64 : | ||
| 143 | kNumClasses <= 128 ? 128 : 256; | ||
| 144 | |||
| 145 | static uptr Size(uptr class_id) { | ||
| 146 | // Estimate the result for kBatchClassID because this class does not know | ||
| 147 | // the exact size of TransferBatch. It's OK since we are using the actual | ||
| 148 | // sizeof(TransferBatch) where it matters. | ||
| 149 | if (UNLIKELY(class_id == kBatchClassID)) | ||
| 150 | return kMaxNumCachedHint * sizeof(uptr); | ||
| 151 | if (class_id <= kMidClass) | ||
| 152 | return kMinSize * class_id; | ||
| 153 | class_id -= kMidClass; | ||
| 154 | uptr t = kMidSize << (class_id >> S); | ||
| 155 | return t + (t >> S) * (class_id & M); | ||
| 156 | } | ||
| 157 | |||
| 158 | static uptr ClassID(uptr size) { | ||
| 159 | if (UNLIKELY(size > kMaxSize)) | ||
| 160 | return 0; | ||
| 161 | if (size <= kMidSize) | ||
| 162 | return (size + kMinSize - 1) >> kMinSizeLog; | ||
| 163 | const uptr l = MostSignificantSetBitIndex(size); | ||
| 164 | const uptr hbits = (size >> (l - S)) & M; | ||
| 165 | const uptr lbits = size & ((1U << (l - S)) - 1); | ||
| 166 | const uptr l1 = l - kMidSizeLog; | ||
| 167 | return kMidClass + (l1 << S) + hbits + (lbits > 0); | ||
| 168 | } | ||
| 169 | |||
| 170 | static uptr MaxCachedHint(uptr size) { | ||
| 171 | DCHECK_LE(size, kMaxSize); | ||
| 172 | if (UNLIKELY(size == 0)) | ||
| 173 | return 0; | ||
| 174 | uptr n; | ||
| 175 | // Force a 32-bit division if the template parameters allow for it. | ||
| 176 | if (kMaxBytesCachedLog > 31 || kMaxSizeLog > 31) | ||
| 177 | n = (1UL << kMaxBytesCachedLog) / size; | ||
| 178 | else | ||
| 179 | n = (1U << kMaxBytesCachedLog) / static_cast<u32>(size); | ||
| 180 | return Max<uptr>(1U, Min(kMaxNumCachedHint, n)); | ||
| 181 | } | ||
| 182 | |||
| 183 | static void Print() { | ||
| 184 | uptr prev_s = 0; | ||
| 185 | uptr total_cached = 0; | ||
| 186 | for (uptr i = 0; i < kNumClasses; i++) { | ||
| 187 | uptr s = Size(i); | ||
| 188 | if (s >= kMidSize / 2 && (s & (s - 1)) == 0) | ||
| 189 | Printf("\n"); | ||
| 190 | uptr d = s - prev_s; | ||
| 191 | uptr p = prev_s ? (d * 100 / prev_s) : 0; | ||
| 192 | uptr l = s ? MostSignificantSetBitIndex(s) : 0; | ||
| 193 | uptr cached = MaxCachedHint(s) * s; | ||
| 194 | if (i == kBatchClassID) | ||
| 195 | d = p = l = 0; | ||
| 196 | Printf("c%02zd => s: %zd diff: +%zd %02zd%% l %zd " | ||
| 197 | "cached: %zd %zd; id %zd\n", | ||
| 198 | i, Size(i), d, p, l, MaxCachedHint(s), cached, ClassID(s)); | ||
| 199 | total_cached += cached; | ||
| 200 | prev_s = s; | ||
| 201 | } | ||
| 202 | Printf("Total cached: %zd\n", total_cached); | ||
| 203 | } | ||
| 204 | |||
| 205 | static void Validate() { | ||
| 206 | for (uptr c = 1; c < kNumClasses; c++) { | ||
| 207 | // Printf("Validate: c%zd\n", c); | ||
| 208 | uptr s = Size(c); | ||
| 209 | CHECK_NE(s, 0U); | ||
| 210 | if (c == kBatchClassID) | ||
| 211 | continue; | ||
| 212 | CHECK_EQ(ClassID(s), c); | ||
| 213 | if (c < kLargestClassID) | ||
| 214 | CHECK_EQ(ClassID(s + 1), c + 1); | ||
| 215 | CHECK_EQ(ClassID(s - 1), c); | ||
| 216 | CHECK_GT(Size(c), Size(c - 1)); | ||
| 217 | } | ||
| 218 | CHECK_EQ(ClassID(kMaxSize + 1), 0); | ||
| 219 | |||
| 220 | for (uptr s = 1; s <= kMaxSize; s++) { | ||
| 221 | uptr c = ClassID(s); | ||
| 222 | // Printf("s%zd => c%zd\n", s, c); | ||
| 223 | CHECK_LT(c, kNumClasses); | ||
| 224 | CHECK_GE(Size(c), s); | ||
| 225 | if (c > 0) | ||
| 226 | CHECK_LT(Size(c - 1), s); | ||
| 227 | } | ||
| 228 | } | ||
| 229 | }; | ||
| 230 | |||
| 231 | typedef SizeClassMap<3, 4, 8, 17, 128, 16> DefaultSizeClassMap; | ||
| 232 | typedef SizeClassMap<3, 4, 8, 17, 64, 14> CompactSizeClassMap; | ||
| 233 | typedef SizeClassMap<2, 5, 9, 16, 64, 14> VeryCompactSizeClassMap; | ||
| 234 | |||
| 235 | // The following SizeClassMap only holds a way small number of cached entries, | ||
| 236 | // allowing for denser per-class arrays, smaller memory footprint and usually | ||
| 237 | // better performances in threaded environments. | ||
| 238 | typedef SizeClassMap<3, 4, 8, 17, 8, 10> DenseSizeClassMap; | ||
| 239 | // Similar to VeryCompact map above, this one has a small number of different | ||
| 240 | // size classes, and also reduced thread-local caches. | ||
| 241 | typedef SizeClassMap<2, 5, 9, 16, 8, 10> VeryDenseSizeClassMap; | ||
lib/tsan/sanitizer_common/sanitizer_allocator_stats.h created+106| ... | @@ -0,0 +1,106 @@ | ||
| 1 | //===-- sanitizer_allocator_stats.h -----------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Part of the Sanitizer Allocator. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_ALLOCATOR_H | ||
| 13 | #error This file must be included inside sanitizer_allocator.h | ||
| 14 | #endif | ||
| 15 | |||
| 16 | // Memory allocator statistics | ||
| 17 | enum AllocatorStat { | ||
| 18 | AllocatorStatAllocated, | ||
| 19 | AllocatorStatMapped, | ||
| 20 | AllocatorStatCount | ||
| 21 | }; | ||
| 22 | |||
| 23 | typedef uptr AllocatorStatCounters[AllocatorStatCount]; | ||
| 24 | |||
| 25 | // Per-thread stats, live in per-thread cache. | ||
| 26 | class AllocatorStats { | ||
| 27 | public: | ||
| 28 | void Init() { | ||
| 29 | internal_memset(this, 0, sizeof(*this)); | ||
| 30 | } | ||
| 31 | void InitLinkerInitialized() {} | ||
| 32 | |||
| 33 | void Add(AllocatorStat i, uptr v) { | ||
| 34 | v += atomic_load(&stats_[i], memory_order_relaxed); | ||
| 35 | atomic_store(&stats_[i], v, memory_order_relaxed); | ||
| 36 | } | ||
| 37 | |||
| 38 | void Sub(AllocatorStat i, uptr v) { | ||
| 39 | v = atomic_load(&stats_[i], memory_order_relaxed) - v; | ||
| 40 | atomic_store(&stats_[i], v, memory_order_relaxed); | ||
| 41 | } | ||
| 42 | |||
| 43 | void Set(AllocatorStat i, uptr v) { | ||
| 44 | atomic_store(&stats_[i], v, memory_order_relaxed); | ||
| 45 | } | ||
| 46 | |||
| 47 | uptr Get(AllocatorStat i) const { | ||
| 48 | return atomic_load(&stats_[i], memory_order_relaxed); | ||
| 49 | } | ||
| 50 | |||
| 51 | private: | ||
| 52 | friend class AllocatorGlobalStats; | ||
| 53 | AllocatorStats *next_; | ||
| 54 | AllocatorStats *prev_; | ||
| 55 | atomic_uintptr_t stats_[AllocatorStatCount]; | ||
| 56 | }; | ||
| 57 | |||
| 58 | // Global stats, used for aggregation and querying. | ||
| 59 | class AllocatorGlobalStats : public AllocatorStats { | ||
| 60 | public: | ||
| 61 | void InitLinkerInitialized() { | ||
| 62 | next_ = this; | ||
| 63 | prev_ = this; | ||
| 64 | } | ||
| 65 | void Init() { | ||
| 66 | internal_memset(this, 0, sizeof(*this)); | ||
| 67 | InitLinkerInitialized(); | ||
| 68 | } | ||
| 69 | |||
| 70 | void Register(AllocatorStats *s) { | ||
| 71 | SpinMutexLock l(&mu_); | ||
| 72 | s->next_ = next_; | ||
| 73 | s->prev_ = this; | ||
| 74 | next_->prev_ = s; | ||
| 75 | next_ = s; | ||
| 76 | } | ||
| 77 | |||
| 78 | void Unregister(AllocatorStats *s) { | ||
| 79 | SpinMutexLock l(&mu_); | ||
| 80 | s->prev_->next_ = s->next_; | ||
| 81 | s->next_->prev_ = s->prev_; | ||
| 82 | for (int i = 0; i < AllocatorStatCount; i++) | ||
| 83 | Add(AllocatorStat(i), s->Get(AllocatorStat(i))); | ||
| 84 | } | ||
| 85 | |||
| 86 | void Get(AllocatorStatCounters s) const { | ||
| 87 | internal_memset(s, 0, AllocatorStatCount * sizeof(uptr)); | ||
| 88 | SpinMutexLock l(&mu_); | ||
| 89 | const AllocatorStats *stats = this; | ||
| 90 | for (;;) { | ||
| 91 | for (int i = 0; i < AllocatorStatCount; i++) | ||
| 92 | s[i] += stats->Get(AllocatorStat(i)); | ||
| 93 | stats = stats->next_; | ||
| 94 | if (stats == this) | ||
| 95 | break; | ||
| 96 | } | ||
| 97 | // All stats must be non-negative. | ||
| 98 | for (int i = 0; i < AllocatorStatCount; i++) | ||
| 99 | s[i] = ((sptr)s[i]) >= 0 ? s[i] : 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | private: | ||
| 103 | mutable StaticSpinMutex mu_; | ||
| 104 | }; | ||
| 105 | |||
| 106 | |||
lib/tsan/sanitizer_common/sanitizer_asm.h created+68| ... | @@ -0,0 +1,68 @@ | ||
| 1 | //===-- sanitizer_asm.h -----------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Various support for assemebler. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | // Some toolchains do not support .cfi asm directives, so we have to hide | ||
| 14 | // them inside macros. | ||
| 15 | #if defined(__clang__) || \ | ||
| 16 | (defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)) | ||
| 17 | // GCC defined __GCC_HAVE_DWARF2_CFI_ASM if it supports CFI. | ||
| 18 | // Clang seems to support CFI by default (or not?). | ||
| 19 | // We need two versions of macros: for inline asm and standalone asm files. | ||
| 20 | # define CFI_INL_ADJUST_CFA_OFFSET(n) ".cfi_adjust_cfa_offset " #n ";" | ||
| 21 | |||
| 22 | # define CFI_STARTPROC .cfi_startproc | ||
| 23 | # define CFI_ENDPROC .cfi_endproc | ||
| 24 | # define CFI_ADJUST_CFA_OFFSET(n) .cfi_adjust_cfa_offset n | ||
| 25 | # define CFI_DEF_CFA_OFFSET(n) .cfi_def_cfa_offset n | ||
| 26 | # define CFI_REL_OFFSET(reg, n) .cfi_rel_offset reg, n | ||
| 27 | # define CFI_OFFSET(reg, n) .cfi_offset reg, n | ||
| 28 | # define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg | ||
| 29 | # define CFI_DEF_CFA(reg, n) .cfi_def_cfa reg, n | ||
| 30 | # define CFI_RESTORE(reg) .cfi_restore reg | ||
| 31 | |||
| 32 | #else // No CFI | ||
| 33 | # define CFI_INL_ADJUST_CFA_OFFSET(n) | ||
| 34 | # define CFI_STARTPROC | ||
| 35 | # define CFI_ENDPROC | ||
| 36 | # define CFI_ADJUST_CFA_OFFSET(n) | ||
| 37 | # define CFI_DEF_CFA_OFFSET(n) | ||
| 38 | # define CFI_REL_OFFSET(reg, n) | ||
| 39 | # define CFI_OFFSET(reg, n) | ||
| 40 | # define CFI_DEF_CFA_REGISTER(reg) | ||
| 41 | # define CFI_DEF_CFA(reg, n) | ||
| 42 | # define CFI_RESTORE(reg) | ||
| 43 | #endif | ||
| 44 | |||
| 45 | #if !defined(__APPLE__) | ||
| 46 | # define ASM_HIDDEN(symbol) .hidden symbol | ||
| 47 | # define ASM_TYPE_FUNCTION(symbol) .type symbol, %function | ||
| 48 | # define ASM_SIZE(symbol) .size symbol, .-symbol | ||
| 49 | # define ASM_SYMBOL(symbol) symbol | ||
| 50 | # define ASM_SYMBOL_INTERCEPTOR(symbol) symbol | ||
| 51 | # define ASM_WRAPPER_NAME(symbol) __interceptor_##symbol | ||
| 52 | #else | ||
| 53 | # define ASM_HIDDEN(symbol) | ||
| 54 | # define ASM_TYPE_FUNCTION(symbol) | ||
| 55 | # define ASM_SIZE(symbol) | ||
| 56 | # define ASM_SYMBOL(symbol) _##symbol | ||
| 57 | # define ASM_SYMBOL_INTERCEPTOR(symbol) _wrap_##symbol | ||
| 58 | # define ASM_WRAPPER_NAME(symbol) __interceptor_##symbol | ||
| 59 | #endif | ||
| 60 | |||
| 61 | #if defined(__ELF__) && (defined(__GNU__) || defined(__FreeBSD__) || \ | ||
| 62 | defined(__Fuchsia__) || defined(__linux__)) | ||
| 63 | // clang-format off | ||
| 64 | #define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits // NOLINT | ||
| 65 | // clang-format on | ||
| 66 | #else | ||
| 67 | #define NO_EXEC_STACK_DIRECTIVE | ||
| 68 | #endif | ||
lib/tsan/sanitizer_common/sanitizer_atomic.h created+86| ... | @@ -0,0 +1,86 @@ | ||
| 1 | //===-- sanitizer_atomic.h --------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer/AddressSanitizer runtime. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef SANITIZER_ATOMIC_H | ||
| 14 | #define SANITIZER_ATOMIC_H | ||
| 15 | |||
| 16 | #include "sanitizer_internal_defs.h" | ||
| 17 | |||
| 18 | namespace __sanitizer { | ||
| 19 | |||
| 20 | enum memory_order { | ||
| 21 | memory_order_relaxed = 1 << 0, | ||
| 22 | memory_order_consume = 1 << 1, | ||
| 23 | memory_order_acquire = 1 << 2, | ||
| 24 | memory_order_release = 1 << 3, | ||
| 25 | memory_order_acq_rel = 1 << 4, | ||
| 26 | memory_order_seq_cst = 1 << 5 | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct atomic_uint8_t { | ||
| 30 | typedef u8 Type; | ||
| 31 | volatile Type val_dont_use; | ||
| 32 | }; | ||
| 33 | |||
| 34 | struct atomic_uint16_t { | ||
| 35 | typedef u16 Type; | ||
| 36 | volatile Type val_dont_use; | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct atomic_sint32_t { | ||
| 40 | typedef s32 Type; | ||
| 41 | volatile Type val_dont_use; | ||
| 42 | }; | ||
| 43 | |||
| 44 | struct atomic_uint32_t { | ||
| 45 | typedef u32 Type; | ||
| 46 | volatile Type val_dont_use; | ||
| 47 | }; | ||
| 48 | |||
| 49 | struct atomic_uint64_t { | ||
| 50 | typedef u64 Type; | ||
| 51 | // On 32-bit platforms u64 is not necessary aligned on 8 bytes. | ||
| 52 | volatile ALIGNED(8) Type val_dont_use; | ||
| 53 | }; | ||
| 54 | |||
| 55 | struct atomic_uintptr_t { | ||
| 56 | typedef uptr Type; | ||
| 57 | volatile Type val_dont_use; | ||
| 58 | }; | ||
| 59 | |||
| 60 | } // namespace __sanitizer | ||
| 61 | |||
| 62 | #if defined(__clang__) || defined(__GNUC__) | ||
| 63 | # include "sanitizer_atomic_clang.h" | ||
| 64 | #elif defined(_MSC_VER) | ||
| 65 | # include "sanitizer_atomic_msvc.h" | ||
| 66 | #else | ||
| 67 | # error "Unsupported compiler" | ||
| 68 | #endif | ||
| 69 | |||
| 70 | namespace __sanitizer { | ||
| 71 | |||
| 72 | // Clutter-reducing helpers. | ||
| 73 | |||
| 74 | template<typename T> | ||
| 75 | INLINE typename T::Type atomic_load_relaxed(const volatile T *a) { | ||
| 76 | return atomic_load(a, memory_order_relaxed); | ||
| 77 | } | ||
| 78 | |||
| 79 | template<typename T> | ||
| 80 | INLINE void atomic_store_relaxed(volatile T *a, typename T::Type v) { | ||
| 81 | atomic_store(a, v, memory_order_relaxed); | ||
| 82 | } | ||
| 83 | |||
| 84 | } // namespace __sanitizer | ||
| 85 | |||
| 86 | #endif // SANITIZER_ATOMIC_H | ||
lib/tsan/sanitizer_common/sanitizer_atomic_clang.h created+105| ... | @@ -0,0 +1,105 @@ | ||
| 1 | //===-- sanitizer_atomic_clang.h --------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer/AddressSanitizer runtime. | ||
| 10 | // Not intended for direct inclusion. Include sanitizer_atomic.h. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_ATOMIC_CLANG_H | ||
| 15 | #define SANITIZER_ATOMIC_CLANG_H | ||
| 16 | |||
| 17 | #if defined(__i386__) || defined(__x86_64__) | ||
| 18 | # include "sanitizer_atomic_clang_x86.h" | ||
| 19 | #else | ||
| 20 | # include "sanitizer_atomic_clang_other.h" | ||
| 21 | #endif | ||
| 22 | |||
| 23 | namespace __sanitizer { | ||
| 24 | |||
| 25 | // We would like to just use compiler builtin atomic operations | ||
| 26 | // for loads and stores, but they are mostly broken in clang: | ||
| 27 | // - they lead to vastly inefficient code generation | ||
| 28 | // (http://llvm.org/bugs/show_bug.cgi?id=17281) | ||
| 29 | // - 64-bit atomic operations are not implemented on x86_32 | ||
| 30 | // (http://llvm.org/bugs/show_bug.cgi?id=15034) | ||
| 31 | // - they are not implemented on ARM | ||
| 32 | // error: undefined reference to '__atomic_load_4' | ||
| 33 | |||
| 34 | // See http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html | ||
| 35 | // for mappings of the memory model to different processors. | ||
| 36 | |||
| 37 | INLINE void atomic_signal_fence(memory_order) { | ||
| 38 | __asm__ __volatile__("" ::: "memory"); | ||
| 39 | } | ||
| 40 | |||
| 41 | INLINE void atomic_thread_fence(memory_order) { | ||
| 42 | __sync_synchronize(); | ||
| 43 | } | ||
| 44 | |||
| 45 | template<typename T> | ||
| 46 | INLINE typename T::Type atomic_fetch_add(volatile T *a, | ||
| 47 | typename T::Type v, memory_order mo) { | ||
| 48 | (void)mo; | ||
| 49 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 50 | return __sync_fetch_and_add(&a->val_dont_use, v); | ||
| 51 | } | ||
| 52 | |||
| 53 | template<typename T> | ||
| 54 | INLINE typename T::Type atomic_fetch_sub(volatile T *a, | ||
| 55 | typename T::Type v, memory_order mo) { | ||
| 56 | (void)mo; | ||
| 57 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 58 | return __sync_fetch_and_add(&a->val_dont_use, -v); | ||
| 59 | } | ||
| 60 | |||
| 61 | template<typename T> | ||
| 62 | INLINE typename T::Type atomic_exchange(volatile T *a, | ||
| 63 | typename T::Type v, memory_order mo) { | ||
| 64 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 65 | if (mo & (memory_order_release | memory_order_acq_rel | memory_order_seq_cst)) | ||
| 66 | __sync_synchronize(); | ||
| 67 | v = __sync_lock_test_and_set(&a->val_dont_use, v); | ||
| 68 | if (mo == memory_order_seq_cst) | ||
| 69 | __sync_synchronize(); | ||
| 70 | return v; | ||
| 71 | } | ||
| 72 | |||
| 73 | template <typename T> | ||
| 74 | INLINE bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp, | ||
| 75 | typename T::Type xchg, | ||
| 76 | memory_order mo) { | ||
| 77 | typedef typename T::Type Type; | ||
| 78 | Type cmpv = *cmp; | ||
| 79 | Type prev; | ||
| 80 | prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg); | ||
| 81 | if (prev == cmpv) return true; | ||
| 82 | *cmp = prev; | ||
| 83 | return false; | ||
| 84 | } | ||
| 85 | |||
| 86 | template<typename T> | ||
| 87 | INLINE bool atomic_compare_exchange_weak(volatile T *a, | ||
| 88 | typename T::Type *cmp, | ||
| 89 | typename T::Type xchg, | ||
| 90 | memory_order mo) { | ||
| 91 | return atomic_compare_exchange_strong(a, cmp, xchg, mo); | ||
| 92 | } | ||
| 93 | |||
| 94 | } // namespace __sanitizer | ||
| 95 | |||
| 96 | // This include provides explicit template instantiations for atomic_uint64_t | ||
| 97 | // on MIPS32, which does not directly support 8 byte atomics. It has to | ||
| 98 | // proceed the template definitions above. | ||
| 99 | #if defined(_MIPS_SIM) && defined(_ABIO32) | ||
| 100 | #include "sanitizer_atomic_clang_mips.h" | ||
| 101 | #endif | ||
| 102 | |||
| 103 | #undef ATOMIC_ORDER | ||
| 104 | |||
| 105 | #endif // SANITIZER_ATOMIC_CLANG_H | ||
lib/tsan/sanitizer_common/sanitizer_atomic_clang_mips.h created+117| ... | @@ -0,0 +1,117 @@ | ||
| 1 | //===-- sanitizer_atomic_clang_mips.h ---------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer/AddressSanitizer runtime. | ||
| 10 | // Not intended for direct inclusion. Include sanitizer_atomic.h. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_ATOMIC_CLANG_MIPS_H | ||
| 15 | #define SANITIZER_ATOMIC_CLANG_MIPS_H | ||
| 16 | |||
| 17 | namespace __sanitizer { | ||
| 18 | |||
| 19 | // MIPS32 does not support atomics > 4 bytes. To address this lack of | ||
| 20 | // functionality, the sanitizer library provides helper methods which use an | ||
| 21 | // internal spin lock mechanism to emulate atomic oprations when the size is | ||
| 22 | // 8 bytes. | ||
| 23 | static void __spin_lock(volatile int *lock) { | ||
| 24 | while (__sync_lock_test_and_set(lock, 1)) | ||
| 25 | while (*lock) { | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | static void __spin_unlock(volatile int *lock) { __sync_lock_release(lock); } | ||
| 30 | |||
| 31 | // Make sure the lock is on its own cache line to prevent false sharing. | ||
| 32 | // Put it inside a struct that is aligned and padded to the typical MIPS | ||
| 33 | // cacheline which is 32 bytes. | ||
| 34 | static struct { | ||
| 35 | int lock; | ||
| 36 | char pad[32 - sizeof(int)]; | ||
| 37 | } __attribute__((aligned(32))) lock = {0, {0}}; | ||
| 38 | |||
| 39 | template <> | ||
| 40 | INLINE atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr, | ||
| 41 | atomic_uint64_t::Type val, | ||
| 42 | memory_order mo) { | ||
| 43 | DCHECK(mo & | ||
| 44 | (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst)); | ||
| 45 | DCHECK(!((uptr)ptr % sizeof(*ptr))); | ||
| 46 | |||
| 47 | atomic_uint64_t::Type ret; | ||
| 48 | |||
| 49 | __spin_lock(&lock.lock); | ||
| 50 | ret = *(const_cast<atomic_uint64_t::Type volatile *>(&ptr->val_dont_use)); | ||
| 51 | ptr->val_dont_use = ret + val; | ||
| 52 | __spin_unlock(&lock.lock); | ||
| 53 | |||
| 54 | return ret; | ||
| 55 | } | ||
| 56 | |||
| 57 | template <> | ||
| 58 | INLINE atomic_uint64_t::Type atomic_fetch_sub(volatile atomic_uint64_t *ptr, | ||
| 59 | atomic_uint64_t::Type val, | ||
| 60 | memory_order mo) { | ||
| 61 | return atomic_fetch_add(ptr, -val, mo); | ||
| 62 | } | ||
| 63 | |||
| 64 | template <> | ||
| 65 | INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr, | ||
| 66 | atomic_uint64_t::Type *cmp, | ||
| 67 | atomic_uint64_t::Type xchg, | ||
| 68 | memory_order mo) { | ||
| 69 | DCHECK(mo & | ||
| 70 | (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst)); | ||
| 71 | DCHECK(!((uptr)ptr % sizeof(*ptr))); | ||
| 72 | |||
| 73 | typedef atomic_uint64_t::Type Type; | ||
| 74 | Type cmpv = *cmp; | ||
| 75 | Type prev; | ||
| 76 | bool ret = false; | ||
| 77 | |||
| 78 | __spin_lock(&lock.lock); | ||
| 79 | prev = *(const_cast<Type volatile *>(&ptr->val_dont_use)); | ||
| 80 | if (prev == cmpv) { | ||
| 81 | ret = true; | ||
| 82 | ptr->val_dont_use = xchg; | ||
| 83 | } | ||
| 84 | __spin_unlock(&lock.lock); | ||
| 85 | |||
| 86 | return ret; | ||
| 87 | } | ||
| 88 | |||
| 89 | template <> | ||
| 90 | INLINE atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr, | ||
| 91 | memory_order mo) { | ||
| 92 | DCHECK(mo & | ||
| 93 | (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst)); | ||
| 94 | DCHECK(!((uptr)ptr % sizeof(*ptr))); | ||
| 95 | |||
| 96 | atomic_uint64_t::Type zero = 0; | ||
| 97 | volatile atomic_uint64_t *Newptr = | ||
| 98 | const_cast<volatile atomic_uint64_t *>(ptr); | ||
| 99 | return atomic_fetch_add(Newptr, zero, mo); | ||
| 100 | } | ||
| 101 | |||
| 102 | template <> | ||
| 103 | INLINE void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v, | ||
| 104 | memory_order mo) { | ||
| 105 | DCHECK(mo & | ||
| 106 | (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst)); | ||
| 107 | DCHECK(!((uptr)ptr % sizeof(*ptr))); | ||
| 108 | |||
| 109 | __spin_lock(&lock.lock); | ||
| 110 | ptr->val_dont_use = v; | ||
| 111 | __spin_unlock(&lock.lock); | ||
| 112 | } | ||
| 113 | |||
| 114 | } // namespace __sanitizer | ||
| 115 | |||
| 116 | #endif // SANITIZER_ATOMIC_CLANG_MIPS_H | ||
| 117 | |||
lib/tsan/sanitizer_common/sanitizer_atomic_clang_other.h created+97| ... | @@ -0,0 +1,97 @@ | ||
| 1 | //===-- sanitizer_atomic_clang_other.h --------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer/AddressSanitizer runtime. | ||
| 10 | // Not intended for direct inclusion. Include sanitizer_atomic.h. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_ATOMIC_CLANG_OTHER_H | ||
| 15 | #define SANITIZER_ATOMIC_CLANG_OTHER_H | ||
| 16 | |||
| 17 | namespace __sanitizer { | ||
| 18 | |||
| 19 | |||
| 20 | INLINE void proc_yield(int cnt) { | ||
| 21 | __asm__ __volatile__("" ::: "memory"); | ||
| 22 | } | ||
| 23 | |||
| 24 | template<typename T> | ||
| 25 | INLINE typename T::Type atomic_load( | ||
| 26 | const volatile T *a, memory_order mo) { | ||
| 27 | DCHECK(mo & (memory_order_relaxed | memory_order_consume | ||
| 28 | | memory_order_acquire | memory_order_seq_cst)); | ||
| 29 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 30 | typename T::Type v; | ||
| 31 | |||
| 32 | if (sizeof(*a) < 8 || sizeof(void*) == 8) { | ||
| 33 | // Assume that aligned loads are atomic. | ||
| 34 | if (mo == memory_order_relaxed) { | ||
| 35 | v = a->val_dont_use; | ||
| 36 | } else if (mo == memory_order_consume) { | ||
| 37 | // Assume that processor respects data dependencies | ||
| 38 | // (and that compiler won't break them). | ||
| 39 | __asm__ __volatile__("" ::: "memory"); | ||
| 40 | v = a->val_dont_use; | ||
| 41 | __asm__ __volatile__("" ::: "memory"); | ||
| 42 | } else if (mo == memory_order_acquire) { | ||
| 43 | __asm__ __volatile__("" ::: "memory"); | ||
| 44 | v = a->val_dont_use; | ||
| 45 | __sync_synchronize(); | ||
| 46 | } else { // seq_cst | ||
| 47 | // E.g. on POWER we need a hw fence even before the store. | ||
| 48 | __sync_synchronize(); | ||
| 49 | v = a->val_dont_use; | ||
| 50 | __sync_synchronize(); | ||
| 51 | } | ||
| 52 | } else { | ||
| 53 | // 64-bit load on 32-bit platform. | ||
| 54 | // Gross, but simple and reliable. | ||
| 55 | // Assume that it is not in read-only memory. | ||
| 56 | v = __sync_fetch_and_add( | ||
| 57 | const_cast<typename T::Type volatile *>(&a->val_dont_use), 0); | ||
| 58 | } | ||
| 59 | return v; | ||
| 60 | } | ||
| 61 | |||
| 62 | template<typename T> | ||
| 63 | INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { | ||
| 64 | DCHECK(mo & (memory_order_relaxed | memory_order_release | ||
| 65 | | memory_order_seq_cst)); | ||
| 66 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 67 | |||
| 68 | if (sizeof(*a) < 8 || sizeof(void*) == 8) { | ||
| 69 | // Assume that aligned loads are atomic. | ||
| 70 | if (mo == memory_order_relaxed) { | ||
| 71 | a->val_dont_use = v; | ||
| 72 | } else if (mo == memory_order_release) { | ||
| 73 | __sync_synchronize(); | ||
| 74 | a->val_dont_use = v; | ||
| 75 | __asm__ __volatile__("" ::: "memory"); | ||
| 76 | } else { // seq_cst | ||
| 77 | __sync_synchronize(); | ||
| 78 | a->val_dont_use = v; | ||
| 79 | __sync_synchronize(); | ||
| 80 | } | ||
| 81 | } else { | ||
| 82 | // 64-bit store on 32-bit platform. | ||
| 83 | // Gross, but simple and reliable. | ||
| 84 | typename T::Type cmp = a->val_dont_use; | ||
| 85 | typename T::Type cur; | ||
| 86 | for (;;) { | ||
| 87 | cur = __sync_val_compare_and_swap(&a->val_dont_use, cmp, v); | ||
| 88 | if (cur == cmp || cur == v) | ||
| 89 | break; | ||
| 90 | cmp = cur; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | } // namespace __sanitizer | ||
| 96 | |||
| 97 | #endif // #ifndef SANITIZER_ATOMIC_CLANG_OTHER_H | ||
lib/tsan/sanitizer_common/sanitizer_atomic_clang_x86.h created+113| ... | @@ -0,0 +1,113 @@ | ||
| 1 | //===-- sanitizer_atomic_clang_x86.h ----------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer/AddressSanitizer runtime. | ||
| 10 | // Not intended for direct inclusion. Include sanitizer_atomic.h. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_ATOMIC_CLANG_X86_H | ||
| 15 | #define SANITIZER_ATOMIC_CLANG_X86_H | ||
| 16 | |||
| 17 | namespace __sanitizer { | ||
| 18 | |||
| 19 | INLINE void proc_yield(int cnt) { | ||
| 20 | __asm__ __volatile__("" ::: "memory"); | ||
| 21 | for (int i = 0; i < cnt; i++) | ||
| 22 | __asm__ __volatile__("pause"); | ||
| 23 | __asm__ __volatile__("" ::: "memory"); | ||
| 24 | } | ||
| 25 | |||
| 26 | template<typename T> | ||
| 27 | INLINE typename T::Type atomic_load( | ||
| 28 | const volatile T *a, memory_order mo) { | ||
| 29 | DCHECK(mo & (memory_order_relaxed | memory_order_consume | ||
| 30 | | memory_order_acquire | memory_order_seq_cst)); | ||
| 31 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 32 | typename T::Type v; | ||
| 33 | |||
| 34 | if (sizeof(*a) < 8 || sizeof(void*) == 8) { | ||
| 35 | // Assume that aligned loads are atomic. | ||
| 36 | if (mo == memory_order_relaxed) { | ||
| 37 | v = a->val_dont_use; | ||
| 38 | } else if (mo == memory_order_consume) { | ||
| 39 | // Assume that processor respects data dependencies | ||
| 40 | // (and that compiler won't break them). | ||
| 41 | __asm__ __volatile__("" ::: "memory"); | ||
| 42 | v = a->val_dont_use; | ||
| 43 | __asm__ __volatile__("" ::: "memory"); | ||
| 44 | } else if (mo == memory_order_acquire) { | ||
| 45 | __asm__ __volatile__("" ::: "memory"); | ||
| 46 | v = a->val_dont_use; | ||
| 47 | // On x86 loads are implicitly acquire. | ||
| 48 | __asm__ __volatile__("" ::: "memory"); | ||
| 49 | } else { // seq_cst | ||
| 50 | // On x86 plain MOV is enough for seq_cst store. | ||
| 51 | __asm__ __volatile__("" ::: "memory"); | ||
| 52 | v = a->val_dont_use; | ||
| 53 | __asm__ __volatile__("" ::: "memory"); | ||
| 54 | } | ||
| 55 | } else { | ||
| 56 | // 64-bit load on 32-bit platform. | ||
| 57 | __asm__ __volatile__( | ||
| 58 | "movq %1, %%mm0;" // Use mmx reg for 64-bit atomic moves | ||
| 59 | "movq %%mm0, %0;" // (ptr could be read-only) | ||
| 60 | "emms;" // Empty mmx state/Reset FP regs | ||
| 61 | : "=m" (v) | ||
| 62 | : "m" (a->val_dont_use) | ||
| 63 | : // mark the mmx registers as clobbered | ||
| 64 | #ifdef __MMX__ | ||
| 65 | "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", | ||
| 66 | #endif // #ifdef __MMX__ | ||
| 67 | "memory"); | ||
| 68 | } | ||
| 69 | return v; | ||
| 70 | } | ||
| 71 | |||
| 72 | template<typename T> | ||
| 73 | INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { | ||
| 74 | DCHECK(mo & (memory_order_relaxed | memory_order_release | ||
| 75 | | memory_order_seq_cst)); | ||
| 76 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 77 | |||
| 78 | if (sizeof(*a) < 8 || sizeof(void*) == 8) { | ||
| 79 | // Assume that aligned loads are atomic. | ||
| 80 | if (mo == memory_order_relaxed) { | ||
| 81 | a->val_dont_use = v; | ||
| 82 | } else if (mo == memory_order_release) { | ||
| 83 | // On x86 stores are implicitly release. | ||
| 84 | __asm__ __volatile__("" ::: "memory"); | ||
| 85 | a->val_dont_use = v; | ||
| 86 | __asm__ __volatile__("" ::: "memory"); | ||
| 87 | } else { // seq_cst | ||
| 88 | // On x86 stores are implicitly release. | ||
| 89 | __asm__ __volatile__("" ::: "memory"); | ||
| 90 | a->val_dont_use = v; | ||
| 91 | __sync_synchronize(); | ||
| 92 | } | ||
| 93 | } else { | ||
| 94 | // 64-bit store on 32-bit platform. | ||
| 95 | __asm__ __volatile__( | ||
| 96 | "movq %1, %%mm0;" // Use mmx reg for 64-bit atomic moves | ||
| 97 | "movq %%mm0, %0;" | ||
| 98 | "emms;" // Empty mmx state/Reset FP regs | ||
| 99 | : "=m" (a->val_dont_use) | ||
| 100 | : "m" (v) | ||
| 101 | : // mark the mmx registers as clobbered | ||
| 102 | #ifdef __MMX__ | ||
| 103 | "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", | ||
| 104 | #endif // #ifdef __MMX__ | ||
| 105 | "memory"); | ||
| 106 | if (mo == memory_order_seq_cst) | ||
| 107 | __sync_synchronize(); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | } // namespace __sanitizer | ||
| 112 | |||
| 113 | #endif // #ifndef SANITIZER_ATOMIC_CLANG_X86_H | ||
lib/tsan/sanitizer_common/sanitizer_atomic_msvc.h created+256| ... | @@ -0,0 +1,256 @@ | ||
| 1 | //===-- sanitizer_atomic_msvc.h ---------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer/AddressSanitizer runtime. | ||
| 10 | // Not intended for direct inclusion. Include sanitizer_atomic.h. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_ATOMIC_MSVC_H | ||
| 15 | #define SANITIZER_ATOMIC_MSVC_H | ||
| 16 | |||
| 17 | extern "C" void _ReadWriteBarrier(); | ||
| 18 | #pragma intrinsic(_ReadWriteBarrier) | ||
| 19 | extern "C" void _mm_mfence(); | ||
| 20 | #pragma intrinsic(_mm_mfence) | ||
| 21 | extern "C" void _mm_pause(); | ||
| 22 | #pragma intrinsic(_mm_pause) | ||
| 23 | extern "C" char _InterlockedExchange8(char volatile *Addend, char Value); | ||
| 24 | #pragma intrinsic(_InterlockedExchange8) | ||
| 25 | extern "C" short _InterlockedExchange16(short volatile *Addend, short Value); | ||
| 26 | #pragma intrinsic(_InterlockedExchange16) | ||
| 27 | extern "C" long _InterlockedExchange(long volatile *Addend, long Value); | ||
| 28 | #pragma intrinsic(_InterlockedExchange) | ||
| 29 | extern "C" long _InterlockedExchangeAdd(long volatile *Addend, long Value); | ||
| 30 | #pragma intrinsic(_InterlockedExchangeAdd) | ||
| 31 | extern "C" char _InterlockedCompareExchange8(char volatile *Destination, | ||
| 32 | char Exchange, char Comparand); | ||
| 33 | #pragma intrinsic(_InterlockedCompareExchange8) | ||
| 34 | extern "C" short _InterlockedCompareExchange16(short volatile *Destination, | ||
| 35 | short Exchange, short Comparand); | ||
| 36 | #pragma intrinsic(_InterlockedCompareExchange16) | ||
| 37 | extern "C" long long _InterlockedCompareExchange64( | ||
| 38 | long long volatile *Destination, long long Exchange, long long Comparand); | ||
| 39 | #pragma intrinsic(_InterlockedCompareExchange64) | ||
| 40 | extern "C" void *_InterlockedCompareExchangePointer( | ||
| 41 | void *volatile *Destination, | ||
| 42 | void *Exchange, void *Comparand); | ||
| 43 | #pragma intrinsic(_InterlockedCompareExchangePointer) | ||
| 44 | extern "C" long __cdecl _InterlockedCompareExchange(long volatile *Destination, | ||
| 45 | long Exchange, | ||
| 46 | long Comparand); | ||
| 47 | #pragma intrinsic(_InterlockedCompareExchange) | ||
| 48 | |||
| 49 | #ifdef _WIN64 | ||
| 50 | extern "C" long long _InterlockedExchangeAdd64(long long volatile *Addend, | ||
| 51 | long long Value); | ||
| 52 | #pragma intrinsic(_InterlockedExchangeAdd64) | ||
| 53 | #endif | ||
| 54 | |||
| 55 | namespace __sanitizer { | ||
| 56 | |||
| 57 | INLINE void atomic_signal_fence(memory_order) { | ||
| 58 | _ReadWriteBarrier(); | ||
| 59 | } | ||
| 60 | |||
| 61 | INLINE void atomic_thread_fence(memory_order) { | ||
| 62 | _mm_mfence(); | ||
| 63 | } | ||
| 64 | |||
| 65 | INLINE void proc_yield(int cnt) { | ||
| 66 | for (int i = 0; i < cnt; i++) | ||
| 67 | _mm_pause(); | ||
| 68 | } | ||
| 69 | |||
| 70 | template<typename T> | ||
| 71 | INLINE typename T::Type atomic_load( | ||
| 72 | const volatile T *a, memory_order mo) { | ||
| 73 | DCHECK(mo & (memory_order_relaxed | memory_order_consume | ||
| 74 | | memory_order_acquire | memory_order_seq_cst)); | ||
| 75 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 76 | typename T::Type v; | ||
| 77 | // FIXME(dvyukov): 64-bit load is not atomic on 32-bits. | ||
| 78 | if (mo == memory_order_relaxed) { | ||
| 79 | v = a->val_dont_use; | ||
| 80 | } else { | ||
| 81 | atomic_signal_fence(memory_order_seq_cst); | ||
| 82 | v = a->val_dont_use; | ||
| 83 | atomic_signal_fence(memory_order_seq_cst); | ||
| 84 | } | ||
| 85 | return v; | ||
| 86 | } | ||
| 87 | |||
| 88 | template<typename T> | ||
| 89 | INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { | ||
| 90 | DCHECK(mo & (memory_order_relaxed | memory_order_release | ||
| 91 | | memory_order_seq_cst)); | ||
| 92 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 93 | // FIXME(dvyukov): 64-bit store is not atomic on 32-bits. | ||
| 94 | if (mo == memory_order_relaxed) { | ||
| 95 | a->val_dont_use = v; | ||
| 96 | } else { | ||
| 97 | atomic_signal_fence(memory_order_seq_cst); | ||
| 98 | a->val_dont_use = v; | ||
| 99 | atomic_signal_fence(memory_order_seq_cst); | ||
| 100 | } | ||
| 101 | if (mo == memory_order_seq_cst) | ||
| 102 | atomic_thread_fence(memory_order_seq_cst); | ||
| 103 | } | ||
| 104 | |||
| 105 | INLINE u32 atomic_fetch_add(volatile atomic_uint32_t *a, | ||
| 106 | u32 v, memory_order mo) { | ||
| 107 | (void)mo; | ||
| 108 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 109 | return (u32)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use, | ||
| 110 | (long)v); | ||
| 111 | } | ||
| 112 | |||
| 113 | INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a, | ||
| 114 | uptr v, memory_order mo) { | ||
| 115 | (void)mo; | ||
| 116 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 117 | #ifdef _WIN64 | ||
| 118 | return (uptr)_InterlockedExchangeAdd64((volatile long long *)&a->val_dont_use, | ||
| 119 | (long long)v); | ||
| 120 | #else | ||
| 121 | return (uptr)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use, | ||
| 122 | (long)v); | ||
| 123 | #endif | ||
| 124 | } | ||
| 125 | |||
| 126 | INLINE u32 atomic_fetch_sub(volatile atomic_uint32_t *a, | ||
| 127 | u32 v, memory_order mo) { | ||
| 128 | (void)mo; | ||
| 129 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 130 | return (u32)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use, | ||
| 131 | -(long)v); | ||
| 132 | } | ||
| 133 | |||
| 134 | INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a, | ||
| 135 | uptr v, memory_order mo) { | ||
| 136 | (void)mo; | ||
| 137 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 138 | #ifdef _WIN64 | ||
| 139 | return (uptr)_InterlockedExchangeAdd64((volatile long long *)&a->val_dont_use, | ||
| 140 | -(long long)v); | ||
| 141 | #else | ||
| 142 | return (uptr)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use, | ||
| 143 | -(long)v); | ||
| 144 | #endif | ||
| 145 | } | ||
| 146 | |||
| 147 | INLINE u8 atomic_exchange(volatile atomic_uint8_t *a, | ||
| 148 | u8 v, memory_order mo) { | ||
| 149 | (void)mo; | ||
| 150 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 151 | return (u8)_InterlockedExchange8((volatile char*)&a->val_dont_use, v); | ||
| 152 | } | ||
| 153 | |||
| 154 | INLINE u16 atomic_exchange(volatile atomic_uint16_t *a, | ||
| 155 | u16 v, memory_order mo) { | ||
| 156 | (void)mo; | ||
| 157 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 158 | return (u16)_InterlockedExchange16((volatile short*)&a->val_dont_use, v); | ||
| 159 | } | ||
| 160 | |||
| 161 | INLINE u32 atomic_exchange(volatile atomic_uint32_t *a, | ||
| 162 | u32 v, memory_order mo) { | ||
| 163 | (void)mo; | ||
| 164 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 165 | return (u32)_InterlockedExchange((volatile long*)&a->val_dont_use, v); | ||
| 166 | } | ||
| 167 | |||
| 168 | INLINE bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a, | ||
| 169 | u8 *cmp, | ||
| 170 | u8 xchgv, | ||
| 171 | memory_order mo) { | ||
| 172 | (void)mo; | ||
| 173 | DCHECK(!((uptr)a % sizeof(*a))); | ||
| 174 | u8 cmpv = *cmp; | ||
| 175 | #ifdef _WIN64 | ||
| 176 | u8 prev = (u8)_InterlockedCompareExchange8( | ||
| 177 | (volatile char*)&a->val_dont_use, (char)xchgv, (char)cmpv); | ||
| 178 | #else | ||
| 179 | u8 prev; | ||
| 180 | __asm { | ||
| 181 | mov al, cmpv | ||
| 182 | mov ecx, a | ||
| 183 | mov dl, xchgv | ||
| 184 | lock cmpxchg [ecx], dl | ||
| 185 | mov prev, al | ||
| 186 | } | ||
| 187 | #endif | ||
| 188 | if (prev == cmpv) | ||
| 189 | return true; | ||
| 190 | *cmp = prev; | ||
| 191 | return false; | ||
| 192 | } | ||
| 193 | |||
| 194 | INLINE bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a, | ||
| 195 | uptr *cmp, | ||
| 196 | uptr xchg, | ||
| 197 | memory_order mo) { | ||
| 198 | uptr cmpv = *cmp; | ||
| 199 | uptr prev = (uptr)_InterlockedCompareExchangePointer( | ||
| 200 | (void*volatile*)&a->val_dont_use, (void*)xchg, (void*)cmpv); | ||
| 201 | if (prev == cmpv) | ||
| 202 | return true; | ||
| 203 | *cmp = prev; | ||
| 204 | return false; | ||
| 205 | } | ||
| 206 | |||
| 207 | INLINE bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a, | ||
| 208 | u16 *cmp, | ||
| 209 | u16 xchg, | ||
| 210 | memory_order mo) { | ||
| 211 | u16 cmpv = *cmp; | ||
| 212 | u16 prev = (u16)_InterlockedCompareExchange16( | ||
| 213 | (volatile short*)&a->val_dont_use, (short)xchg, (short)cmpv); | ||
| 214 | if (prev == cmpv) | ||
| 215 | return true; | ||
| 216 | *cmp = prev; | ||
| 217 | return false; | ||
| 218 | } | ||
| 219 | |||
| 220 | INLINE bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a, | ||
| 221 | u32 *cmp, | ||
| 222 | u32 xchg, | ||
| 223 | memory_order mo) { | ||
| 224 | u32 cmpv = *cmp; | ||
| 225 | u32 prev = (u32)_InterlockedCompareExchange( | ||
| 226 | (volatile long*)&a->val_dont_use, (long)xchg, (long)cmpv); | ||
| 227 | if (prev == cmpv) | ||
| 228 | return true; | ||
| 229 | *cmp = prev; | ||
| 230 | return false; | ||
| 231 | } | ||
| 232 | |||
| 233 | INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a, | ||
| 234 | u64 *cmp, | ||
| 235 | u64 xchg, | ||
| 236 | memory_order mo) { | ||
| 237 | u64 cmpv = *cmp; | ||
| 238 | u64 prev = (u64)_InterlockedCompareExchange64( | ||
| 239 | (volatile long long*)&a->val_dont_use, (long long)xchg, (long long)cmpv); | ||
| 240 | if (prev == cmpv) | ||
| 241 | return true; | ||
| 242 | *cmp = prev; | ||
| 243 | return false; | ||
| 244 | } | ||
| 245 | |||
| 246 | template<typename T> | ||
| 247 | INLINE bool atomic_compare_exchange_weak(volatile T *a, | ||
| 248 | typename T::Type *cmp, | ||
| 249 | typename T::Type xchg, | ||
| 250 | memory_order mo) { | ||
| 251 | return atomic_compare_exchange_strong(a, cmp, xchg, mo); | ||
| 252 | } | ||
| 253 | |||
| 254 | } // namespace __sanitizer | ||
| 255 | |||
| 256 | #endif // SANITIZER_ATOMIC_CLANG_H | ||
lib/tsan/sanitizer_common/sanitizer_bitvector.h created+350| ... | @@ -0,0 +1,350 @@ | ||
| 1 | //===-- sanitizer_bitvector.h -----------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Specializer BitVector implementation. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef SANITIZER_BITVECTOR_H | ||
| 14 | #define SANITIZER_BITVECTOR_H | ||
| 15 | |||
| 16 | #include "sanitizer_common.h" | ||
| 17 | |||
| 18 | namespace __sanitizer { | ||
| 19 | |||
| 20 | // Fixed size bit vector based on a single basic integer. | ||
| 21 | template <class basic_int_t = uptr> | ||
| 22 | class BasicBitVector { | ||
| 23 | public: | ||
| 24 | enum SizeEnum : uptr { kSize = sizeof(basic_int_t) * 8 }; | ||
| 25 | |||
| 26 | uptr size() const { return kSize; } | ||
| 27 | // No CTOR. | ||
| 28 | void clear() { bits_ = 0; } | ||
| 29 | void setAll() { bits_ = ~(basic_int_t)0; } | ||
| 30 | bool empty() const { return bits_ == 0; } | ||
| 31 | |||
| 32 | // Returns true if the bit has changed from 0 to 1. | ||
| 33 | bool setBit(uptr idx) { | ||
| 34 | basic_int_t old = bits_; | ||
| 35 | bits_ |= mask(idx); | ||
| 36 | return bits_ != old; | ||
| 37 | } | ||
| 38 | |||
| 39 | // Returns true if the bit has changed from 1 to 0. | ||
| 40 | bool clearBit(uptr idx) { | ||
| 41 | basic_int_t old = bits_; | ||
| 42 | bits_ &= ~mask(idx); | ||
| 43 | return bits_ != old; | ||
| 44 | } | ||
| 45 | |||
| 46 | bool getBit(uptr idx) const { return (bits_ & mask(idx)) != 0; } | ||
| 47 | |||
| 48 | uptr getAndClearFirstOne() { | ||
| 49 | CHECK(!empty()); | ||
| 50 | uptr idx = LeastSignificantSetBitIndex(bits_); | ||
| 51 | clearBit(idx); | ||
| 52 | return idx; | ||
| 53 | } | ||
| 54 | |||
| 55 | // Do "this |= v" and return whether new bits have been added. | ||
| 56 | bool setUnion(const BasicBitVector &v) { | ||
| 57 | basic_int_t old = bits_; | ||
| 58 | bits_ |= v.bits_; | ||
| 59 | return bits_ != old; | ||
| 60 | } | ||
| 61 | |||
| 62 | // Do "this &= v" and return whether any bits have been removed. | ||
| 63 | bool setIntersection(const BasicBitVector &v) { | ||
| 64 | basic_int_t old = bits_; | ||
| 65 | bits_ &= v.bits_; | ||
| 66 | return bits_ != old; | ||
| 67 | } | ||
| 68 | |||
| 69 | // Do "this &= ~v" and return whether any bits have been removed. | ||
| 70 | bool setDifference(const BasicBitVector &v) { | ||
| 71 | basic_int_t old = bits_; | ||
| 72 | bits_ &= ~v.bits_; | ||
| 73 | return bits_ != old; | ||
| 74 | } | ||
| 75 | |||
| 76 | void copyFrom(const BasicBitVector &v) { bits_ = v.bits_; } | ||
| 77 | |||
| 78 | // Returns true if 'this' intersects with 'v'. | ||
| 79 | bool intersectsWith(const BasicBitVector &v) const { | ||
| 80 | return (bits_ & v.bits_) != 0; | ||
| 81 | } | ||
| 82 | |||
| 83 | // for (BasicBitVector<>::Iterator it(bv); it.hasNext();) { | ||
| 84 | // uptr idx = it.next(); | ||
| 85 | // use(idx); | ||
| 86 | // } | ||
| 87 | class Iterator { | ||
| 88 | public: | ||
| 89 | Iterator() { } | ||
| 90 | explicit Iterator(const BasicBitVector &bv) : bv_(bv) {} | ||
| 91 | bool hasNext() const { return !bv_.empty(); } | ||
| 92 | uptr next() { return bv_.getAndClearFirstOne(); } | ||
| 93 | void clear() { bv_.clear(); } | ||
| 94 | private: | ||
| 95 | BasicBitVector bv_; | ||
| 96 | }; | ||
| 97 | |||
| 98 | private: | ||
| 99 | basic_int_t mask(uptr idx) const { | ||
| 100 | CHECK_LT(idx, size()); | ||
| 101 | return (basic_int_t)1UL << idx; | ||
| 102 | } | ||
| 103 | basic_int_t bits_; | ||
| 104 | }; | ||
| 105 | |||
| 106 | // Fixed size bit vector of (kLevel1Size*BV::kSize**2) bits. | ||
| 107 | // The implementation is optimized for better performance on | ||
| 108 | // sparse bit vectors, i.e. the those with few set bits. | ||
| 109 | template <uptr kLevel1Size = 1, class BV = BasicBitVector<> > | ||
| 110 | class TwoLevelBitVector { | ||
| 111 | // This is essentially a 2-level bit vector. | ||
| 112 | // Set bit in the first level BV indicates that there are set bits | ||
| 113 | // in the corresponding BV of the second level. | ||
| 114 | // This structure allows O(kLevel1Size) time for clear() and empty(), | ||
| 115 | // as well fast handling of sparse BVs. | ||
| 116 | public: | ||
| 117 | enum SizeEnum : uptr { kSize = BV::kSize * BV::kSize * kLevel1Size }; | ||
| 118 | // No CTOR. | ||
| 119 | |||
| 120 | uptr size() const { return kSize; } | ||
| 121 | |||
| 122 | void clear() { | ||
| 123 | for (uptr i = 0; i < kLevel1Size; i++) | ||
| 124 | l1_[i].clear(); | ||
| 125 | } | ||
| 126 | |||
| 127 | void setAll() { | ||
| 128 | for (uptr i0 = 0; i0 < kLevel1Size; i0++) { | ||
| 129 | l1_[i0].setAll(); | ||
| 130 | for (uptr i1 = 0; i1 < BV::kSize; i1++) | ||
| 131 | l2_[i0][i1].setAll(); | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | bool empty() const { | ||
| 136 | for (uptr i = 0; i < kLevel1Size; i++) | ||
| 137 | if (!l1_[i].empty()) | ||
| 138 | return false; | ||
| 139 | return true; | ||
| 140 | } | ||
| 141 | |||
| 142 | // Returns true if the bit has changed from 0 to 1. | ||
| 143 | bool setBit(uptr idx) { | ||
| 144 | check(idx); | ||
| 145 | uptr i0 = idx0(idx); | ||
| 146 | uptr i1 = idx1(idx); | ||
| 147 | uptr i2 = idx2(idx); | ||
| 148 | if (!l1_[i0].getBit(i1)) { | ||
| 149 | l1_[i0].setBit(i1); | ||
| 150 | l2_[i0][i1].clear(); | ||
| 151 | } | ||
| 152 | bool res = l2_[i0][i1].setBit(i2); | ||
| 153 | // Printf("%s: %zd => %zd %zd %zd; %d\n", __func__, | ||
| 154 | // idx, i0, i1, i2, res); | ||
| 155 | return res; | ||
| 156 | } | ||
| 157 | |||
| 158 | bool clearBit(uptr idx) { | ||
| 159 | check(idx); | ||
| 160 | uptr i0 = idx0(idx); | ||
| 161 | uptr i1 = idx1(idx); | ||
| 162 | uptr i2 = idx2(idx); | ||
| 163 | bool res = false; | ||
| 164 | if (l1_[i0].getBit(i1)) { | ||
| 165 | res = l2_[i0][i1].clearBit(i2); | ||
| 166 | if (l2_[i0][i1].empty()) | ||
| 167 | l1_[i0].clearBit(i1); | ||
| 168 | } | ||
| 169 | return res; | ||
| 170 | } | ||
| 171 | |||
| 172 | bool getBit(uptr idx) const { | ||
| 173 | check(idx); | ||
| 174 | uptr i0 = idx0(idx); | ||
| 175 | uptr i1 = idx1(idx); | ||
| 176 | uptr i2 = idx2(idx); | ||
| 177 | // Printf("%s: %zd => %zd %zd %zd\n", __func__, idx, i0, i1, i2); | ||
| 178 | return l1_[i0].getBit(i1) && l2_[i0][i1].getBit(i2); | ||
| 179 | } | ||
| 180 | |||
| 181 | uptr getAndClearFirstOne() { | ||
| 182 | for (uptr i0 = 0; i0 < kLevel1Size; i0++) { | ||
| 183 | if (l1_[i0].empty()) continue; | ||
| 184 | uptr i1 = l1_[i0].getAndClearFirstOne(); | ||
| 185 | uptr i2 = l2_[i0][i1].getAndClearFirstOne(); | ||
| 186 | if (!l2_[i0][i1].empty()) | ||
| 187 | l1_[i0].setBit(i1); | ||
| 188 | uptr res = i0 * BV::kSize * BV::kSize + i1 * BV::kSize + i2; | ||
| 189 | // Printf("getAndClearFirstOne: %zd %zd %zd => %zd\n", i0, i1, i2, res); | ||
| 190 | return res; | ||
| 191 | } | ||
| 192 | CHECK(0); | ||
| 193 | return 0; | ||
| 194 | } | ||
| 195 | |||
| 196 | // Do "this |= v" and return whether new bits have been added. | ||
| 197 | bool setUnion(const TwoLevelBitVector &v) { | ||
| 198 | bool res = false; | ||
| 199 | for (uptr i0 = 0; i0 < kLevel1Size; i0++) { | ||
| 200 | BV t = v.l1_[i0]; | ||
| 201 | while (!t.empty()) { | ||
| 202 | uptr i1 = t.getAndClearFirstOne(); | ||
| 203 | if (l1_[i0].setBit(i1)) | ||
| 204 | l2_[i0][i1].clear(); | ||
| 205 | if (l2_[i0][i1].setUnion(v.l2_[i0][i1])) | ||
| 206 | res = true; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | return res; | ||
| 210 | } | ||
| 211 | |||
| 212 | // Do "this &= v" and return whether any bits have been removed. | ||
| 213 | bool setIntersection(const TwoLevelBitVector &v) { | ||
| 214 | bool res = false; | ||
| 215 | for (uptr i0 = 0; i0 < kLevel1Size; i0++) { | ||
| 216 | if (l1_[i0].setIntersection(v.l1_[i0])) | ||
| 217 | res = true; | ||
| 218 | if (!l1_[i0].empty()) { | ||
| 219 | BV t = l1_[i0]; | ||
| 220 | while (!t.empty()) { | ||
| 221 | uptr i1 = t.getAndClearFirstOne(); | ||
| 222 | if (l2_[i0][i1].setIntersection(v.l2_[i0][i1])) | ||
| 223 | res = true; | ||
| 224 | if (l2_[i0][i1].empty()) | ||
| 225 | l1_[i0].clearBit(i1); | ||
| 226 | } | ||
| 227 | } | ||
| 228 | } | ||
| 229 | return res; | ||
| 230 | } | ||
| 231 | |||
| 232 | // Do "this &= ~v" and return whether any bits have been removed. | ||
| 233 | bool setDifference(const TwoLevelBitVector &v) { | ||
| 234 | bool res = false; | ||
| 235 | for (uptr i0 = 0; i0 < kLevel1Size; i0++) { | ||
| 236 | BV t = l1_[i0]; | ||
| 237 | t.setIntersection(v.l1_[i0]); | ||
| 238 | while (!t.empty()) { | ||
| 239 | uptr i1 = t.getAndClearFirstOne(); | ||
| 240 | if (l2_[i0][i1].setDifference(v.l2_[i0][i1])) | ||
| 241 | res = true; | ||
| 242 | if (l2_[i0][i1].empty()) | ||
| 243 | l1_[i0].clearBit(i1); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | return res; | ||
| 247 | } | ||
| 248 | |||
| 249 | void copyFrom(const TwoLevelBitVector &v) { | ||
| 250 | clear(); | ||
| 251 | setUnion(v); | ||
| 252 | } | ||
| 253 | |||
| 254 | // Returns true if 'this' intersects with 'v'. | ||
| 255 | bool intersectsWith(const TwoLevelBitVector &v) const { | ||
| 256 | for (uptr i0 = 0; i0 < kLevel1Size; i0++) { | ||
| 257 | BV t = l1_[i0]; | ||
| 258 | t.setIntersection(v.l1_[i0]); | ||
| 259 | while (!t.empty()) { | ||
| 260 | uptr i1 = t.getAndClearFirstOne(); | ||
| 261 | if (!v.l1_[i0].getBit(i1)) continue; | ||
| 262 | if (l2_[i0][i1].intersectsWith(v.l2_[i0][i1])) | ||
| 263 | return true; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | return false; | ||
| 267 | } | ||
| 268 | |||
| 269 | // for (TwoLevelBitVector<>::Iterator it(bv); it.hasNext();) { | ||
| 270 | // uptr idx = it.next(); | ||
| 271 | // use(idx); | ||
| 272 | // } | ||
| 273 | class Iterator { | ||
| 274 | public: | ||
| 275 | Iterator() { } | ||
| 276 | explicit Iterator(const TwoLevelBitVector &bv) : bv_(bv), i0_(0), i1_(0) { | ||
| 277 | it1_.clear(); | ||
| 278 | it2_.clear(); | ||
| 279 | } | ||
| 280 | |||
| 281 | bool hasNext() const { | ||
| 282 | if (it1_.hasNext()) return true; | ||
| 283 | for (uptr i = i0_; i < kLevel1Size; i++) | ||
| 284 | if (!bv_.l1_[i].empty()) return true; | ||
| 285 | return false; | ||
| 286 | } | ||
| 287 | |||
| 288 | uptr next() { | ||
| 289 | // Printf("++++: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(), | ||
| 290 | // it2_.hasNext(), kSize); | ||
| 291 | if (!it1_.hasNext() && !it2_.hasNext()) { | ||
| 292 | for (; i0_ < kLevel1Size; i0_++) { | ||
| 293 | if (bv_.l1_[i0_].empty()) continue; | ||
| 294 | it1_ = typename BV::Iterator(bv_.l1_[i0_]); | ||
| 295 | // Printf("+i0: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(), | ||
| 296 | // it2_.hasNext(), kSize); | ||
| 297 | break; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | if (!it2_.hasNext()) { | ||
| 301 | CHECK(it1_.hasNext()); | ||
| 302 | i1_ = it1_.next(); | ||
| 303 | it2_ = typename BV::Iterator(bv_.l2_[i0_][i1_]); | ||
| 304 | // Printf("++i1: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(), | ||
| 305 | // it2_.hasNext(), kSize); | ||
| 306 | } | ||
| 307 | CHECK(it2_.hasNext()); | ||
| 308 | uptr i2 = it2_.next(); | ||
| 309 | uptr res = i0_ * BV::kSize * BV::kSize + i1_ * BV::kSize + i2; | ||
| 310 | // Printf("+ret: %zd %zd; %d %d; size %zd; res: %zd\n", i0_, i1_, | ||
| 311 | // it1_.hasNext(), it2_.hasNext(), kSize, res); | ||
| 312 | if (!it1_.hasNext() && !it2_.hasNext()) | ||
| 313 | i0_++; | ||
| 314 | return res; | ||
| 315 | } | ||
| 316 | |||
| 317 | private: | ||
| 318 | const TwoLevelBitVector &bv_; | ||
| 319 | uptr i0_, i1_; | ||
| 320 | typename BV::Iterator it1_, it2_; | ||
| 321 | }; | ||
| 322 | |||
| 323 | private: | ||
| 324 | void check(uptr idx) const { CHECK_LE(idx, size()); } | ||
| 325 | |||
| 326 | uptr idx0(uptr idx) const { | ||
| 327 | uptr res = idx / (BV::kSize * BV::kSize); | ||
| 328 | CHECK_LE(res, kLevel1Size); | ||
| 329 | return res; | ||
| 330 | } | ||
| 331 | |||
| 332 | uptr idx1(uptr idx) const { | ||
| 333 | uptr res = (idx / BV::kSize) % BV::kSize; | ||
| 334 | CHECK_LE(res, BV::kSize); | ||
| 335 | return res; | ||
| 336 | } | ||
| 337 | |||
| 338 | uptr idx2(uptr idx) const { | ||
| 339 | uptr res = idx % BV::kSize; | ||
| 340 | CHECK_LE(res, BV::kSize); | ||
| 341 | return res; | ||
| 342 | } | ||
| 343 | |||
| 344 | BV l1_[kLevel1Size]; | ||
| 345 | BV l2_[kLevel1Size][BV::kSize]; | ||
| 346 | }; | ||
| 347 | |||
| 348 | } // namespace __sanitizer | ||
| 349 | |||
| 350 | #endif // SANITIZER_BITVECTOR_H | ||
lib/tsan/sanitizer_common/sanitizer_bvgraph.h created+164| ... | @@ -0,0 +1,164 @@ | ||
| 1 | //===-- sanitizer_bvgraph.h -------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer runtime. | ||
| 10 | // BVGraph -- a directed graph. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_BVGRAPH_H | ||
| 15 | #define SANITIZER_BVGRAPH_H | ||
| 16 | |||
| 17 | #include "sanitizer_common.h" | ||
| 18 | #include "sanitizer_bitvector.h" | ||
| 19 | |||
| 20 | namespace __sanitizer { | ||
| 21 | |||
| 22 | // Directed graph of fixed size implemented as an array of bit vectors. | ||
| 23 | // Not thread-safe, all accesses should be protected by an external lock. | ||
| 24 | template<class BV> | ||
| 25 | class BVGraph { | ||
| 26 | public: | ||
| 27 | enum SizeEnum : uptr { kSize = BV::kSize }; | ||
| 28 | uptr size() const { return kSize; } | ||
| 29 | // No CTOR. | ||
| 30 | void clear() { | ||
| 31 | for (uptr i = 0; i < size(); i++) | ||
| 32 | v[i].clear(); | ||
| 33 | } | ||
| 34 | |||
| 35 | bool empty() const { | ||
| 36 | for (uptr i = 0; i < size(); i++) | ||
| 37 | if (!v[i].empty()) | ||
| 38 | return false; | ||
| 39 | return true; | ||
| 40 | } | ||
| 41 | |||
| 42 | // Returns true if a new edge was added. | ||
| 43 | bool addEdge(uptr from, uptr to) { | ||
| 44 | check(from, to); | ||
| 45 | return v[from].setBit(to); | ||
| 46 | } | ||
| 47 | |||
| 48 | // Returns true if at least one new edge was added. | ||
| 49 | uptr addEdges(const BV &from, uptr to, uptr added_edges[], | ||
| 50 | uptr max_added_edges) { | ||
| 51 | uptr res = 0; | ||
| 52 | t1.copyFrom(from); | ||
| 53 | while (!t1.empty()) { | ||
| 54 | uptr node = t1.getAndClearFirstOne(); | ||
| 55 | if (v[node].setBit(to)) | ||
| 56 | if (res < max_added_edges) | ||
| 57 | added_edges[res++] = node; | ||
| 58 | } | ||
| 59 | return res; | ||
| 60 | } | ||
| 61 | |||
| 62 | // *EXPERIMENTAL* | ||
| 63 | // Returns true if an edge from=>to exist. | ||
| 64 | // This function does not use any global state except for 'this' itself, | ||
| 65 | // and thus can be called from different threads w/o locking. | ||
| 66 | // This would be racy. | ||
| 67 | // FIXME: investigate how much we can prove about this race being "benign". | ||
| 68 | bool hasEdge(uptr from, uptr to) { return v[from].getBit(to); } | ||
| 69 | |||
| 70 | // Returns true if the edge from=>to was removed. | ||
| 71 | bool removeEdge(uptr from, uptr to) { | ||
| 72 | return v[from].clearBit(to); | ||
| 73 | } | ||
| 74 | |||
| 75 | // Returns true if at least one edge *=>to was removed. | ||
| 76 | bool removeEdgesTo(const BV &to) { | ||
| 77 | bool res = 0; | ||
| 78 | for (uptr from = 0; from < size(); from++) { | ||
| 79 | if (v[from].setDifference(to)) | ||
| 80 | res = true; | ||
| 81 | } | ||
| 82 | return res; | ||
| 83 | } | ||
| 84 | |||
| 85 | // Returns true if at least one edge from=>* was removed. | ||
| 86 | bool removeEdgesFrom(const BV &from) { | ||
| 87 | bool res = false; | ||
| 88 | t1.copyFrom(from); | ||
| 89 | while (!t1.empty()) { | ||
| 90 | uptr idx = t1.getAndClearFirstOne(); | ||
| 91 | if (!v[idx].empty()) { | ||
| 92 | v[idx].clear(); | ||
| 93 | res = true; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | return res; | ||
| 97 | } | ||
| 98 | |||
| 99 | void removeEdgesFrom(uptr from) { | ||
| 100 | return v[from].clear(); | ||
| 101 | } | ||
| 102 | |||
| 103 | bool hasEdge(uptr from, uptr to) const { | ||
| 104 | check(from, to); | ||
| 105 | return v[from].getBit(to); | ||
| 106 | } | ||
| 107 | |||
| 108 | // Returns true if there is a path from the node 'from' | ||
| 109 | // to any of the nodes in 'targets'. | ||
| 110 | bool isReachable(uptr from, const BV &targets) { | ||
| 111 | BV &to_visit = t1, | ||
| 112 | &visited = t2; | ||
| 113 | to_visit.copyFrom(v[from]); | ||
| 114 | visited.clear(); | ||
| 115 | visited.setBit(from); | ||
| 116 | while (!to_visit.empty()) { | ||
| 117 | uptr idx = to_visit.getAndClearFirstOne(); | ||
| 118 | if (visited.setBit(idx)) | ||
| 119 | to_visit.setUnion(v[idx]); | ||
| 120 | } | ||
| 121 | return targets.intersectsWith(visited); | ||
| 122 | } | ||
| 123 | |||
| 124 | // Finds a path from 'from' to one of the nodes in 'target', | ||
| 125 | // stores up to 'path_size' items of the path into 'path', | ||
| 126 | // returns the path length, or 0 if there is no path of size 'path_size'. | ||
| 127 | uptr findPath(uptr from, const BV &targets, uptr *path, uptr path_size) { | ||
| 128 | if (path_size == 0) | ||
| 129 | return 0; | ||
| 130 | path[0] = from; | ||
| 131 | if (targets.getBit(from)) | ||
| 132 | return 1; | ||
| 133 | // The function is recursive, so we don't want to create BV on stack. | ||
| 134 | // Instead of a getAndClearFirstOne loop we use the slower iterator. | ||
| 135 | for (typename BV::Iterator it(v[from]); it.hasNext(); ) { | ||
| 136 | uptr idx = it.next(); | ||
| 137 | if (uptr res = findPath(idx, targets, path + 1, path_size - 1)) | ||
| 138 | return res + 1; | ||
| 139 | } | ||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | // Same as findPath, but finds a shortest path. | ||
| 144 | uptr findShortestPath(uptr from, const BV &targets, uptr *path, | ||
| 145 | uptr path_size) { | ||
| 146 | for (uptr p = 1; p <= path_size; p++) | ||
| 147 | if (findPath(from, targets, path, p) == p) | ||
| 148 | return p; | ||
| 149 | return 0; | ||
| 150 | } | ||
| 151 | |||
| 152 | private: | ||
| 153 | void check(uptr idx1, uptr idx2) const { | ||
| 154 | CHECK_LT(idx1, size()); | ||
| 155 | CHECK_LT(idx2, size()); | ||
| 156 | } | ||
| 157 | BV v[kSize]; | ||
| 158 | // Keep temporary vectors here since we can not create large objects on stack. | ||
| 159 | BV t1, t2; | ||
| 160 | }; | ||
| 161 | |||
| 162 | } // namespace __sanitizer | ||
| 163 | |||
| 164 | #endif // SANITIZER_BVGRAPH_H | ||
lib/tsan/sanitizer_common/sanitizer_common.cpp created+348| ... | @@ -0,0 +1,348 @@ | ||
| 1 | //===-- sanitizer_common.cpp ----------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer | ||
| 10 | // run-time libraries. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_common.h" | ||
| 14 | #include "sanitizer_allocator_interface.h" | ||
| 15 | #include "sanitizer_allocator_internal.h" | ||
| 16 | #include "sanitizer_atomic.h" | ||
| 17 | #include "sanitizer_flags.h" | ||
| 18 | #include "sanitizer_libc.h" | ||
| 19 | #include "sanitizer_placement_new.h" | ||
| 20 | |||
| 21 | namespace __sanitizer { | ||
| 22 | |||
| 23 | const char *SanitizerToolName = "SanitizerTool"; | ||
| 24 | |||
| 25 | atomic_uint32_t current_verbosity; | ||
| 26 | uptr PageSizeCached; | ||
| 27 | u32 NumberOfCPUsCached; | ||
| 28 | |||
| 29 | // PID of the tracer task in StopTheWorld. It shares the address space with the | ||
| 30 | // main process, but has a different PID and thus requires special handling. | ||
| 31 | uptr stoptheworld_tracer_pid = 0; | ||
| 32 | // Cached pid of parent process - if the parent process dies, we want to keep | ||
| 33 | // writing to the same log file. | ||
| 34 | uptr stoptheworld_tracer_ppid = 0; | ||
| 35 | |||
| 36 | void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type, | ||
| 37 | const char *mmap_type, error_t err, | ||
| 38 | bool raw_report) { | ||
| 39 | static int recursion_count; | ||
| 40 | if (SANITIZER_RTEMS || raw_report || recursion_count) { | ||
| 41 | // If we are on RTEMS or raw report is requested or we went into recursion, | ||
| 42 | // just die. The Report() and CHECK calls below may call mmap recursively | ||
| 43 | // and fail. | ||
| 44 | RawWrite("ERROR: Failed to mmap\n"); | ||
| 45 | Die(); | ||
| 46 | } | ||
| 47 | recursion_count++; | ||
| 48 | Report("ERROR: %s failed to " | ||
| 49 | "%s 0x%zx (%zd) bytes of %s (error code: %d)\n", | ||
| 50 | SanitizerToolName, mmap_type, size, size, mem_type, err); | ||
| 51 | #if !SANITIZER_GO | ||
| 52 | DumpProcessMap(); | ||
| 53 | #endif | ||
| 54 | UNREACHABLE("unable to mmap"); | ||
| 55 | } | ||
| 56 | |||
| 57 | typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); | ||
| 58 | typedef bool U32ComparisonFunction(const u32 &a, const u32 &b); | ||
| 59 | |||
| 60 | const char *StripPathPrefix(const char *filepath, | ||
| 61 | const char *strip_path_prefix) { | ||
| 62 | if (!filepath) return nullptr; | ||
| 63 | if (!strip_path_prefix) return filepath; | ||
| 64 | const char *res = filepath; | ||
| 65 | if (const char *pos = internal_strstr(filepath, strip_path_prefix)) | ||
| 66 | res = pos + internal_strlen(strip_path_prefix); | ||
| 67 | if (res[0] == '.' && res[1] == '/') | ||
| 68 | res += 2; | ||
| 69 | return res; | ||
| 70 | } | ||
| 71 | |||
| 72 | const char *StripModuleName(const char *module) { | ||
| 73 | if (!module) | ||
| 74 | return nullptr; | ||
| 75 | if (SANITIZER_WINDOWS) { | ||
| 76 | // On Windows, both slash and backslash are possible. | ||
| 77 | // Pick the one that goes last. | ||
| 78 | if (const char *bslash_pos = internal_strrchr(module, '\\')) | ||
| 79 | return StripModuleName(bslash_pos + 1); | ||
| 80 | } | ||
| 81 | if (const char *slash_pos = internal_strrchr(module, '/')) { | ||
| 82 | return slash_pos + 1; | ||
| 83 | } | ||
| 84 | return module; | ||
| 85 | } | ||
| 86 | |||
| 87 | void ReportErrorSummary(const char *error_message, const char *alt_tool_name) { | ||
| 88 | if (!common_flags()->print_summary) | ||
| 89 | return; | ||
| 90 | InternalScopedString buff(kMaxSummaryLength); | ||
| 91 | buff.append("SUMMARY: %s: %s", | ||
| 92 | alt_tool_name ? alt_tool_name : SanitizerToolName, error_message); | ||
| 93 | __sanitizer_report_error_summary(buff.data()); | ||
| 94 | } | ||
| 95 | |||
| 96 | // Removes the ANSI escape sequences from the input string (in-place). | ||
| 97 | void RemoveANSIEscapeSequencesFromString(char *str) { | ||
| 98 | if (!str) | ||
| 99 | return; | ||
| 100 | |||
| 101 | // We are going to remove the escape sequences in place. | ||
| 102 | char *s = str; | ||
| 103 | char *z = str; | ||
| 104 | while (*s != '\0') { | ||
| 105 | CHECK_GE(s, z); | ||
| 106 | // Skip over ANSI escape sequences with pointer 's'. | ||
| 107 | if (*s == '\033' && *(s + 1) == '[') { | ||
| 108 | s = internal_strchrnul(s, 'm'); | ||
| 109 | if (*s == '\0') { | ||
| 110 | break; | ||
| 111 | } | ||
| 112 | s++; | ||
| 113 | continue; | ||
| 114 | } | ||
| 115 | // 's' now points at a character we want to keep. Copy over the buffer | ||
| 116 | // content if the escape sequence has been perviously skipped andadvance | ||
| 117 | // both pointers. | ||
| 118 | if (s != z) | ||
| 119 | *z = *s; | ||
| 120 | |||
| 121 | // If we have not seen an escape sequence, just advance both pointers. | ||
| 122 | z++; | ||
| 123 | s++; | ||
| 124 | } | ||
| 125 | |||
| 126 | // Null terminate the string. | ||
| 127 | *z = '\0'; | ||
| 128 | } | ||
| 129 | |||
| 130 | void LoadedModule::set(const char *module_name, uptr base_address) { | ||
| 131 | clear(); | ||
| 132 | full_name_ = internal_strdup(module_name); | ||
| 133 | base_address_ = base_address; | ||
| 134 | } | ||
| 135 | |||
| 136 | void LoadedModule::set(const char *module_name, uptr base_address, | ||
| 137 | ModuleArch arch, u8 uuid[kModuleUUIDSize], | ||
| 138 | bool instrumented) { | ||
| 139 | set(module_name, base_address); | ||
| 140 | arch_ = arch; | ||
| 141 | internal_memcpy(uuid_, uuid, sizeof(uuid_)); | ||
| 142 | instrumented_ = instrumented; | ||
| 143 | } | ||
| 144 | |||
| 145 | void LoadedModule::clear() { | ||
| 146 | InternalFree(full_name_); | ||
| 147 | base_address_ = 0; | ||
| 148 | max_executable_address_ = 0; | ||
| 149 | full_name_ = nullptr; | ||
| 150 | arch_ = kModuleArchUnknown; | ||
| 151 | internal_memset(uuid_, 0, kModuleUUIDSize); | ||
| 152 | instrumented_ = false; | ||
| 153 | while (!ranges_.empty()) { | ||
| 154 | AddressRange *r = ranges_.front(); | ||
| 155 | ranges_.pop_front(); | ||
| 156 | InternalFree(r); | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable, | ||
| 161 | bool writable, const char *name) { | ||
| 162 | void *mem = InternalAlloc(sizeof(AddressRange)); | ||
| 163 | AddressRange *r = | ||
| 164 | new(mem) AddressRange(beg, end, executable, writable, name); | ||
| 165 | ranges_.push_back(r); | ||
| 166 | if (executable && end > max_executable_address_) | ||
| 167 | max_executable_address_ = end; | ||
| 168 | } | ||
| 169 | |||
| 170 | bool LoadedModule::containsAddress(uptr address) const { | ||
| 171 | for (const AddressRange &r : ranges()) { | ||
| 172 | if (r.beg <= address && address < r.end) | ||
| 173 | return true; | ||
| 174 | } | ||
| 175 | return false; | ||
| 176 | } | ||
| 177 | |||
| 178 | static atomic_uintptr_t g_total_mmaped; | ||
| 179 | |||
| 180 | void IncreaseTotalMmap(uptr size) { | ||
| 181 | if (!common_flags()->mmap_limit_mb) return; | ||
| 182 | uptr total_mmaped = | ||
| 183 | atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size; | ||
| 184 | // Since for now mmap_limit_mb is not a user-facing flag, just kill | ||
| 185 | // a program. Use RAW_CHECK to avoid extra mmaps in reporting. | ||
| 186 | RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb); | ||
| 187 | } | ||
| 188 | |||
| 189 | void DecreaseTotalMmap(uptr size) { | ||
| 190 | if (!common_flags()->mmap_limit_mb) return; | ||
| 191 | atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed); | ||
| 192 | } | ||
| 193 | |||
| 194 | bool TemplateMatch(const char *templ, const char *str) { | ||
| 195 | if ((!str) || str[0] == 0) | ||
| 196 | return false; | ||
| 197 | bool start = false; | ||
| 198 | if (templ && templ[0] == '^') { | ||
| 199 | start = true; | ||
| 200 | templ++; | ||
| 201 | } | ||
| 202 | bool asterisk = false; | ||
| 203 | while (templ && templ[0]) { | ||
| 204 | if (templ[0] == '*') { | ||
| 205 | templ++; | ||
| 206 | start = false; | ||
| 207 | asterisk = true; | ||
| 208 | continue; | ||
| 209 | } | ||
| 210 | if (templ[0] == '$') | ||
| 211 | return str[0] == 0 || asterisk; | ||
| 212 | if (str[0] == 0) | ||
| 213 | return false; | ||
| 214 | char *tpos = (char*)internal_strchr(templ, '*'); | ||
| 215 | char *tpos1 = (char*)internal_strchr(templ, '$'); | ||
| 216 | if ((!tpos) || (tpos1 && tpos1 < tpos)) | ||
| 217 | tpos = tpos1; | ||
| 218 | if (tpos) | ||
| 219 | tpos[0] = 0; | ||
| 220 | const char *str0 = str; | ||
| 221 | const char *spos = internal_strstr(str, templ); | ||
| 222 | str = spos + internal_strlen(templ); | ||
| 223 | templ = tpos; | ||
| 224 | if (tpos) | ||
| 225 | tpos[0] = tpos == tpos1 ? '$' : '*'; | ||
| 226 | if (!spos) | ||
| 227 | return false; | ||
| 228 | if (start && spos != str0) | ||
| 229 | return false; | ||
| 230 | start = false; | ||
| 231 | asterisk = false; | ||
| 232 | } | ||
| 233 | return true; | ||
| 234 | } | ||
| 235 | |||
| 236 | static char binary_name_cache_str[kMaxPathLength]; | ||
| 237 | static char process_name_cache_str[kMaxPathLength]; | ||
| 238 | |||
| 239 | const char *GetProcessName() { | ||
| 240 | return process_name_cache_str; | ||
| 241 | } | ||
| 242 | |||
| 243 | static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) { | ||
| 244 | ReadLongProcessName(buf, buf_len); | ||
| 245 | char *s = const_cast<char *>(StripModuleName(buf)); | ||
| 246 | uptr len = internal_strlen(s); | ||
| 247 | if (s != buf) { | ||
| 248 | internal_memmove(buf, s, len); | ||
| 249 | buf[len] = '\0'; | ||
| 250 | } | ||
| 251 | return len; | ||
| 252 | } | ||
| 253 | |||
| 254 | void UpdateProcessName() { | ||
| 255 | ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); | ||
| 256 | } | ||
| 257 | |||
| 258 | // Call once to make sure that binary_name_cache_str is initialized | ||
| 259 | void CacheBinaryName() { | ||
| 260 | if (binary_name_cache_str[0] != '\0') | ||
| 261 | return; | ||
| 262 | ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str)); | ||
| 263 | ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); | ||
| 264 | } | ||
| 265 | |||
| 266 | uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) { | ||
| 267 | CacheBinaryName(); | ||
| 268 | uptr name_len = internal_strlen(binary_name_cache_str); | ||
| 269 | name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1; | ||
| 270 | if (buf_len == 0) | ||
| 271 | return 0; | ||
| 272 | internal_memcpy(buf, binary_name_cache_str, name_len); | ||
| 273 | buf[name_len] = '\0'; | ||
| 274 | return name_len; | ||
| 275 | } | ||
| 276 | |||
| 277 | #if !SANITIZER_GO | ||
| 278 | void PrintCmdline() { | ||
| 279 | char **argv = GetArgv(); | ||
| 280 | if (!argv) return; | ||
| 281 | Printf("\nCommand: "); | ||
| 282 | for (uptr i = 0; argv[i]; ++i) | ||
| 283 | Printf("%s ", argv[i]); | ||
| 284 | Printf("\n\n"); | ||
| 285 | } | ||
| 286 | #endif | ||
| 287 | |||
| 288 | // Malloc hooks. | ||
| 289 | static const int kMaxMallocFreeHooks = 5; | ||
| 290 | struct MallocFreeHook { | ||
| 291 | void (*malloc_hook)(const void *, uptr); | ||
| 292 | void (*free_hook)(const void *); | ||
| 293 | }; | ||
| 294 | |||
| 295 | static MallocFreeHook MFHooks[kMaxMallocFreeHooks]; | ||
| 296 | |||
| 297 | void RunMallocHooks(const void *ptr, uptr size) { | ||
| 298 | for (int i = 0; i < kMaxMallocFreeHooks; i++) { | ||
| 299 | auto hook = MFHooks[i].malloc_hook; | ||
| 300 | if (!hook) return; | ||
| 301 | hook(ptr, size); | ||
| 302 | } | ||
| 303 | } | ||
| 304 | |||
| 305 | void RunFreeHooks(const void *ptr) { | ||
| 306 | for (int i = 0; i < kMaxMallocFreeHooks; i++) { | ||
| 307 | auto hook = MFHooks[i].free_hook; | ||
| 308 | if (!hook) return; | ||
| 309 | hook(ptr); | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr), | ||
| 314 | void (*free_hook)(const void *)) { | ||
| 315 | if (!malloc_hook || !free_hook) return 0; | ||
| 316 | for (int i = 0; i < kMaxMallocFreeHooks; i++) { | ||
| 317 | if (MFHooks[i].malloc_hook == nullptr) { | ||
| 318 | MFHooks[i].malloc_hook = malloc_hook; | ||
| 319 | MFHooks[i].free_hook = free_hook; | ||
| 320 | return i + 1; | ||
| 321 | } | ||
| 322 | } | ||
| 323 | return 0; | ||
| 324 | } | ||
| 325 | |||
| 326 | } // namespace __sanitizer | ||
| 327 | |||
| 328 | using namespace __sanitizer; | ||
| 329 | |||
| 330 | extern "C" { | ||
| 331 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary, | ||
| 332 | const char *error_summary) { | ||
| 333 | Printf("%s\n", error_summary); | ||
| 334 | } | ||
| 335 | |||
| 336 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 337 | int __sanitizer_acquire_crash_state() { | ||
| 338 | static atomic_uint8_t in_crash_state = {}; | ||
| 339 | return !atomic_exchange(&in_crash_state, 1, memory_order_relaxed); | ||
| 340 | } | ||
| 341 | |||
| 342 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 343 | int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *, | ||
| 344 | uptr), | ||
| 345 | void (*free_hook)(const void *)) { | ||
| 346 | return InstallMallocFreeHooks(malloc_hook, free_hook); | ||
| 347 | } | ||
| 348 | } // extern "C" | ||
lib/tsan/sanitizer_common/sanitizer_common.h created+1002| ... | @@ -0,0 +1,1002 @@ | ||
| 1 | //===-- sanitizer_common.h --------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between run-time libraries of sanitizers. | ||
| 10 | // | ||
| 11 | // It declares common functions and classes that are used in both runtimes. | ||
| 12 | // Implementation of some functions are provided in sanitizer_common, while | ||
| 13 | // others must be defined by run-time library itself. | ||
| 14 | //===----------------------------------------------------------------------===// | ||
| 15 | #ifndef SANITIZER_COMMON_H | ||
| 16 | #define SANITIZER_COMMON_H | ||
| 17 | |||
| 18 | #include "sanitizer_flags.h" | ||
| 19 | #include "sanitizer_interface_internal.h" | ||
| 20 | #include "sanitizer_internal_defs.h" | ||
| 21 | #include "sanitizer_libc.h" | ||
| 22 | #include "sanitizer_list.h" | ||
| 23 | #include "sanitizer_mutex.h" | ||
| 24 | |||
| 25 | #if defined(_MSC_VER) && !defined(__clang__) | ||
| 26 | extern "C" void _ReadWriteBarrier(); | ||
| 27 | #pragma intrinsic(_ReadWriteBarrier) | ||
| 28 | #endif | ||
| 29 | |||
| 30 | namespace __sanitizer { | ||
| 31 | |||
| 32 | struct AddressInfo; | ||
| 33 | struct BufferedStackTrace; | ||
| 34 | struct SignalContext; | ||
| 35 | struct StackTrace; | ||
| 36 | |||
| 37 | // Constants. | ||
| 38 | const uptr kWordSize = SANITIZER_WORDSIZE / 8; | ||
| 39 | const uptr kWordSizeInBits = 8 * kWordSize; | ||
| 40 | |||
| 41 | const uptr kCacheLineSize = SANITIZER_CACHE_LINE_SIZE; | ||
| 42 | |||
| 43 | const uptr kMaxPathLength = 4096; | ||
| 44 | |||
| 45 | const uptr kMaxThreadStackSize = 1 << 30; // 1Gb | ||
| 46 | |||
| 47 | static const uptr kErrorMessageBufferSize = 1 << 16; | ||
| 48 | |||
| 49 | // Denotes fake PC values that come from JIT/JAVA/etc. | ||
| 50 | // For such PC values __tsan_symbolize_external_ex() will be called. | ||
| 51 | const u64 kExternalPCBit = 1ULL << 60; | ||
| 52 | |||
| 53 | extern const char *SanitizerToolName; // Can be changed by the tool. | ||
| 54 | |||
| 55 | extern atomic_uint32_t current_verbosity; | ||
| 56 | INLINE void SetVerbosity(int verbosity) { | ||
| 57 | atomic_store(&current_verbosity, verbosity, memory_order_relaxed); | ||
| 58 | } | ||
| 59 | INLINE int Verbosity() { | ||
| 60 | return atomic_load(&current_verbosity, memory_order_relaxed); | ||
| 61 | } | ||
| 62 | |||
| 63 | #if SANITIZER_ANDROID | ||
| 64 | INLINE uptr GetPageSize() { | ||
| 65 | // Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array. | ||
| 66 | return 4096; | ||
| 67 | } | ||
| 68 | INLINE uptr GetPageSizeCached() { | ||
| 69 | return 4096; | ||
| 70 | } | ||
| 71 | #else | ||
| 72 | uptr GetPageSize(); | ||
| 73 | extern uptr PageSizeCached; | ||
| 74 | INLINE uptr GetPageSizeCached() { | ||
| 75 | if (!PageSizeCached) | ||
| 76 | PageSizeCached = GetPageSize(); | ||
| 77 | return PageSizeCached; | ||
| 78 | } | ||
| 79 | #endif | ||
| 80 | uptr GetMmapGranularity(); | ||
| 81 | uptr GetMaxVirtualAddress(); | ||
| 82 | uptr GetMaxUserVirtualAddress(); | ||
| 83 | // Threads | ||
| 84 | tid_t GetTid(); | ||
| 85 | int TgKill(pid_t pid, tid_t tid, int sig); | ||
| 86 | uptr GetThreadSelf(); | ||
| 87 | void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, | ||
| 88 | uptr *stack_bottom); | ||
| 89 | void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, | ||
| 90 | uptr *tls_addr, uptr *tls_size); | ||
| 91 | |||
| 92 | // Memory management | ||
| 93 | void *MmapOrDie(uptr size, const char *mem_type, bool raw_report = false); | ||
| 94 | INLINE void *MmapOrDieQuietly(uptr size, const char *mem_type) { | ||
| 95 | return MmapOrDie(size, mem_type, /*raw_report*/ true); | ||
| 96 | } | ||
| 97 | void UnmapOrDie(void *addr, uptr size); | ||
| 98 | // Behaves just like MmapOrDie, but tolerates out of memory condition, in that | ||
| 99 | // case returns nullptr. | ||
| 100 | void *MmapOrDieOnFatalError(uptr size, const char *mem_type); | ||
| 101 | bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name = nullptr) | ||
| 102 | WARN_UNUSED_RESULT; | ||
| 103 | bool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, | ||
| 104 | const char *name = nullptr) WARN_UNUSED_RESULT; | ||
| 105 | void *MmapNoReserveOrDie(uptr size, const char *mem_type); | ||
| 106 | void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name = nullptr); | ||
| 107 | // Behaves just like MmapFixedOrDie, but tolerates out of memory condition, in | ||
| 108 | // that case returns nullptr. | ||
| 109 | void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, | ||
| 110 | const char *name = nullptr); | ||
| 111 | void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name = nullptr); | ||
| 112 | void *MmapNoAccess(uptr size); | ||
| 113 | // Map aligned chunk of address space; size and alignment are powers of two. | ||
| 114 | // Dies on all but out of memory errors, in the latter case returns nullptr. | ||
| 115 | void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, | ||
| 116 | const char *mem_type); | ||
| 117 | // Disallow access to a memory range. Use MmapFixedNoAccess to allocate an | ||
| 118 | // unaccessible memory. | ||
| 119 | bool MprotectNoAccess(uptr addr, uptr size); | ||
| 120 | bool MprotectReadOnly(uptr addr, uptr size); | ||
| 121 | |||
| 122 | void MprotectMallocZones(void *addr, int prot); | ||
| 123 | |||
| 124 | // Find an available address space. | ||
| 125 | uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, | ||
| 126 | uptr *largest_gap_found, uptr *max_occupied_addr); | ||
| 127 | |||
| 128 | // Used to check if we can map shadow memory to a fixed location. | ||
| 129 | bool MemoryRangeIsAvailable(uptr range_start, uptr range_end); | ||
| 130 | // Releases memory pages entirely within the [beg, end] address range. Noop if | ||
| 131 | // the provided range does not contain at least one entire page. | ||
| 132 | void ReleaseMemoryPagesToOS(uptr beg, uptr end); | ||
| 133 | void IncreaseTotalMmap(uptr size); | ||
| 134 | void DecreaseTotalMmap(uptr size); | ||
| 135 | uptr GetRSS(); | ||
| 136 | void SetShadowRegionHugePageMode(uptr addr, uptr length); | ||
| 137 | bool DontDumpShadowMemory(uptr addr, uptr length); | ||
| 138 | // Check if the built VMA size matches the runtime one. | ||
| 139 | void CheckVMASize(); | ||
| 140 | void RunMallocHooks(const void *ptr, uptr size); | ||
| 141 | void RunFreeHooks(const void *ptr); | ||
| 142 | |||
| 143 | class ReservedAddressRange { | ||
| 144 | public: | ||
| 145 | uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr = 0); | ||
| 146 | uptr InitAligned(uptr size, uptr align, const char *name = nullptr); | ||
| 147 | uptr Map(uptr fixed_addr, uptr size, const char *name = nullptr); | ||
| 148 | uptr MapOrDie(uptr fixed_addr, uptr size, const char *name = nullptr); | ||
| 149 | void Unmap(uptr addr, uptr size); | ||
| 150 | void *base() const { return base_; } | ||
| 151 | uptr size() const { return size_; } | ||
| 152 | |||
| 153 | private: | ||
| 154 | void* base_; | ||
| 155 | uptr size_; | ||
| 156 | const char* name_; | ||
| 157 | uptr os_handle_; | ||
| 158 | }; | ||
| 159 | |||
| 160 | typedef void (*fill_profile_f)(uptr start, uptr rss, bool file, | ||
| 161 | /*out*/uptr *stats, uptr stats_size); | ||
| 162 | |||
| 163 | // Parse the contents of /proc/self/smaps and generate a memory profile. | ||
| 164 | // |cb| is a tool-specific callback that fills the |stats| array containing | ||
| 165 | // |stats_size| elements. | ||
| 166 | void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size); | ||
| 167 | |||
| 168 | // Simple low-level (mmap-based) allocator for internal use. Doesn't have | ||
| 169 | // constructor, so all instances of LowLevelAllocator should be | ||
| 170 | // linker initialized. | ||
| 171 | class LowLevelAllocator { | ||
| 172 | public: | ||
| 173 | // Requires an external lock. | ||
| 174 | void *Allocate(uptr size); | ||
| 175 | private: | ||
| 176 | char *allocated_end_; | ||
| 177 | char *allocated_current_; | ||
| 178 | }; | ||
| 179 | // Set the min alignment of LowLevelAllocator to at least alignment. | ||
| 180 | void SetLowLevelAllocateMinAlignment(uptr alignment); | ||
| 181 | typedef void (*LowLevelAllocateCallback)(uptr ptr, uptr size); | ||
| 182 | // Allows to register tool-specific callbacks for LowLevelAllocator. | ||
| 183 | // Passing NULL removes the callback. | ||
| 184 | void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback); | ||
| 185 | |||
| 186 | // IO | ||
| 187 | void CatastrophicErrorWrite(const char *buffer, uptr length); | ||
| 188 | void RawWrite(const char *buffer); | ||
| 189 | bool ColorizeReports(); | ||
| 190 | void RemoveANSIEscapeSequencesFromString(char *buffer); | ||
| 191 | void Printf(const char *format, ...); | ||
| 192 | void Report(const char *format, ...); | ||
| 193 | void SetPrintfAndReportCallback(void (*callback)(const char *)); | ||
| 194 | #define VReport(level, ...) \ | ||
| 195 | do { \ | ||
| 196 | if ((uptr)Verbosity() >= (level)) Report(__VA_ARGS__); \ | ||
| 197 | } while (0) | ||
| 198 | #define VPrintf(level, ...) \ | ||
| 199 | do { \ | ||
| 200 | if ((uptr)Verbosity() >= (level)) Printf(__VA_ARGS__); \ | ||
| 201 | } while (0) | ||
| 202 | |||
| 203 | // Lock sanitizer error reporting and protects against nested errors. | ||
| 204 | class ScopedErrorReportLock { | ||
| 205 | public: | ||
| 206 | ScopedErrorReportLock(); | ||
| 207 | ~ScopedErrorReportLock(); | ||
| 208 | |||
| 209 | static void CheckLocked(); | ||
| 210 | }; | ||
| 211 | |||
| 212 | extern uptr stoptheworld_tracer_pid; | ||
| 213 | extern uptr stoptheworld_tracer_ppid; | ||
| 214 | |||
| 215 | bool IsAccessibleMemoryRange(uptr beg, uptr size); | ||
| 216 | |||
| 217 | // Error report formatting. | ||
| 218 | const char *StripPathPrefix(const char *filepath, | ||
| 219 | const char *strip_file_prefix); | ||
| 220 | // Strip the directories from the module name. | ||
| 221 | const char *StripModuleName(const char *module); | ||
| 222 | |||
| 223 | // OS | ||
| 224 | uptr ReadBinaryName(/*out*/char *buf, uptr buf_len); | ||
| 225 | uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len); | ||
| 226 | uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len); | ||
| 227 | const char *GetProcessName(); | ||
| 228 | void UpdateProcessName(); | ||
| 229 | void CacheBinaryName(); | ||
| 230 | void DisableCoreDumperIfNecessary(); | ||
| 231 | void DumpProcessMap(); | ||
| 232 | void PrintModuleMap(); | ||
| 233 | const char *GetEnv(const char *name); | ||
| 234 | bool SetEnv(const char *name, const char *value); | ||
| 235 | |||
| 236 | u32 GetUid(); | ||
| 237 | void ReExec(); | ||
| 238 | void CheckASLR(); | ||
| 239 | void CheckMPROTECT(); | ||
| 240 | char **GetArgv(); | ||
| 241 | char **GetEnviron(); | ||
| 242 | void PrintCmdline(); | ||
| 243 | bool StackSizeIsUnlimited(); | ||
| 244 | void SetStackSizeLimitInBytes(uptr limit); | ||
| 245 | bool AddressSpaceIsUnlimited(); | ||
| 246 | void SetAddressSpaceUnlimited(); | ||
| 247 | void AdjustStackSize(void *attr); | ||
| 248 | void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args); | ||
| 249 | void SetSandboxingCallback(void (*f)()); | ||
| 250 | |||
| 251 | void InitializeCoverage(bool enabled, const char *coverage_dir); | ||
| 252 | |||
| 253 | void InitTlsSize(); | ||
| 254 | uptr GetTlsSize(); | ||
| 255 | |||
| 256 | // Other | ||
| 257 | void SleepForSeconds(int seconds); | ||
| 258 | void SleepForMillis(int millis); | ||
| 259 | u64 NanoTime(); | ||
| 260 | u64 MonotonicNanoTime(); | ||
| 261 | int Atexit(void (*function)(void)); | ||
| 262 | bool TemplateMatch(const char *templ, const char *str); | ||
| 263 | |||
| 264 | // Exit | ||
| 265 | void NORETURN Abort(); | ||
| 266 | void NORETURN Die(); | ||
| 267 | void NORETURN | ||
| 268 | CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2); | ||
| 269 | void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type, | ||
| 270 | const char *mmap_type, error_t err, | ||
| 271 | bool raw_report = false); | ||
| 272 | |||
| 273 | // Specific tools may override behavior of "Die" and "CheckFailed" functions | ||
| 274 | // to do tool-specific job. | ||
| 275 | typedef void (*DieCallbackType)(void); | ||
| 276 | |||
| 277 | // It's possible to add several callbacks that would be run when "Die" is | ||
| 278 | // called. The callbacks will be run in the opposite order. The tools are | ||
| 279 | // strongly recommended to setup all callbacks during initialization, when there | ||
| 280 | // is only a single thread. | ||
| 281 | bool AddDieCallback(DieCallbackType callback); | ||
| 282 | bool RemoveDieCallback(DieCallbackType callback); | ||
| 283 | |||
| 284 | void SetUserDieCallback(DieCallbackType callback); | ||
| 285 | |||
| 286 | typedef void (*CheckFailedCallbackType)(const char *, int, const char *, | ||
| 287 | u64, u64); | ||
| 288 | void SetCheckFailedCallback(CheckFailedCallbackType callback); | ||
| 289 | |||
| 290 | // Callback will be called if soft_rss_limit_mb is given and the limit is | ||
| 291 | // exceeded (exceeded==true) or if rss went down below the limit | ||
| 292 | // (exceeded==false). | ||
| 293 | // The callback should be registered once at the tool init time. | ||
| 294 | void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)); | ||
| 295 | |||
| 296 | // Functions related to signal handling. | ||
| 297 | typedef void (*SignalHandlerType)(int, void *, void *); | ||
| 298 | HandleSignalMode GetHandleSignalMode(int signum); | ||
| 299 | void InstallDeadlySignalHandlers(SignalHandlerType handler); | ||
| 300 | |||
| 301 | // Signal reporting. | ||
| 302 | // Each sanitizer uses slightly different implementation of stack unwinding. | ||
| 303 | typedef void (*UnwindSignalStackCallbackType)(const SignalContext &sig, | ||
| 304 | const void *callback_context, | ||
| 305 | BufferedStackTrace *stack); | ||
| 306 | // Print deadly signal report and die. | ||
| 307 | void HandleDeadlySignal(void *siginfo, void *context, u32 tid, | ||
| 308 | UnwindSignalStackCallbackType unwind, | ||
| 309 | const void *unwind_context); | ||
| 310 | |||
| 311 | // Part of HandleDeadlySignal, exposed for asan. | ||
| 312 | void StartReportDeadlySignal(); | ||
| 313 | // Part of HandleDeadlySignal, exposed for asan. | ||
| 314 | void ReportDeadlySignal(const SignalContext &sig, u32 tid, | ||
| 315 | UnwindSignalStackCallbackType unwind, | ||
| 316 | const void *unwind_context); | ||
| 317 | |||
| 318 | // Alternative signal stack (POSIX-only). | ||
| 319 | void SetAlternateSignalStack(); | ||
| 320 | void UnsetAlternateSignalStack(); | ||
| 321 | |||
| 322 | // We don't want a summary too long. | ||
| 323 | const int kMaxSummaryLength = 1024; | ||
| 324 | // Construct a one-line string: | ||
| 325 | // SUMMARY: SanitizerToolName: error_message | ||
| 326 | // and pass it to __sanitizer_report_error_summary. | ||
| 327 | // If alt_tool_name is provided, it's used in place of SanitizerToolName. | ||
| 328 | void ReportErrorSummary(const char *error_message, | ||
| 329 | const char *alt_tool_name = nullptr); | ||
| 330 | // Same as above, but construct error_message as: | ||
| 331 | // error_type file:line[:column][ function] | ||
| 332 | void ReportErrorSummary(const char *error_type, const AddressInfo &info, | ||
| 333 | const char *alt_tool_name = nullptr); | ||
| 334 | // Same as above, but obtains AddressInfo by symbolizing top stack trace frame. | ||
| 335 | void ReportErrorSummary(const char *error_type, const StackTrace *trace, | ||
| 336 | const char *alt_tool_name = nullptr); | ||
| 337 | |||
| 338 | void ReportMmapWriteExec(int prot); | ||
| 339 | |||
| 340 | // Math | ||
| 341 | #if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__) | ||
| 342 | extern "C" { | ||
| 343 | unsigned char _BitScanForward(unsigned long *index, unsigned long mask); | ||
| 344 | unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); | ||
| 345 | #if defined(_WIN64) | ||
| 346 | unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask); | ||
| 347 | unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); | ||
| 348 | #endif | ||
| 349 | } | ||
| 350 | #endif | ||
| 351 | |||
| 352 | INLINE uptr MostSignificantSetBitIndex(uptr x) { | ||
| 353 | CHECK_NE(x, 0U); | ||
| 354 | unsigned long up; | ||
| 355 | #if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) | ||
| 356 | # ifdef _WIN64 | ||
| 357 | up = SANITIZER_WORDSIZE - 1 - __builtin_clzll(x); | ||
| 358 | # else | ||
| 359 | up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(x); | ||
| 360 | # endif | ||
| 361 | #elif defined(_WIN64) | ||
| 362 | _BitScanReverse64(&up, x); | ||
| 363 | #else | ||
| 364 | _BitScanReverse(&up, x); | ||
| 365 | #endif | ||
| 366 | return up; | ||
| 367 | } | ||
| 368 | |||
| 369 | INLINE uptr LeastSignificantSetBitIndex(uptr x) { | ||
| 370 | CHECK_NE(x, 0U); | ||
| 371 | unsigned long up; | ||
| 372 | #if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) | ||
| 373 | # ifdef _WIN64 | ||
| 374 | up = __builtin_ctzll(x); | ||
| 375 | # else | ||
| 376 | up = __builtin_ctzl(x); | ||
| 377 | # endif | ||
| 378 | #elif defined(_WIN64) | ||
| 379 | _BitScanForward64(&up, x); | ||
| 380 | #else | ||
| 381 | _BitScanForward(&up, x); | ||
| 382 | #endif | ||
| 383 | return up; | ||
| 384 | } | ||
| 385 | |||
| 386 | INLINE bool IsPowerOfTwo(uptr x) { | ||
| 387 | return (x & (x - 1)) == 0; | ||
| 388 | } | ||
| 389 | |||
| 390 | INLINE uptr RoundUpToPowerOfTwo(uptr size) { | ||
| 391 | CHECK(size); | ||
| 392 | if (IsPowerOfTwo(size)) return size; | ||
| 393 | |||
| 394 | uptr up = MostSignificantSetBitIndex(size); | ||
| 395 | CHECK_LT(size, (1ULL << (up + 1))); | ||
| 396 | CHECK_GT(size, (1ULL << up)); | ||
| 397 | return 1ULL << (up + 1); | ||
| 398 | } | ||
| 399 | |||
| 400 | INLINE uptr RoundUpTo(uptr size, uptr boundary) { | ||
| 401 | RAW_CHECK(IsPowerOfTwo(boundary)); | ||
| 402 | return (size + boundary - 1) & ~(boundary - 1); | ||
| 403 | } | ||
| 404 | |||
| 405 | INLINE uptr RoundDownTo(uptr x, uptr boundary) { | ||
| 406 | return x & ~(boundary - 1); | ||
| 407 | } | ||
| 408 | |||
| 409 | INLINE bool IsAligned(uptr a, uptr alignment) { | ||
| 410 | return (a & (alignment - 1)) == 0; | ||
| 411 | } | ||
| 412 | |||
| 413 | INLINE uptr Log2(uptr x) { | ||
| 414 | CHECK(IsPowerOfTwo(x)); | ||
| 415 | return LeastSignificantSetBitIndex(x); | ||
| 416 | } | ||
| 417 | |||
| 418 | // Don't use std::min, std::max or std::swap, to minimize dependency | ||
| 419 | // on libstdc++. | ||
| 420 | template<class T> T Min(T a, T b) { return a < b ? a : b; } | ||
| 421 | template<class T> T Max(T a, T b) { return a > b ? a : b; } | ||
| 422 | template<class T> void Swap(T& a, T& b) { | ||
| 423 | T tmp = a; | ||
| 424 | a = b; | ||
| 425 | b = tmp; | ||
| 426 | } | ||
| 427 | |||
| 428 | // Char handling | ||
| 429 | INLINE bool IsSpace(int c) { | ||
| 430 | return (c == ' ') || (c == '\n') || (c == '\t') || | ||
| 431 | (c == '\f') || (c == '\r') || (c == '\v'); | ||
| 432 | } | ||
| 433 | INLINE bool IsDigit(int c) { | ||
| 434 | return (c >= '0') && (c <= '9'); | ||
| 435 | } | ||
| 436 | INLINE int ToLower(int c) { | ||
| 437 | return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c; | ||
| 438 | } | ||
| 439 | |||
| 440 | // A low-level vector based on mmap. May incur a significant memory overhead for | ||
| 441 | // small vectors. | ||
| 442 | // WARNING: The current implementation supports only POD types. | ||
| 443 | template<typename T> | ||
| 444 | class InternalMmapVectorNoCtor { | ||
| 445 | public: | ||
| 446 | void Initialize(uptr initial_capacity) { | ||
| 447 | capacity_bytes_ = 0; | ||
| 448 | size_ = 0; | ||
| 449 | data_ = 0; | ||
| 450 | reserve(initial_capacity); | ||
| 451 | } | ||
| 452 | void Destroy() { UnmapOrDie(data_, capacity_bytes_); } | ||
| 453 | T &operator[](uptr i) { | ||
| 454 | CHECK_LT(i, size_); | ||
| 455 | return data_[i]; | ||
| 456 | } | ||
| 457 | const T &operator[](uptr i) const { | ||
| 458 | CHECK_LT(i, size_); | ||
| 459 | return data_[i]; | ||
| 460 | } | ||
| 461 | void push_back(const T &element) { | ||
| 462 | CHECK_LE(size_, capacity()); | ||
| 463 | if (size_ == capacity()) { | ||
| 464 | uptr new_capacity = RoundUpToPowerOfTwo(size_ + 1); | ||
| 465 | Realloc(new_capacity); | ||
| 466 | } | ||
| 467 | internal_memcpy(&data_[size_++], &element, sizeof(T)); | ||
| 468 | } | ||
| 469 | T &back() { | ||
| 470 | CHECK_GT(size_, 0); | ||
| 471 | return data_[size_ - 1]; | ||
| 472 | } | ||
| 473 | void pop_back() { | ||
| 474 | CHECK_GT(size_, 0); | ||
| 475 | size_--; | ||
| 476 | } | ||
| 477 | uptr size() const { | ||
| 478 | return size_; | ||
| 479 | } | ||
| 480 | const T *data() const { | ||
| 481 | return data_; | ||
| 482 | } | ||
| 483 | T *data() { | ||
| 484 | return data_; | ||
| 485 | } | ||
| 486 | uptr capacity() const { return capacity_bytes_ / sizeof(T); } | ||
| 487 | void reserve(uptr new_size) { | ||
| 488 | // Never downsize internal buffer. | ||
| 489 | if (new_size > capacity()) | ||
| 490 | Realloc(new_size); | ||
| 491 | } | ||
| 492 | void resize(uptr new_size) { | ||
| 493 | if (new_size > size_) { | ||
| 494 | reserve(new_size); | ||
| 495 | internal_memset(&data_[size_], 0, sizeof(T) * (new_size - size_)); | ||
| 496 | } | ||
| 497 | size_ = new_size; | ||
| 498 | } | ||
| 499 | |||
| 500 | void clear() { size_ = 0; } | ||
| 501 | bool empty() const { return size() == 0; } | ||
| 502 | |||
| 503 | const T *begin() const { | ||
| 504 | return data(); | ||
| 505 | } | ||
| 506 | T *begin() { | ||
| 507 | return data(); | ||
| 508 | } | ||
| 509 | const T *end() const { | ||
| 510 | return data() + size(); | ||
| 511 | } | ||
| 512 | T *end() { | ||
| 513 | return data() + size(); | ||
| 514 | } | ||
| 515 | |||
| 516 | void swap(InternalMmapVectorNoCtor &other) { | ||
| 517 | Swap(data_, other.data_); | ||
| 518 | Swap(capacity_bytes_, other.capacity_bytes_); | ||
| 519 | Swap(size_, other.size_); | ||
| 520 | } | ||
| 521 | |||
| 522 | private: | ||
| 523 | void Realloc(uptr new_capacity) { | ||
| 524 | CHECK_GT(new_capacity, 0); | ||
| 525 | CHECK_LE(size_, new_capacity); | ||
| 526 | uptr new_capacity_bytes = | ||
| 527 | RoundUpTo(new_capacity * sizeof(T), GetPageSizeCached()); | ||
| 528 | T *new_data = (T *)MmapOrDie(new_capacity_bytes, "InternalMmapVector"); | ||
| 529 | internal_memcpy(new_data, data_, size_ * sizeof(T)); | ||
| 530 | UnmapOrDie(data_, capacity_bytes_); | ||
| 531 | data_ = new_data; | ||
| 532 | capacity_bytes_ = new_capacity_bytes; | ||
| 533 | } | ||
| 534 | |||
| 535 | T *data_; | ||
| 536 | uptr capacity_bytes_; | ||
| 537 | uptr size_; | ||
| 538 | }; | ||
| 539 | |||
| 540 | template <typename T> | ||
| 541 | bool operator==(const InternalMmapVectorNoCtor<T> &lhs, | ||
| 542 | const InternalMmapVectorNoCtor<T> &rhs) { | ||
| 543 | if (lhs.size() != rhs.size()) return false; | ||
| 544 | return internal_memcmp(lhs.data(), rhs.data(), lhs.size() * sizeof(T)) == 0; | ||
| 545 | } | ||
| 546 | |||
| 547 | template <typename T> | ||
| 548 | bool operator!=(const InternalMmapVectorNoCtor<T> &lhs, | ||
| 549 | const InternalMmapVectorNoCtor<T> &rhs) { | ||
| 550 | return !(lhs == rhs); | ||
| 551 | } | ||
| 552 | |||
| 553 | template<typename T> | ||
| 554 | class InternalMmapVector : public InternalMmapVectorNoCtor<T> { | ||
| 555 | public: | ||
| 556 | InternalMmapVector() { InternalMmapVectorNoCtor<T>::Initialize(0); } | ||
| 557 | explicit InternalMmapVector(uptr cnt) { | ||
| 558 | InternalMmapVectorNoCtor<T>::Initialize(cnt); | ||
| 559 | this->resize(cnt); | ||
| 560 | } | ||
| 561 | ~InternalMmapVector() { InternalMmapVectorNoCtor<T>::Destroy(); } | ||
| 562 | // Disallow copies and moves. | ||
| 563 | InternalMmapVector(const InternalMmapVector &) = delete; | ||
| 564 | InternalMmapVector &operator=(const InternalMmapVector &) = delete; | ||
| 565 | InternalMmapVector(InternalMmapVector &&) = delete; | ||
| 566 | InternalMmapVector &operator=(InternalMmapVector &&) = delete; | ||
| 567 | }; | ||
| 568 | |||
| 569 | class InternalScopedString : public InternalMmapVector<char> { | ||
| 570 | public: | ||
| 571 | explicit InternalScopedString(uptr max_length) | ||
| 572 | : InternalMmapVector<char>(max_length), length_(0) { | ||
| 573 | (*this)[0] = '\0'; | ||
| 574 | } | ||
| 575 | uptr length() { return length_; } | ||
| 576 | void clear() { | ||
| 577 | (*this)[0] = '\0'; | ||
| 578 | length_ = 0; | ||
| 579 | } | ||
| 580 | void append(const char *format, ...); | ||
| 581 | |||
| 582 | private: | ||
| 583 | uptr length_; | ||
| 584 | }; | ||
| 585 | |||
| 586 | template <class T> | ||
| 587 | struct CompareLess { | ||
| 588 | bool operator()(const T &a, const T &b) const { return a < b; } | ||
| 589 | }; | ||
| 590 | |||
| 591 | // HeapSort for arrays and InternalMmapVector. | ||
| 592 | template <class T, class Compare = CompareLess<T>> | ||
| 593 | void Sort(T *v, uptr size, Compare comp = {}) { | ||
| 594 | if (size < 2) | ||
| 595 | return; | ||
| 596 | // Stage 1: insert elements to the heap. | ||
| 597 | for (uptr i = 1; i < size; i++) { | ||
| 598 | uptr j, p; | ||
| 599 | for (j = i; j > 0; j = p) { | ||
| 600 | p = (j - 1) / 2; | ||
| 601 | if (comp(v[p], v[j])) | ||
| 602 | Swap(v[j], v[p]); | ||
| 603 | else | ||
| 604 | break; | ||
| 605 | } | ||
| 606 | } | ||
| 607 | // Stage 2: swap largest element with the last one, | ||
| 608 | // and sink the new top. | ||
| 609 | for (uptr i = size - 1; i > 0; i--) { | ||
| 610 | Swap(v[0], v[i]); | ||
| 611 | uptr j, max_ind; | ||
| 612 | for (j = 0; j < i; j = max_ind) { | ||
| 613 | uptr left = 2 * j + 1; | ||
| 614 | uptr right = 2 * j + 2; | ||
| 615 | max_ind = j; | ||
| 616 | if (left < i && comp(v[max_ind], v[left])) | ||
| 617 | max_ind = left; | ||
| 618 | if (right < i && comp(v[max_ind], v[right])) | ||
| 619 | max_ind = right; | ||
| 620 | if (max_ind != j) | ||
| 621 | Swap(v[j], v[max_ind]); | ||
| 622 | else | ||
| 623 | break; | ||
| 624 | } | ||
| 625 | } | ||
| 626 | } | ||
| 627 | |||
| 628 | // Works like std::lower_bound: finds the first element that is not less | ||
| 629 | // than the val. | ||
| 630 | template <class Container, class Value, class Compare> | ||
| 631 | uptr InternalLowerBound(const Container &v, uptr first, uptr last, | ||
| 632 | const Value &val, Compare comp) { | ||
| 633 | while (last > first) { | ||
| 634 | uptr mid = (first + last) / 2; | ||
| 635 | if (comp(v[mid], val)) | ||
| 636 | first = mid + 1; | ||
| 637 | else | ||
| 638 | last = mid; | ||
| 639 | } | ||
| 640 | return first; | ||
| 641 | } | ||
| 642 | |||
| 643 | enum ModuleArch { | ||
| 644 | kModuleArchUnknown, | ||
| 645 | kModuleArchI386, | ||
| 646 | kModuleArchX86_64, | ||
| 647 | kModuleArchX86_64H, | ||
| 648 | kModuleArchARMV6, | ||
| 649 | kModuleArchARMV7, | ||
| 650 | kModuleArchARMV7S, | ||
| 651 | kModuleArchARMV7K, | ||
| 652 | kModuleArchARM64 | ||
| 653 | }; | ||
| 654 | |||
| 655 | // Opens the file 'file_name" and reads up to 'max_len' bytes. | ||
| 656 | // The resulting buffer is mmaped and stored in '*buff'. | ||
| 657 | // Returns true if file was successfully opened and read. | ||
| 658 | bool ReadFileToVector(const char *file_name, | ||
| 659 | InternalMmapVectorNoCtor<char> *buff, | ||
| 660 | uptr max_len = 1 << 26, error_t *errno_p = nullptr); | ||
| 661 | |||
| 662 | // Opens the file 'file_name" and reads up to 'max_len' bytes. | ||
| 663 | // This function is less I/O efficient than ReadFileToVector as it may reread | ||
| 664 | // file multiple times to avoid mmap during read attempts. It's used to read | ||
| 665 | // procmap, so short reads with mmap in between can produce inconsistent result. | ||
| 666 | // The resulting buffer is mmaped and stored in '*buff'. | ||
| 667 | // The size of the mmaped region is stored in '*buff_size'. | ||
| 668 | // The total number of read bytes is stored in '*read_len'. | ||
| 669 | // Returns true if file was successfully opened and read. | ||
| 670 | bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, | ||
| 671 | uptr *read_len, uptr max_len = 1 << 26, | ||
| 672 | error_t *errno_p = nullptr); | ||
| 673 | |||
| 674 | // When adding a new architecture, don't forget to also update | ||
| 675 | // script/asan_symbolize.py and sanitizer_symbolizer_libcdep.cpp. | ||
| 676 | inline const char *ModuleArchToString(ModuleArch arch) { | ||
| 677 | switch (arch) { | ||
| 678 | case kModuleArchUnknown: | ||
| 679 | return ""; | ||
| 680 | case kModuleArchI386: | ||
| 681 | return "i386"; | ||
| 682 | case kModuleArchX86_64: | ||
| 683 | return "x86_64"; | ||
| 684 | case kModuleArchX86_64H: | ||
| 685 | return "x86_64h"; | ||
| 686 | case kModuleArchARMV6: | ||
| 687 | return "armv6"; | ||
| 688 | case kModuleArchARMV7: | ||
| 689 | return "armv7"; | ||
| 690 | case kModuleArchARMV7S: | ||
| 691 | return "armv7s"; | ||
| 692 | case kModuleArchARMV7K: | ||
| 693 | return "armv7k"; | ||
| 694 | case kModuleArchARM64: | ||
| 695 | return "arm64"; | ||
| 696 | } | ||
| 697 | CHECK(0 && "Invalid module arch"); | ||
| 698 | return ""; | ||
| 699 | } | ||
| 700 | |||
| 701 | const uptr kModuleUUIDSize = 16; | ||
| 702 | const uptr kMaxSegName = 16; | ||
| 703 | |||
| 704 | // Represents a binary loaded into virtual memory (e.g. this can be an | ||
| 705 | // executable or a shared object). | ||
| 706 | class LoadedModule { | ||
| 707 | public: | ||
| 708 | LoadedModule() | ||
| 709 | : full_name_(nullptr), | ||
| 710 | base_address_(0), | ||
| 711 | max_executable_address_(0), | ||
| 712 | arch_(kModuleArchUnknown), | ||
| 713 | instrumented_(false) { | ||
| 714 | internal_memset(uuid_, 0, kModuleUUIDSize); | ||
| 715 | ranges_.clear(); | ||
| 716 | } | ||
| 717 | void set(const char *module_name, uptr base_address); | ||
| 718 | void set(const char *module_name, uptr base_address, ModuleArch arch, | ||
| 719 | u8 uuid[kModuleUUIDSize], bool instrumented); | ||
| 720 | void clear(); | ||
| 721 | void addAddressRange(uptr beg, uptr end, bool executable, bool writable, | ||
| 722 | const char *name = nullptr); | ||
| 723 | bool containsAddress(uptr address) const; | ||
| 724 | |||
| 725 | const char *full_name() const { return full_name_; } | ||
| 726 | uptr base_address() const { return base_address_; } | ||
| 727 | uptr max_executable_address() const { return max_executable_address_; } | ||
| 728 | ModuleArch arch() const { return arch_; } | ||
| 729 | const u8 *uuid() const { return uuid_; } | ||
| 730 | bool instrumented() const { return instrumented_; } | ||
| 731 | |||
| 732 | struct AddressRange { | ||
| 733 | AddressRange *next; | ||
| 734 | uptr beg; | ||
| 735 | uptr end; | ||
| 736 | bool executable; | ||
| 737 | bool writable; | ||
| 738 | char name[kMaxSegName]; | ||
| 739 | |||
| 740 | AddressRange(uptr beg, uptr end, bool executable, bool writable, | ||
| 741 | const char *name) | ||
| 742 | : next(nullptr), | ||
| 743 | beg(beg), | ||
| 744 | end(end), | ||
| 745 | executable(executable), | ||
| 746 | writable(writable) { | ||
| 747 | internal_strncpy(this->name, (name ? name : ""), ARRAY_SIZE(this->name)); | ||
| 748 | } | ||
| 749 | }; | ||
| 750 | |||
| 751 | const IntrusiveList<AddressRange> &ranges() const { return ranges_; } | ||
| 752 | |||
| 753 | private: | ||
| 754 | char *full_name_; // Owned. | ||
| 755 | uptr base_address_; | ||
| 756 | uptr max_executable_address_; | ||
| 757 | ModuleArch arch_; | ||
| 758 | u8 uuid_[kModuleUUIDSize]; | ||
| 759 | bool instrumented_; | ||
| 760 | IntrusiveList<AddressRange> ranges_; | ||
| 761 | }; | ||
| 762 | |||
| 763 | // List of LoadedModules. OS-dependent implementation is responsible for | ||
| 764 | // filling this information. | ||
| 765 | class ListOfModules { | ||
| 766 | public: | ||
| 767 | ListOfModules() : initialized(false) {} | ||
| 768 | ~ListOfModules() { clear(); } | ||
| 769 | void init(); | ||
| 770 | void fallbackInit(); // Uses fallback init if available, otherwise clears | ||
| 771 | const LoadedModule *begin() const { return modules_.begin(); } | ||
| 772 | LoadedModule *begin() { return modules_.begin(); } | ||
| 773 | const LoadedModule *end() const { return modules_.end(); } | ||
| 774 | LoadedModule *end() { return modules_.end(); } | ||
| 775 | uptr size() const { return modules_.size(); } | ||
| 776 | const LoadedModule &operator[](uptr i) const { | ||
| 777 | CHECK_LT(i, modules_.size()); | ||
| 778 | return modules_[i]; | ||
| 779 | } | ||
| 780 | |||
| 781 | private: | ||
| 782 | void clear() { | ||
| 783 | for (auto &module : modules_) module.clear(); | ||
| 784 | modules_.clear(); | ||
| 785 | } | ||
| 786 | void clearOrInit() { | ||
| 787 | initialized ? clear() : modules_.Initialize(kInitialCapacity); | ||
| 788 | initialized = true; | ||
| 789 | } | ||
| 790 | |||
| 791 | InternalMmapVectorNoCtor<LoadedModule> modules_; | ||
| 792 | // We rarely have more than 16K loaded modules. | ||
| 793 | static const uptr kInitialCapacity = 1 << 14; | ||
| 794 | bool initialized; | ||
| 795 | }; | ||
| 796 | |||
| 797 | // Callback type for iterating over a set of memory ranges. | ||
| 798 | typedef void (*RangeIteratorCallback)(uptr begin, uptr end, void *arg); | ||
| 799 | |||
| 800 | enum AndroidApiLevel { | ||
| 801 | ANDROID_NOT_ANDROID = 0, | ||
| 802 | ANDROID_KITKAT = 19, | ||
| 803 | ANDROID_LOLLIPOP_MR1 = 22, | ||
| 804 | ANDROID_POST_LOLLIPOP = 23 | ||
| 805 | }; | ||
| 806 | |||
| 807 | void WriteToSyslog(const char *buffer); | ||
| 808 | |||
| 809 | #if defined(SANITIZER_WINDOWS) && defined(_MSC_VER) && !defined(__clang__) | ||
| 810 | #define SANITIZER_WIN_TRACE 1 | ||
| 811 | #else | ||
| 812 | #define SANITIZER_WIN_TRACE 0 | ||
| 813 | #endif | ||
| 814 | |||
| 815 | #if SANITIZER_MAC || SANITIZER_WIN_TRACE | ||
| 816 | void LogFullErrorReport(const char *buffer); | ||
| 817 | #else | ||
| 818 | INLINE void LogFullErrorReport(const char *buffer) {} | ||
| 819 | #endif | ||
| 820 | |||
| 821 | #if SANITIZER_LINUX || SANITIZER_MAC | ||
| 822 | void WriteOneLineToSyslog(const char *s); | ||
| 823 | void LogMessageOnPrintf(const char *str); | ||
| 824 | #else | ||
| 825 | INLINE void WriteOneLineToSyslog(const char *s) {} | ||
| 826 | INLINE void LogMessageOnPrintf(const char *str) {} | ||
| 827 | #endif | ||
| 828 | |||
| 829 | #if SANITIZER_LINUX || SANITIZER_WIN_TRACE | ||
| 830 | // Initialize Android logging. Any writes before this are silently lost. | ||
| 831 | void AndroidLogInit(); | ||
| 832 | void SetAbortMessage(const char *); | ||
| 833 | #else | ||
| 834 | INLINE void AndroidLogInit() {} | ||
| 835 | // FIXME: MacOS implementation could use CRSetCrashLogMessage. | ||
| 836 | INLINE void SetAbortMessage(const char *) {} | ||
| 837 | #endif | ||
| 838 | |||
| 839 | #if SANITIZER_ANDROID | ||
| 840 | void SanitizerInitializeUnwinder(); | ||
| 841 | AndroidApiLevel AndroidGetApiLevel(); | ||
| 842 | #else | ||
| 843 | INLINE void AndroidLogWrite(const char *buffer_unused) {} | ||
| 844 | INLINE void SanitizerInitializeUnwinder() {} | ||
| 845 | INLINE AndroidApiLevel AndroidGetApiLevel() { return ANDROID_NOT_ANDROID; } | ||
| 846 | #endif | ||
| 847 | |||
| 848 | INLINE uptr GetPthreadDestructorIterations() { | ||
| 849 | #if SANITIZER_ANDROID | ||
| 850 | return (AndroidGetApiLevel() == ANDROID_LOLLIPOP_MR1) ? 8 : 4; | ||
| 851 | #elif SANITIZER_POSIX | ||
| 852 | return 4; | ||
| 853 | #else | ||
| 854 | // Unused on Windows. | ||
| 855 | return 0; | ||
| 856 | #endif | ||
| 857 | } | ||
| 858 | |||
| 859 | void *internal_start_thread(void *(*func)(void*), void *arg); | ||
| 860 | void internal_join_thread(void *th); | ||
| 861 | void MaybeStartBackgroudThread(); | ||
| 862 | |||
| 863 | // Make the compiler think that something is going on there. | ||
| 864 | // Use this inside a loop that looks like memset/memcpy/etc to prevent the | ||
| 865 | // compiler from recognising it and turning it into an actual call to | ||
| 866 | // memset/memcpy/etc. | ||
| 867 | static inline void SanitizerBreakOptimization(void *arg) { | ||
| 868 | #if defined(_MSC_VER) && !defined(__clang__) | ||
| 869 | _ReadWriteBarrier(); | ||
| 870 | #else | ||
| 871 | __asm__ __volatile__("" : : "r" (arg) : "memory"); | ||
| 872 | #endif | ||
| 873 | } | ||
| 874 | |||
| 875 | struct SignalContext { | ||
| 876 | void *siginfo; | ||
| 877 | void *context; | ||
| 878 | uptr addr; | ||
| 879 | uptr pc; | ||
| 880 | uptr sp; | ||
| 881 | uptr bp; | ||
| 882 | bool is_memory_access; | ||
| 883 | enum WriteFlag { UNKNOWN, READ, WRITE } write_flag; | ||
| 884 | |||
| 885 | // In some cases the kernel cannot provide the true faulting address; `addr` | ||
| 886 | // will be zero then. This field allows to distinguish between these cases | ||
| 887 | // and dereferences of null. | ||
| 888 | bool is_true_faulting_addr; | ||
| 889 | |||
| 890 | // VS2013 doesn't implement unrestricted unions, so we need a trivial default | ||
| 891 | // constructor | ||
| 892 | SignalContext() = default; | ||
| 893 | |||
| 894 | // Creates signal context in a platform-specific manner. | ||
| 895 | // SignalContext is going to keep pointers to siginfo and context without | ||
| 896 | // owning them. | ||
| 897 | SignalContext(void *siginfo, void *context) | ||
| 898 | : siginfo(siginfo), | ||
| 899 | context(context), | ||
| 900 | addr(GetAddress()), | ||
| 901 | is_memory_access(IsMemoryAccess()), | ||
| 902 | write_flag(GetWriteFlag()), | ||
| 903 | is_true_faulting_addr(IsTrueFaultingAddress()) { | ||
| 904 | InitPcSpBp(); | ||
| 905 | } | ||
| 906 | |||
| 907 | static void DumpAllRegisters(void *context); | ||
| 908 | |||
| 909 | // Type of signal e.g. SIGSEGV or EXCEPTION_ACCESS_VIOLATION. | ||
| 910 | int GetType() const; | ||
| 911 | |||
| 912 | // String description of the signal. | ||
| 913 | const char *Describe() const; | ||
| 914 | |||
| 915 | // Returns true if signal is stack overflow. | ||
| 916 | bool IsStackOverflow() const; | ||
| 917 | |||
| 918 | private: | ||
| 919 | // Platform specific initialization. | ||
| 920 | void InitPcSpBp(); | ||
| 921 | uptr GetAddress() const; | ||
| 922 | WriteFlag GetWriteFlag() const; | ||
| 923 | bool IsMemoryAccess() const; | ||
| 924 | bool IsTrueFaultingAddress() const; | ||
| 925 | }; | ||
| 926 | |||
| 927 | void InitializePlatformEarly(); | ||
| 928 | void MaybeReexec(); | ||
| 929 | |||
| 930 | template <typename Fn> | ||
| 931 | class RunOnDestruction { | ||
| 932 | public: | ||
| 933 | explicit RunOnDestruction(Fn fn) : fn_(fn) {} | ||
| 934 | ~RunOnDestruction() { fn_(); } | ||
| 935 | |||
| 936 | private: | ||
| 937 | Fn fn_; | ||
| 938 | }; | ||
| 939 | |||
| 940 | // A simple scope guard. Usage: | ||
| 941 | // auto cleanup = at_scope_exit([]{ do_cleanup; }); | ||
| 942 | template <typename Fn> | ||
| 943 | RunOnDestruction<Fn> at_scope_exit(Fn fn) { | ||
| 944 | return RunOnDestruction<Fn>(fn); | ||
| 945 | } | ||
| 946 | |||
| 947 | // Linux on 64-bit s390 had a nasty bug that crashes the whole machine | ||
| 948 | // if a process uses virtual memory over 4TB (as many sanitizers like | ||
| 949 | // to do). This function will abort the process if running on a kernel | ||
| 950 | // that looks vulnerable. | ||
| 951 | #if SANITIZER_LINUX && SANITIZER_S390_64 | ||
| 952 | void AvoidCVE_2016_2143(); | ||
| 953 | #else | ||
| 954 | INLINE void AvoidCVE_2016_2143() {} | ||
| 955 | #endif | ||
| 956 | |||
| 957 | struct StackDepotStats { | ||
| 958 | uptr n_uniq_ids; | ||
| 959 | uptr allocated; | ||
| 960 | }; | ||
| 961 | |||
| 962 | // The default value for allocator_release_to_os_interval_ms common flag to | ||
| 963 | // indicate that sanitizer allocator should not attempt to release memory to OS. | ||
| 964 | const s32 kReleaseToOSIntervalNever = -1; | ||
| 965 | |||
| 966 | void CheckNoDeepBind(const char *filename, int flag); | ||
| 967 | |||
| 968 | // Returns the requested amount of random data (up to 256 bytes) that can then | ||
| 969 | // be used to seed a PRNG. Defaults to blocking like the underlying syscall. | ||
| 970 | bool GetRandom(void *buffer, uptr length, bool blocking = true); | ||
| 971 | |||
| 972 | // Returns the number of logical processors on the system. | ||
| 973 | u32 GetNumberOfCPUs(); | ||
| 974 | extern u32 NumberOfCPUsCached; | ||
| 975 | INLINE u32 GetNumberOfCPUsCached() { | ||
| 976 | if (!NumberOfCPUsCached) | ||
| 977 | NumberOfCPUsCached = GetNumberOfCPUs(); | ||
| 978 | return NumberOfCPUsCached; | ||
| 979 | } | ||
| 980 | |||
| 981 | template <typename T> | ||
| 982 | class ArrayRef { | ||
| 983 | public: | ||
| 984 | ArrayRef() {} | ||
| 985 | ArrayRef(T *begin, T *end) : begin_(begin), end_(end) {} | ||
| 986 | |||
| 987 | T *begin() { return begin_; } | ||
| 988 | T *end() { return end_; } | ||
| 989 | |||
| 990 | private: | ||
| 991 | T *begin_ = nullptr; | ||
| 992 | T *end_ = nullptr; | ||
| 993 | }; | ||
| 994 | |||
| 995 | } // namespace __sanitizer | ||
| 996 | |||
| 997 | inline void *operator new(__sanitizer::operator_new_size_type size, | ||
| 998 | __sanitizer::LowLevelAllocator &alloc) { // NOLINT | ||
| 999 | return alloc.Allocate(size); | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | #endif // SANITIZER_COMMON_H | ||
lib/tsan/sanitizer_common/sanitizer_common_interceptors.inc created+10175| ... | @@ -0,0 +1,10175 @@ | ||
| 1 | //===-- sanitizer_common_interceptors.inc -----------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Common function interceptors for tools like AddressSanitizer, | ||
| 10 | // ThreadSanitizer, MemorySanitizer, etc. | ||
| 11 | // | ||
| 12 | // This file should be included into the tool's interceptor file, | ||
| 13 | // which has to define its own macros: | ||
| 14 | // COMMON_INTERCEPTOR_ENTER | ||
| 15 | // COMMON_INTERCEPTOR_ENTER_NOIGNORE | ||
| 16 | // COMMON_INTERCEPTOR_READ_RANGE | ||
| 17 | // COMMON_INTERCEPTOR_WRITE_RANGE | ||
| 18 | // COMMON_INTERCEPTOR_INITIALIZE_RANGE | ||
| 19 | // COMMON_INTERCEPTOR_DIR_ACQUIRE | ||
| 20 | // COMMON_INTERCEPTOR_FD_ACQUIRE | ||
| 21 | // COMMON_INTERCEPTOR_FD_RELEASE | ||
| 22 | // COMMON_INTERCEPTOR_FD_ACCESS | ||
| 23 | // COMMON_INTERCEPTOR_SET_THREAD_NAME | ||
| 24 | // COMMON_INTERCEPTOR_ON_DLOPEN | ||
| 25 | // COMMON_INTERCEPTOR_ON_EXIT | ||
| 26 | // COMMON_INTERCEPTOR_MUTEX_PRE_LOCK | ||
| 27 | // COMMON_INTERCEPTOR_MUTEX_POST_LOCK | ||
| 28 | // COMMON_INTERCEPTOR_MUTEX_UNLOCK | ||
| 29 | // COMMON_INTERCEPTOR_MUTEX_REPAIR | ||
| 30 | // COMMON_INTERCEPTOR_SET_PTHREAD_NAME | ||
| 31 | // COMMON_INTERCEPTOR_HANDLE_RECVMSG | ||
| 32 | // COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED | ||
| 33 | // COMMON_INTERCEPTOR_MEMSET_IMPL | ||
| 34 | // COMMON_INTERCEPTOR_MEMMOVE_IMPL | ||
| 35 | // COMMON_INTERCEPTOR_MEMCPY_IMPL | ||
| 36 | // COMMON_INTERCEPTOR_MMAP_IMPL | ||
| 37 | // COMMON_INTERCEPTOR_COPY_STRING | ||
| 38 | // COMMON_INTERCEPTOR_STRNDUP_IMPL | ||
| 39 | // COMMON_INTERCEPTOR_STRERROR | ||
| 40 | //===----------------------------------------------------------------------===// | ||
| 41 | |||
| 42 | #include "interception/interception.h" | ||
| 43 | #include "sanitizer_addrhashmap.h" | ||
| 44 | #include "sanitizer_errno.h" | ||
| 45 | #include "sanitizer_placement_new.h" | ||
| 46 | #include "sanitizer_platform_interceptors.h" | ||
| 47 | #include "sanitizer_symbolizer.h" | ||
| 48 | #include "sanitizer_tls_get_addr.h" | ||
| 49 | |||
| 50 | #include <stdarg.h> | ||
| 51 | |||
| 52 | #if SANITIZER_INTERCEPTOR_HOOKS | ||
| 53 | #define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) f(__VA_ARGS__); | ||
| 54 | #define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \ | ||
| 55 | SANITIZER_INTERFACE_WEAK_DEF(void, f, __VA_ARGS__) {} | ||
| 56 | #else | ||
| 57 | #define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) | ||
| 58 | #define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) | ||
| 59 | |||
| 60 | #endif // SANITIZER_INTERCEPTOR_HOOKS | ||
| 61 | |||
| 62 | #if SANITIZER_WINDOWS && !defined(va_copy) | ||
| 63 | #define va_copy(dst, src) ((dst) = (src)) | ||
| 64 | #endif // _WIN32 | ||
| 65 | |||
| 66 | #if SANITIZER_FREEBSD | ||
| 67 | #define pthread_setname_np pthread_set_name_np | ||
| 68 | #define inet_aton __inet_aton | ||
| 69 | #define inet_pton __inet_pton | ||
| 70 | #define iconv __bsd_iconv | ||
| 71 | #endif | ||
| 72 | |||
| 73 | #if SANITIZER_NETBSD | ||
| 74 | #define clock_getres __clock_getres50 | ||
| 75 | #define clock_gettime __clock_gettime50 | ||
| 76 | #define clock_settime __clock_settime50 | ||
| 77 | #define ctime __ctime50 | ||
| 78 | #define ctime_r __ctime_r50 | ||
| 79 | #define devname __devname50 | ||
| 80 | #define fgetpos __fgetpos50 | ||
| 81 | #define fsetpos __fsetpos50 | ||
| 82 | #define fstatvfs __fstatvfs90 | ||
| 83 | #define fstatvfs1 __fstatvfs190 | ||
| 84 | #define fts_children __fts_children60 | ||
| 85 | #define fts_close __fts_close60 | ||
| 86 | #define fts_open __fts_open60 | ||
| 87 | #define fts_read __fts_read60 | ||
| 88 | #define fts_set __fts_set60 | ||
| 89 | #define getitimer __getitimer50 | ||
| 90 | #define getmntinfo __getmntinfo90 | ||
| 91 | #define getpwent __getpwent50 | ||
| 92 | #define getpwnam __getpwnam50 | ||
| 93 | #define getpwnam_r __getpwnam_r50 | ||
| 94 | #define getpwuid __getpwuid50 | ||
| 95 | #define getpwuid_r __getpwuid_r50 | ||
| 96 | #define getutent __getutent50 | ||
| 97 | #define getutxent __getutxent50 | ||
| 98 | #define getutxid __getutxid50 | ||
| 99 | #define getutxline __getutxline50 | ||
| 100 | #define getvfsstat __getvfsstat90 | ||
| 101 | #define pututxline __pututxline50 | ||
| 102 | #define glob __glob30 | ||
| 103 | #define gmtime __gmtime50 | ||
| 104 | #define gmtime_r __gmtime_r50 | ||
| 105 | #define localtime __locatime50 | ||
| 106 | #define localtime_r __localtime_r50 | ||
| 107 | #define mktime __mktime50 | ||
| 108 | #define lstat __lstat50 | ||
| 109 | #define opendir __opendir30 | ||
| 110 | #define readdir __readdir30 | ||
| 111 | #define readdir_r __readdir_r30 | ||
| 112 | #define scandir __scandir30 | ||
| 113 | #define setitimer __setitimer50 | ||
| 114 | #define setlocale __setlocale50 | ||
| 115 | #define shmctl __shmctl50 | ||
| 116 | #define sigaltstack __sigaltstack14 | ||
| 117 | #define sigemptyset __sigemptyset14 | ||
| 118 | #define sigfillset __sigfillset14 | ||
| 119 | #define sigpending __sigpending14 | ||
| 120 | #define sigprocmask __sigprocmask14 | ||
| 121 | #define sigtimedwait __sigtimedwait50 | ||
| 122 | #define stat __stat50 | ||
| 123 | #define statvfs __statvfs90 | ||
| 124 | #define statvfs1 __statvfs190 | ||
| 125 | #define time __time50 | ||
| 126 | #define times __times13 | ||
| 127 | #define unvis __unvis50 | ||
| 128 | #define wait3 __wait350 | ||
| 129 | #define wait4 __wait450 | ||
| 130 | extern const unsigned short *_ctype_tab_; | ||
| 131 | extern const short *_toupper_tab_; | ||
| 132 | extern const short *_tolower_tab_; | ||
| 133 | #endif | ||
| 134 | |||
| 135 | // Platform-specific options. | ||
| 136 | #if SANITIZER_MAC | ||
| 137 | #define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false | ||
| 138 | #elif SANITIZER_WINDOWS64 | ||
| 139 | #define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false | ||
| 140 | #else | ||
| 141 | #define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE true | ||
| 142 | #endif // SANITIZER_MAC | ||
| 143 | |||
| 144 | #ifndef COMMON_INTERCEPTOR_INITIALIZE_RANGE | ||
| 145 | #define COMMON_INTERCEPTOR_INITIALIZE_RANGE(p, size) {} | ||
| 146 | #endif | ||
| 147 | |||
| 148 | #ifndef COMMON_INTERCEPTOR_UNPOISON_PARAM | ||
| 149 | #define COMMON_INTERCEPTOR_UNPOISON_PARAM(count) {} | ||
| 150 | #endif | ||
| 151 | |||
| 152 | #ifndef COMMON_INTERCEPTOR_FD_ACCESS | ||
| 153 | #define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) {} | ||
| 154 | #endif | ||
| 155 | |||
| 156 | #ifndef COMMON_INTERCEPTOR_MUTEX_PRE_LOCK | ||
| 157 | #define COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m) {} | ||
| 158 | #endif | ||
| 159 | |||
| 160 | #ifndef COMMON_INTERCEPTOR_MUTEX_POST_LOCK | ||
| 161 | #define COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m) {} | ||
| 162 | #endif | ||
| 163 | |||
| 164 | #ifndef COMMON_INTERCEPTOR_MUTEX_UNLOCK | ||
| 165 | #define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) {} | ||
| 166 | #endif | ||
| 167 | |||
| 168 | #ifndef COMMON_INTERCEPTOR_MUTEX_REPAIR | ||
| 169 | #define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) {} | ||
| 170 | #endif | ||
| 171 | |||
| 172 | #ifndef COMMON_INTERCEPTOR_MUTEX_INVALID | ||
| 173 | #define COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m) {} | ||
| 174 | #endif | ||
| 175 | |||
| 176 | #ifndef COMMON_INTERCEPTOR_HANDLE_RECVMSG | ||
| 177 | #define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) ((void)(msg)) | ||
| 178 | #endif | ||
| 179 | |||
| 180 | #ifndef COMMON_INTERCEPTOR_FILE_OPEN | ||
| 181 | #define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) {} | ||
| 182 | #endif | ||
| 183 | |||
| 184 | #ifndef COMMON_INTERCEPTOR_FILE_CLOSE | ||
| 185 | #define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) {} | ||
| 186 | #endif | ||
| 187 | |||
| 188 | #ifndef COMMON_INTERCEPTOR_LIBRARY_LOADED | ||
| 189 | #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) {} | ||
| 190 | #endif | ||
| 191 | |||
| 192 | #ifndef COMMON_INTERCEPTOR_LIBRARY_UNLOADED | ||
| 193 | #define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() {} | ||
| 194 | #endif | ||
| 195 | |||
| 196 | #ifndef COMMON_INTERCEPTOR_ENTER_NOIGNORE | ||
| 197 | #define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, ...) \ | ||
| 198 | COMMON_INTERCEPTOR_ENTER(ctx, __VA_ARGS__) | ||
| 199 | #endif | ||
| 200 | |||
| 201 | #ifndef COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED | ||
| 202 | #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (0) | ||
| 203 | #endif | ||
| 204 | |||
| 205 | #define COMMON_INTERCEPTOR_READ_STRING(ctx, s, n) \ | ||
| 206 | COMMON_INTERCEPTOR_READ_RANGE((ctx), (s), \ | ||
| 207 | common_flags()->strict_string_checks ? (REAL(strlen)(s)) + 1 : (n) ) | ||
| 208 | |||
| 209 | #ifndef COMMON_INTERCEPTOR_ON_DLOPEN | ||
| 210 | #define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \ | ||
| 211 | CheckNoDeepBind(filename, flag); | ||
| 212 | #endif | ||
| 213 | |||
| 214 | #ifndef COMMON_INTERCEPTOR_GET_TLS_RANGE | ||
| 215 | #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) *begin = *end = 0; | ||
| 216 | #endif | ||
| 217 | |||
| 218 | #ifndef COMMON_INTERCEPTOR_ACQUIRE | ||
| 219 | #define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) {} | ||
| 220 | #endif | ||
| 221 | |||
| 222 | #ifndef COMMON_INTERCEPTOR_RELEASE | ||
| 223 | #define COMMON_INTERCEPTOR_RELEASE(ctx, u) {} | ||
| 224 | #endif | ||
| 225 | |||
| 226 | #ifndef COMMON_INTERCEPTOR_USER_CALLBACK_START | ||
| 227 | #define COMMON_INTERCEPTOR_USER_CALLBACK_START() {} | ||
| 228 | #endif | ||
| 229 | |||
| 230 | #ifndef COMMON_INTERCEPTOR_USER_CALLBACK_END | ||
| 231 | #define COMMON_INTERCEPTOR_USER_CALLBACK_END() {} | ||
| 232 | #endif | ||
| 233 | |||
| 234 | #ifdef SANITIZER_NLDBL_VERSION | ||
| 235 | #define COMMON_INTERCEPT_FUNCTION_LDBL(fn) \ | ||
| 236 | COMMON_INTERCEPT_FUNCTION_VER(fn, SANITIZER_NLDBL_VERSION) | ||
| 237 | #else | ||
| 238 | #define COMMON_INTERCEPT_FUNCTION_LDBL(fn) \ | ||
| 239 | COMMON_INTERCEPT_FUNCTION(fn) | ||
| 240 | #endif | ||
| 241 | |||
| 242 | #ifndef COMMON_INTERCEPTOR_MEMSET_IMPL | ||
| 243 | #define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size) \ | ||
| 244 | { \ | ||
| 245 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) \ | ||
| 246 | return internal_memset(dst, v, size); \ | ||
| 247 | COMMON_INTERCEPTOR_ENTER(ctx, memset, dst, v, size); \ | ||
| 248 | if (common_flags()->intercept_intrin) \ | ||
| 249 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \ | ||
| 250 | return REAL(memset)(dst, v, size); \ | ||
| 251 | } | ||
| 252 | #endif | ||
| 253 | |||
| 254 | #ifndef COMMON_INTERCEPTOR_MEMMOVE_IMPL | ||
| 255 | #define COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size) \ | ||
| 256 | { \ | ||
| 257 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) \ | ||
| 258 | return internal_memmove(dst, src, size); \ | ||
| 259 | COMMON_INTERCEPTOR_ENTER(ctx, memmove, dst, src, size); \ | ||
| 260 | if (common_flags()->intercept_intrin) { \ | ||
| 261 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \ | ||
| 262 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, size); \ | ||
| 263 | } \ | ||
| 264 | return REAL(memmove)(dst, src, size); \ | ||
| 265 | } | ||
| 266 | #endif | ||
| 267 | |||
| 268 | #ifndef COMMON_INTERCEPTOR_MEMCPY_IMPL | ||
| 269 | #define COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, dst, src, size) \ | ||
| 270 | { \ | ||
| 271 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) { \ | ||
| 272 | return internal_memmove(dst, src, size); \ | ||
| 273 | } \ | ||
| 274 | COMMON_INTERCEPTOR_ENTER(ctx, memcpy, dst, src, size); \ | ||
| 275 | if (common_flags()->intercept_intrin) { \ | ||
| 276 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \ | ||
| 277 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, size); \ | ||
| 278 | } \ | ||
| 279 | return REAL(memcpy)(dst, src, size); \ | ||
| 280 | } | ||
| 281 | #endif | ||
| 282 | |||
| 283 | #ifndef COMMON_INTERCEPTOR_MMAP_IMPL | ||
| 284 | #define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd, \ | ||
| 285 | off) \ | ||
| 286 | { return REAL(mmap)(addr, sz, prot, flags, fd, off); } | ||
| 287 | #endif | ||
| 288 | |||
| 289 | #ifndef COMMON_INTERCEPTOR_COPY_STRING | ||
| 290 | #define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) {} | ||
| 291 | #endif | ||
| 292 | |||
| 293 | #ifndef COMMON_INTERCEPTOR_STRNDUP_IMPL | ||
| 294 | #define COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size) \ | ||
| 295 | COMMON_INTERCEPTOR_ENTER(ctx, strndup, s, size); \ | ||
| 296 | uptr copy_length = internal_strnlen(s, size); \ | ||
| 297 | char *new_mem = (char *)WRAP(malloc)(copy_length + 1); \ | ||
| 298 | if (common_flags()->intercept_strndup) { \ | ||
| 299 | COMMON_INTERCEPTOR_READ_STRING(ctx, s, Min(size, copy_length + 1)); \ | ||
| 300 | } \ | ||
| 301 | COMMON_INTERCEPTOR_COPY_STRING(ctx, new_mem, s, copy_length); \ | ||
| 302 | internal_memcpy(new_mem, s, copy_length); \ | ||
| 303 | new_mem[copy_length] = '\0'; \ | ||
| 304 | return new_mem; | ||
| 305 | #endif | ||
| 306 | |||
| 307 | #ifndef COMMON_INTERCEPTOR_STRERROR | ||
| 308 | #define COMMON_INTERCEPTOR_STRERROR() {} | ||
| 309 | #endif | ||
| 310 | |||
| 311 | struct FileMetadata { | ||
| 312 | // For open_memstream(). | ||
| 313 | char **addr; | ||
| 314 | SIZE_T *size; | ||
| 315 | }; | ||
| 316 | |||
| 317 | struct CommonInterceptorMetadata { | ||
| 318 | enum { | ||
| 319 | CIMT_INVALID = 0, | ||
| 320 | CIMT_FILE | ||
| 321 | } type; | ||
| 322 | union { | ||
| 323 | FileMetadata file; | ||
| 324 | }; | ||
| 325 | }; | ||
| 326 | |||
| 327 | #if SI_POSIX | ||
| 328 | typedef AddrHashMap<CommonInterceptorMetadata, 31051> MetadataHashMap; | ||
| 329 | |||
| 330 | static MetadataHashMap *interceptor_metadata_map; | ||
| 331 | |||
| 332 | UNUSED static void SetInterceptorMetadata(__sanitizer_FILE *addr, | ||
| 333 | const FileMetadata &file) { | ||
| 334 | MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr); | ||
| 335 | CHECK(h.created()); | ||
| 336 | h->type = CommonInterceptorMetadata::CIMT_FILE; | ||
| 337 | h->file = file; | ||
| 338 | } | ||
| 339 | |||
| 340 | UNUSED static const FileMetadata *GetInterceptorMetadata( | ||
| 341 | __sanitizer_FILE *addr) { | ||
| 342 | MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr, | ||
| 343 | /* remove */ false, | ||
| 344 | /* create */ false); | ||
| 345 | if (addr && h.exists()) { | ||
| 346 | CHECK(!h.created()); | ||
| 347 | CHECK(h->type == CommonInterceptorMetadata::CIMT_FILE); | ||
| 348 | return &h->file; | ||
| 349 | } else { | ||
| 350 | return 0; | ||
| 351 | } | ||
| 352 | } | ||
| 353 | |||
| 354 | UNUSED static void DeleteInterceptorMetadata(void *addr) { | ||
| 355 | MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr, true); | ||
| 356 | CHECK(h.exists()); | ||
| 357 | } | ||
| 358 | #endif // SI_POSIX | ||
| 359 | |||
| 360 | #if SANITIZER_INTERCEPT_STRLEN | ||
| 361 | INTERCEPTOR(SIZE_T, strlen, const char *s) { | ||
| 362 | // Sometimes strlen is called prior to InitializeCommonInterceptors, | ||
| 363 | // in which case the REAL(strlen) typically used in | ||
| 364 | // COMMON_INTERCEPTOR_ENTER will fail. We use internal_strlen here | ||
| 365 | // to handle that. | ||
| 366 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) | ||
| 367 | return internal_strlen(s); | ||
| 368 | void *ctx; | ||
| 369 | COMMON_INTERCEPTOR_ENTER(ctx, strlen, s); | ||
| 370 | SIZE_T result = REAL(strlen)(s); | ||
| 371 | if (common_flags()->intercept_strlen) | ||
| 372 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s, result + 1); | ||
| 373 | return result; | ||
| 374 | } | ||
| 375 | #define INIT_STRLEN COMMON_INTERCEPT_FUNCTION(strlen) | ||
| 376 | #else | ||
| 377 | #define INIT_STRLEN | ||
| 378 | #endif | ||
| 379 | |||
| 380 | #if SANITIZER_INTERCEPT_STRNLEN | ||
| 381 | INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T maxlen) { | ||
| 382 | void *ctx; | ||
| 383 | COMMON_INTERCEPTOR_ENTER(ctx, strnlen, s, maxlen); | ||
| 384 | SIZE_T length = REAL(strnlen)(s, maxlen); | ||
| 385 | if (common_flags()->intercept_strlen) | ||
| 386 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s, Min(length + 1, maxlen)); | ||
| 387 | return length; | ||
| 388 | } | ||
| 389 | #define INIT_STRNLEN COMMON_INTERCEPT_FUNCTION(strnlen) | ||
| 390 | #else | ||
| 391 | #define INIT_STRNLEN | ||
| 392 | #endif | ||
| 393 | |||
| 394 | #if SANITIZER_INTERCEPT_STRNDUP | ||
| 395 | INTERCEPTOR(char*, strndup, const char *s, uptr size) { | ||
| 396 | void *ctx; | ||
| 397 | COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); | ||
| 398 | } | ||
| 399 | #define INIT_STRNDUP COMMON_INTERCEPT_FUNCTION(strndup) | ||
| 400 | #else | ||
| 401 | #define INIT_STRNDUP | ||
| 402 | #endif // SANITIZER_INTERCEPT_STRNDUP | ||
| 403 | |||
| 404 | #if SANITIZER_INTERCEPT___STRNDUP | ||
| 405 | INTERCEPTOR(char*, __strndup, const char *s, uptr size) { | ||
| 406 | void *ctx; | ||
| 407 | COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); | ||
| 408 | } | ||
| 409 | #define INIT___STRNDUP COMMON_INTERCEPT_FUNCTION(__strndup) | ||
| 410 | #else | ||
| 411 | #define INIT___STRNDUP | ||
| 412 | #endif // SANITIZER_INTERCEPT___STRNDUP | ||
| 413 | |||
| 414 | #if SANITIZER_INTERCEPT_TEXTDOMAIN | ||
| 415 | INTERCEPTOR(char*, textdomain, const char *domainname) { | ||
| 416 | void *ctx; | ||
| 417 | COMMON_INTERCEPTOR_ENTER(ctx, textdomain, domainname); | ||
| 418 | if (domainname) COMMON_INTERCEPTOR_READ_STRING(ctx, domainname, 0); | ||
| 419 | char *domain = REAL(textdomain)(domainname); | ||
| 420 | if (domain) { | ||
| 421 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(domain, REAL(strlen)(domain) + 1); | ||
| 422 | } | ||
| 423 | return domain; | ||
| 424 | } | ||
| 425 | #define INIT_TEXTDOMAIN COMMON_INTERCEPT_FUNCTION(textdomain) | ||
| 426 | #else | ||
| 427 | #define INIT_TEXTDOMAIN | ||
| 428 | #endif | ||
| 429 | |||
| 430 | #if SANITIZER_INTERCEPT_STRCMP | ||
| 431 | static inline int CharCmpX(unsigned char c1, unsigned char c2) { | ||
| 432 | return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1; | ||
| 433 | } | ||
| 434 | |||
| 435 | DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, uptr called_pc, | ||
| 436 | const char *s1, const char *s2, int result) | ||
| 437 | |||
| 438 | INTERCEPTOR(int, strcmp, const char *s1, const char *s2) { | ||
| 439 | void *ctx; | ||
| 440 | COMMON_INTERCEPTOR_ENTER(ctx, strcmp, s1, s2); | ||
| 441 | unsigned char c1, c2; | ||
| 442 | uptr i; | ||
| 443 | for (i = 0;; i++) { | ||
| 444 | c1 = (unsigned char)s1[i]; | ||
| 445 | c2 = (unsigned char)s2[i]; | ||
| 446 | if (c1 != c2 || c1 == '\0') break; | ||
| 447 | } | ||
| 448 | COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1); | ||
| 449 | COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1); | ||
| 450 | int result = CharCmpX(c1, c2); | ||
| 451 | CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, GET_CALLER_PC(), s1, | ||
| 452 | s2, result); | ||
| 453 | return result; | ||
| 454 | } | ||
| 455 | |||
| 456 | DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, uptr called_pc, | ||
| 457 | const char *s1, const char *s2, uptr n, | ||
| 458 | int result) | ||
| 459 | |||
| 460 | INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) { | ||
| 461 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) | ||
| 462 | return internal_strncmp(s1, s2, size); | ||
| 463 | void *ctx; | ||
| 464 | COMMON_INTERCEPTOR_ENTER(ctx, strncmp, s1, s2, size); | ||
| 465 | unsigned char c1 = 0, c2 = 0; | ||
| 466 | uptr i; | ||
| 467 | for (i = 0; i < size; i++) { | ||
| 468 | c1 = (unsigned char)s1[i]; | ||
| 469 | c2 = (unsigned char)s2[i]; | ||
| 470 | if (c1 != c2 || c1 == '\0') break; | ||
| 471 | } | ||
| 472 | uptr i1 = i; | ||
| 473 | uptr i2 = i; | ||
| 474 | if (common_flags()->strict_string_checks) { | ||
| 475 | for (; i1 < size && s1[i1]; i1++) {} | ||
| 476 | for (; i2 < size && s2[i2]; i2++) {} | ||
| 477 | } | ||
| 478 | COMMON_INTERCEPTOR_READ_RANGE((ctx), (s1), Min(i1 + 1, size)); | ||
| 479 | COMMON_INTERCEPTOR_READ_RANGE((ctx), (s2), Min(i2 + 1, size)); | ||
| 480 | int result = CharCmpX(c1, c2); | ||
| 481 | CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, GET_CALLER_PC(), s1, | ||
| 482 | s2, size, result); | ||
| 483 | return result; | ||
| 484 | } | ||
| 485 | |||
| 486 | #define INIT_STRCMP COMMON_INTERCEPT_FUNCTION(strcmp) | ||
| 487 | #define INIT_STRNCMP COMMON_INTERCEPT_FUNCTION(strncmp) | ||
| 488 | #else | ||
| 489 | #define INIT_STRCMP | ||
| 490 | #define INIT_STRNCMP | ||
| 491 | #endif | ||
| 492 | |||
| 493 | #if SANITIZER_INTERCEPT_STRCASECMP | ||
| 494 | static inline int CharCaseCmp(unsigned char c1, unsigned char c2) { | ||
| 495 | int c1_low = ToLower(c1); | ||
| 496 | int c2_low = ToLower(c2); | ||
| 497 | return c1_low - c2_low; | ||
| 498 | } | ||
| 499 | |||
| 500 | DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasecmp, uptr called_pc, | ||
| 501 | const char *s1, const char *s2, int result) | ||
| 502 | |||
| 503 | INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) { | ||
| 504 | void *ctx; | ||
| 505 | COMMON_INTERCEPTOR_ENTER(ctx, strcasecmp, s1, s2); | ||
| 506 | unsigned char c1 = 0, c2 = 0; | ||
| 507 | uptr i; | ||
| 508 | for (i = 0;; i++) { | ||
| 509 | c1 = (unsigned char)s1[i]; | ||
| 510 | c2 = (unsigned char)s2[i]; | ||
| 511 | if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break; | ||
| 512 | } | ||
| 513 | COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1); | ||
| 514 | COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1); | ||
| 515 | int result = CharCaseCmp(c1, c2); | ||
| 516 | CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasecmp, GET_CALLER_PC(), | ||
| 517 | s1, s2, result); | ||
| 518 | return result; | ||
| 519 | } | ||
| 520 | |||
| 521 | DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncasecmp, uptr called_pc, | ||
| 522 | const char *s1, const char *s2, uptr size, | ||
| 523 | int result) | ||
| 524 | |||
| 525 | INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T size) { | ||
| 526 | void *ctx; | ||
| 527 | COMMON_INTERCEPTOR_ENTER(ctx, strncasecmp, s1, s2, size); | ||
| 528 | unsigned char c1 = 0, c2 = 0; | ||
| 529 | uptr i; | ||
| 530 | for (i = 0; i < size; i++) { | ||
| 531 | c1 = (unsigned char)s1[i]; | ||
| 532 | c2 = (unsigned char)s2[i]; | ||
| 533 | if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break; | ||
| 534 | } | ||
| 535 | uptr i1 = i; | ||
| 536 | uptr i2 = i; | ||
| 537 | if (common_flags()->strict_string_checks) { | ||
| 538 | for (; i1 < size && s1[i1]; i1++) {} | ||
| 539 | for (; i2 < size && s2[i2]; i2++) {} | ||
| 540 | } | ||
| 541 | COMMON_INTERCEPTOR_READ_RANGE((ctx), (s1), Min(i1 + 1, size)); | ||
| 542 | COMMON_INTERCEPTOR_READ_RANGE((ctx), (s2), Min(i2 + 1, size)); | ||
| 543 | int result = CharCaseCmp(c1, c2); | ||
| 544 | CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncasecmp, GET_CALLER_PC(), | ||
| 545 | s1, s2, size, result); | ||
| 546 | return result; | ||
| 547 | } | ||
| 548 | |||
| 549 | #define INIT_STRCASECMP COMMON_INTERCEPT_FUNCTION(strcasecmp) | ||
| 550 | #define INIT_STRNCASECMP COMMON_INTERCEPT_FUNCTION(strncasecmp) | ||
| 551 | #else | ||
| 552 | #define INIT_STRCASECMP | ||
| 553 | #define INIT_STRNCASECMP | ||
| 554 | #endif | ||
| 555 | |||
| 556 | #if SANITIZER_INTERCEPT_STRSTR || SANITIZER_INTERCEPT_STRCASESTR | ||
| 557 | static inline void StrstrCheck(void *ctx, char *r, const char *s1, | ||
| 558 | const char *s2) { | ||
| 559 | uptr len1 = REAL(strlen)(s1); | ||
| 560 | uptr len2 = REAL(strlen)(s2); | ||
| 561 | COMMON_INTERCEPTOR_READ_STRING(ctx, s1, r ? r - s1 + len2 : len1 + 1); | ||
| 562 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, len2 + 1); | ||
| 563 | } | ||
| 564 | #endif | ||
| 565 | |||
| 566 | #if SANITIZER_INTERCEPT_STRSTR | ||
| 567 | |||
| 568 | DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strstr, uptr called_pc, | ||
| 569 | const char *s1, const char *s2, char *result) | ||
| 570 | |||
| 571 | INTERCEPTOR(char*, strstr, const char *s1, const char *s2) { | ||
| 572 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) | ||
| 573 | return internal_strstr(s1, s2); | ||
| 574 | void *ctx; | ||
| 575 | COMMON_INTERCEPTOR_ENTER(ctx, strstr, s1, s2); | ||
| 576 | char *r = REAL(strstr)(s1, s2); | ||
| 577 | if (common_flags()->intercept_strstr) | ||
| 578 | StrstrCheck(ctx, r, s1, s2); | ||
| 579 | CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strstr, GET_CALLER_PC(), s1, | ||
| 580 | s2, r); | ||
| 581 | return r; | ||
| 582 | } | ||
| 583 | |||
| 584 | #define INIT_STRSTR COMMON_INTERCEPT_FUNCTION(strstr); | ||
| 585 | #else | ||
| 586 | #define INIT_STRSTR | ||
| 587 | #endif | ||
| 588 | |||
| 589 | #if SANITIZER_INTERCEPT_STRCASESTR | ||
| 590 | |||
| 591 | DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasestr, uptr called_pc, | ||
| 592 | const char *s1, const char *s2, char *result) | ||
| 593 | |||
| 594 | INTERCEPTOR(char*, strcasestr, const char *s1, const char *s2) { | ||
| 595 | void *ctx; | ||
| 596 | COMMON_INTERCEPTOR_ENTER(ctx, strcasestr, s1, s2); | ||
| 597 | char *r = REAL(strcasestr)(s1, s2); | ||
| 598 | if (common_flags()->intercept_strstr) | ||
| 599 | StrstrCheck(ctx, r, s1, s2); | ||
| 600 | CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasestr, GET_CALLER_PC(), | ||
| 601 | s1, s2, r); | ||
| 602 | return r; | ||
| 603 | } | ||
| 604 | |||
| 605 | #define INIT_STRCASESTR COMMON_INTERCEPT_FUNCTION(strcasestr); | ||
| 606 | #else | ||
| 607 | #define INIT_STRCASESTR | ||
| 608 | #endif | ||
| 609 | |||
| 610 | #if SANITIZER_INTERCEPT_STRTOK | ||
| 611 | |||
| 612 | INTERCEPTOR(char*, strtok, char *str, const char *delimiters) { | ||
| 613 | void *ctx; | ||
| 614 | COMMON_INTERCEPTOR_ENTER(ctx, strtok, str, delimiters); | ||
| 615 | if (!common_flags()->intercept_strtok) { | ||
| 616 | return REAL(strtok)(str, delimiters); | ||
| 617 | } | ||
| 618 | if (common_flags()->strict_string_checks) { | ||
| 619 | // If strict_string_checks is enabled, we check the whole first argument | ||
| 620 | // string on the first call (strtok saves this string in a static buffer | ||
| 621 | // for subsequent calls). We do not need to check strtok's result. | ||
| 622 | // As the delimiters can change, we check them every call. | ||
| 623 | if (str != nullptr) { | ||
| 624 | COMMON_INTERCEPTOR_READ_RANGE(ctx, str, REAL(strlen)(str) + 1); | ||
| 625 | } | ||
| 626 | COMMON_INTERCEPTOR_READ_RANGE(ctx, delimiters, | ||
| 627 | REAL(strlen)(delimiters) + 1); | ||
| 628 | return REAL(strtok)(str, delimiters); | ||
| 629 | } else { | ||
| 630 | // However, when strict_string_checks is disabled we cannot check the | ||
| 631 | // whole string on the first call. Instead, we check the result string | ||
| 632 | // which is guaranteed to be a NULL-terminated substring of the first | ||
| 633 | // argument. We also conservatively check one character of str and the | ||
| 634 | // delimiters. | ||
| 635 | if (str != nullptr) { | ||
| 636 | COMMON_INTERCEPTOR_READ_STRING(ctx, str, 1); | ||
| 637 | } | ||
| 638 | COMMON_INTERCEPTOR_READ_RANGE(ctx, delimiters, 1); | ||
| 639 | char *result = REAL(strtok)(str, delimiters); | ||
| 640 | if (result != nullptr) { | ||
| 641 | COMMON_INTERCEPTOR_READ_RANGE(ctx, result, REAL(strlen)(result) + 1); | ||
| 642 | } else if (str != nullptr) { | ||
| 643 | // No delimiter were found, it's safe to assume that the entire str was | ||
| 644 | // scanned. | ||
| 645 | COMMON_INTERCEPTOR_READ_RANGE(ctx, str, REAL(strlen)(str) + 1); | ||
| 646 | } | ||
| 647 | return result; | ||
| 648 | } | ||
| 649 | } | ||
| 650 | |||
| 651 | #define INIT_STRTOK COMMON_INTERCEPT_FUNCTION(strtok) | ||
| 652 | #else | ||
| 653 | #define INIT_STRTOK | ||
| 654 | #endif | ||
| 655 | |||
| 656 | #if SANITIZER_INTERCEPT_MEMMEM | ||
| 657 | DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memmem, uptr called_pc, | ||
| 658 | const void *s1, SIZE_T len1, const void *s2, | ||
| 659 | SIZE_T len2, void *result) | ||
| 660 | |||
| 661 | INTERCEPTOR(void*, memmem, const void *s1, SIZE_T len1, const void *s2, | ||
| 662 | SIZE_T len2) { | ||
| 663 | void *ctx; | ||
| 664 | COMMON_INTERCEPTOR_ENTER(ctx, memmem, s1, len1, s2, len2); | ||
| 665 | void *r = REAL(memmem)(s1, len1, s2, len2); | ||
| 666 | if (common_flags()->intercept_memmem) { | ||
| 667 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, len1); | ||
| 668 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, len2); | ||
| 669 | } | ||
| 670 | CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memmem, GET_CALLER_PC(), | ||
| 671 | s1, len1, s2, len2, r); | ||
| 672 | return r; | ||
| 673 | } | ||
| 674 | |||
| 675 | #define INIT_MEMMEM COMMON_INTERCEPT_FUNCTION(memmem); | ||
| 676 | #else | ||
| 677 | #define INIT_MEMMEM | ||
| 678 | #endif // SANITIZER_INTERCEPT_MEMMEM | ||
| 679 | |||
| 680 | #if SANITIZER_INTERCEPT_STRCHR | ||
| 681 | INTERCEPTOR(char*, strchr, const char *s, int c) { | ||
| 682 | void *ctx; | ||
| 683 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) | ||
| 684 | return internal_strchr(s, c); | ||
| 685 | COMMON_INTERCEPTOR_ENTER(ctx, strchr, s, c); | ||
| 686 | char *result = REAL(strchr)(s, c); | ||
| 687 | if (common_flags()->intercept_strchr) { | ||
| 688 | // Keep strlen as macro argument, as macro may ignore it. | ||
| 689 | COMMON_INTERCEPTOR_READ_STRING(ctx, s, | ||
| 690 | (result ? result - s : REAL(strlen)(s)) + 1); | ||
| 691 | } | ||
| 692 | return result; | ||
| 693 | } | ||
| 694 | #define INIT_STRCHR COMMON_INTERCEPT_FUNCTION(strchr) | ||
| 695 | #else | ||
| 696 | #define INIT_STRCHR | ||
| 697 | #endif | ||
| 698 | |||
| 699 | #if SANITIZER_INTERCEPT_STRCHRNUL | ||
| 700 | INTERCEPTOR(char*, strchrnul, const char *s, int c) { | ||
| 701 | void *ctx; | ||
| 702 | COMMON_INTERCEPTOR_ENTER(ctx, strchrnul, s, c); | ||
| 703 | char *result = REAL(strchrnul)(s, c); | ||
| 704 | uptr len = result - s + 1; | ||
| 705 | if (common_flags()->intercept_strchr) | ||
| 706 | COMMON_INTERCEPTOR_READ_STRING(ctx, s, len); | ||
| 707 | return result; | ||
| 708 | } | ||
| 709 | #define INIT_STRCHRNUL COMMON_INTERCEPT_FUNCTION(strchrnul) | ||
| 710 | #else | ||
| 711 | #define INIT_STRCHRNUL | ||
| 712 | #endif | ||
| 713 | |||
| 714 | #if SANITIZER_INTERCEPT_STRRCHR | ||
| 715 | INTERCEPTOR(char*, strrchr, const char *s, int c) { | ||
| 716 | void *ctx; | ||
| 717 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) | ||
| 718 | return internal_strrchr(s, c); | ||
| 719 | COMMON_INTERCEPTOR_ENTER(ctx, strrchr, s, c); | ||
| 720 | if (common_flags()->intercept_strchr) | ||
| 721 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1); | ||
| 722 | return REAL(strrchr)(s, c); | ||
| 723 | } | ||
| 724 | #define INIT_STRRCHR COMMON_INTERCEPT_FUNCTION(strrchr) | ||
| 725 | #else | ||
| 726 | #define INIT_STRRCHR | ||
| 727 | #endif | ||
| 728 | |||
| 729 | #if SANITIZER_INTERCEPT_STRSPN | ||
| 730 | INTERCEPTOR(SIZE_T, strspn, const char *s1, const char *s2) { | ||
| 731 | void *ctx; | ||
| 732 | COMMON_INTERCEPTOR_ENTER(ctx, strspn, s1, s2); | ||
| 733 | SIZE_T r = REAL(strspn)(s1, s2); | ||
| 734 | if (common_flags()->intercept_strspn) { | ||
| 735 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, REAL(strlen)(s2) + 1); | ||
| 736 | COMMON_INTERCEPTOR_READ_STRING(ctx, s1, r + 1); | ||
| 737 | } | ||
| 738 | return r; | ||
| 739 | } | ||
| 740 | |||
| 741 | INTERCEPTOR(SIZE_T, strcspn, const char *s1, const char *s2) { | ||
| 742 | void *ctx; | ||
| 743 | COMMON_INTERCEPTOR_ENTER(ctx, strcspn, s1, s2); | ||
| 744 | SIZE_T r = REAL(strcspn)(s1, s2); | ||
| 745 | if (common_flags()->intercept_strspn) { | ||
| 746 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, REAL(strlen)(s2) + 1); | ||
| 747 | COMMON_INTERCEPTOR_READ_STRING(ctx, s1, r + 1); | ||
| 748 | } | ||
| 749 | return r; | ||
| 750 | } | ||
| 751 | |||
| 752 | #define INIT_STRSPN \ | ||
| 753 | COMMON_INTERCEPT_FUNCTION(strspn); \ | ||
| 754 | COMMON_INTERCEPT_FUNCTION(strcspn); | ||
| 755 | #else | ||
| 756 | #define INIT_STRSPN | ||
| 757 | #endif | ||
| 758 | |||
| 759 | #if SANITIZER_INTERCEPT_STRPBRK | ||
| 760 | INTERCEPTOR(char *, strpbrk, const char *s1, const char *s2) { | ||
| 761 | void *ctx; | ||
| 762 | COMMON_INTERCEPTOR_ENTER(ctx, strpbrk, s1, s2); | ||
| 763 | char *r = REAL(strpbrk)(s1, s2); | ||
| 764 | if (common_flags()->intercept_strpbrk) { | ||
| 765 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, REAL(strlen)(s2) + 1); | ||
| 766 | COMMON_INTERCEPTOR_READ_STRING(ctx, s1, | ||
| 767 | r ? r - s1 + 1 : REAL(strlen)(s1) + 1); | ||
| 768 | } | ||
| 769 | return r; | ||
| 770 | } | ||
| 771 | |||
| 772 | #define INIT_STRPBRK COMMON_INTERCEPT_FUNCTION(strpbrk); | ||
| 773 | #else | ||
| 774 | #define INIT_STRPBRK | ||
| 775 | #endif | ||
| 776 | |||
| 777 | #if SANITIZER_INTERCEPT_MEMSET | ||
| 778 | INTERCEPTOR(void *, memset, void *dst, int v, uptr size) { | ||
| 779 | void *ctx; | ||
| 780 | COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size); | ||
| 781 | } | ||
| 782 | |||
| 783 | #define INIT_MEMSET COMMON_INTERCEPT_FUNCTION(memset) | ||
| 784 | #else | ||
| 785 | #define INIT_MEMSET | ||
| 786 | #endif | ||
| 787 | |||
| 788 | #if SANITIZER_INTERCEPT_MEMMOVE | ||
| 789 | INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) { | ||
| 790 | void *ctx; | ||
| 791 | COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size); | ||
| 792 | } | ||
| 793 | |||
| 794 | #define INIT_MEMMOVE COMMON_INTERCEPT_FUNCTION(memmove) | ||
| 795 | #else | ||
| 796 | #define INIT_MEMMOVE | ||
| 797 | #endif | ||
| 798 | |||
| 799 | #if SANITIZER_INTERCEPT_MEMCPY | ||
| 800 | INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) { | ||
| 801 | // On OS X, calling internal_memcpy here will cause memory corruptions, | ||
| 802 | // because memcpy and memmove are actually aliases of the same | ||
| 803 | // implementation. We need to use internal_memmove here. | ||
| 804 | // N.B.: If we switch this to internal_ we'll have to use internal_memmove | ||
| 805 | // due to memcpy being an alias of memmove on OS X. | ||
| 806 | void *ctx; | ||
| 807 | if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) { | ||
| 808 | COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, dst, src, size); | ||
| 809 | } else { | ||
| 810 | COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size); | ||
| 811 | } | ||
| 812 | } | ||
| 813 | |||
| 814 | #define INIT_MEMCPY \ | ||
| 815 | do { \ | ||
| 816 | if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) { \ | ||
| 817 | COMMON_INTERCEPT_FUNCTION(memcpy); \ | ||
| 818 | } else { \ | ||
| 819 | ASSIGN_REAL(memcpy, memmove); \ | ||
| 820 | } \ | ||
| 821 | CHECK(REAL(memcpy)); \ | ||
| 822 | } while (false) | ||
| 823 | |||
| 824 | #else | ||
| 825 | #define INIT_MEMCPY | ||
| 826 | #endif | ||
| 827 | |||
| 828 | #if SANITIZER_INTERCEPT_MEMCMP | ||
| 829 | DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, uptr called_pc, | ||
| 830 | const void *s1, const void *s2, uptr n, | ||
| 831 | int result) | ||
| 832 | |||
| 833 | // Common code for `memcmp` and `bcmp`. | ||
| 834 | int MemcmpInterceptorCommon(void *ctx, | ||
| 835 | int (*real_fn)(const void *, const void *, uptr), | ||
| 836 | const void *a1, const void *a2, uptr size) { | ||
| 837 | if (common_flags()->intercept_memcmp) { | ||
| 838 | if (common_flags()->strict_memcmp) { | ||
| 839 | // Check the entire regions even if the first bytes of the buffers are | ||
| 840 | // different. | ||
| 841 | COMMON_INTERCEPTOR_READ_RANGE(ctx, a1, size); | ||
| 842 | COMMON_INTERCEPTOR_READ_RANGE(ctx, a2, size); | ||
| 843 | // Fallthrough to REAL(memcmp) below. | ||
| 844 | } else { | ||
| 845 | unsigned char c1 = 0, c2 = 0; | ||
| 846 | const unsigned char *s1 = (const unsigned char*)a1; | ||
| 847 | const unsigned char *s2 = (const unsigned char*)a2; | ||
| 848 | uptr i; | ||
| 849 | for (i = 0; i < size; i++) { | ||
| 850 | c1 = s1[i]; | ||
| 851 | c2 = s2[i]; | ||
| 852 | if (c1 != c2) break; | ||
| 853 | } | ||
| 854 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, size)); | ||
| 855 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, size)); | ||
| 856 | int r = CharCmpX(c1, c2); | ||
| 857 | CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, GET_CALLER_PC(), | ||
| 858 | a1, a2, size, r); | ||
| 859 | return r; | ||
| 860 | } | ||
| 861 | } | ||
| 862 | int result = real_fn(a1, a2, size); | ||
| 863 | CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, GET_CALLER_PC(), a1, | ||
| 864 | a2, size, result); | ||
| 865 | return result; | ||
| 866 | } | ||
| 867 | |||
| 868 | INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) { | ||
| 869 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) | ||
| 870 | return internal_memcmp(a1, a2, size); | ||
| 871 | void *ctx; | ||
| 872 | COMMON_INTERCEPTOR_ENTER(ctx, memcmp, a1, a2, size); | ||
| 873 | return MemcmpInterceptorCommon(ctx, REAL(memcmp), a1, a2, size); | ||
| 874 | } | ||
| 875 | |||
| 876 | #define INIT_MEMCMP COMMON_INTERCEPT_FUNCTION(memcmp) | ||
| 877 | #else | ||
| 878 | #define INIT_MEMCMP | ||
| 879 | #endif | ||
| 880 | |||
| 881 | #if SANITIZER_INTERCEPT_BCMP | ||
| 882 | INTERCEPTOR(int, bcmp, const void *a1, const void *a2, uptr size) { | ||
| 883 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) | ||
| 884 | return internal_memcmp(a1, a2, size); | ||
| 885 | void *ctx; | ||
| 886 | COMMON_INTERCEPTOR_ENTER(ctx, bcmp, a1, a2, size); | ||
| 887 | return MemcmpInterceptorCommon(ctx, REAL(bcmp), a1, a2, size); | ||
| 888 | } | ||
| 889 | |||
| 890 | #define INIT_BCMP COMMON_INTERCEPT_FUNCTION(bcmp) | ||
| 891 | #else | ||
| 892 | #define INIT_BCMP | ||
| 893 | #endif | ||
| 894 | |||
| 895 | #if SANITIZER_INTERCEPT_MEMCHR | ||
| 896 | INTERCEPTOR(void*, memchr, const void *s, int c, SIZE_T n) { | ||
| 897 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) | ||
| 898 | return internal_memchr(s, c, n); | ||
| 899 | void *ctx; | ||
| 900 | COMMON_INTERCEPTOR_ENTER(ctx, memchr, s, c, n); | ||
| 901 | #if SANITIZER_WINDOWS | ||
| 902 | void *res; | ||
| 903 | if (REAL(memchr)) { | ||
| 904 | res = REAL(memchr)(s, c, n); | ||
| 905 | } else { | ||
| 906 | res = internal_memchr(s, c, n); | ||
| 907 | } | ||
| 908 | #else | ||
| 909 | void *res = REAL(memchr)(s, c, n); | ||
| 910 | #endif | ||
| 911 | uptr len = res ? (char *)res - (const char *)s + 1 : n; | ||
| 912 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s, len); | ||
| 913 | return res; | ||
| 914 | } | ||
| 915 | |||
| 916 | #define INIT_MEMCHR COMMON_INTERCEPT_FUNCTION(memchr) | ||
| 917 | #else | ||
| 918 | #define INIT_MEMCHR | ||
| 919 | #endif | ||
| 920 | |||
| 921 | #if SANITIZER_INTERCEPT_MEMRCHR | ||
| 922 | INTERCEPTOR(void*, memrchr, const void *s, int c, SIZE_T n) { | ||
| 923 | void *ctx; | ||
| 924 | COMMON_INTERCEPTOR_ENTER(ctx, memrchr, s, c, n); | ||
| 925 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s, n); | ||
| 926 | return REAL(memrchr)(s, c, n); | ||
| 927 | } | ||
| 928 | |||
| 929 | #define INIT_MEMRCHR COMMON_INTERCEPT_FUNCTION(memrchr) | ||
| 930 | #else | ||
| 931 | #define INIT_MEMRCHR | ||
| 932 | #endif | ||
| 933 | |||
| 934 | #if SANITIZER_INTERCEPT_FREXP | ||
| 935 | INTERCEPTOR(double, frexp, double x, int *exp) { | ||
| 936 | void *ctx; | ||
| 937 | COMMON_INTERCEPTOR_ENTER(ctx, frexp, x, exp); | ||
| 938 | // Assuming frexp() always writes to |exp|. | ||
| 939 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp)); | ||
| 940 | double res = REAL(frexp)(x, exp); | ||
| 941 | return res; | ||
| 942 | } | ||
| 943 | |||
| 944 | #define INIT_FREXP COMMON_INTERCEPT_FUNCTION(frexp); | ||
| 945 | #else | ||
| 946 | #define INIT_FREXP | ||
| 947 | #endif // SANITIZER_INTERCEPT_FREXP | ||
| 948 | |||
| 949 | #if SANITIZER_INTERCEPT_FREXPF_FREXPL | ||
| 950 | INTERCEPTOR(float, frexpf, float x, int *exp) { | ||
| 951 | void *ctx; | ||
| 952 | COMMON_INTERCEPTOR_ENTER(ctx, frexpf, x, exp); | ||
| 953 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 954 | // its metadata. See | ||
| 955 | // https://github.com/google/sanitizers/issues/321. | ||
| 956 | float res = REAL(frexpf)(x, exp); | ||
| 957 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp)); | ||
| 958 | return res; | ||
| 959 | } | ||
| 960 | |||
| 961 | INTERCEPTOR(long double, frexpl, long double x, int *exp) { | ||
| 962 | void *ctx; | ||
| 963 | COMMON_INTERCEPTOR_ENTER(ctx, frexpl, x, exp); | ||
| 964 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 965 | // its metadata. See | ||
| 966 | // https://github.com/google/sanitizers/issues/321. | ||
| 967 | long double res = REAL(frexpl)(x, exp); | ||
| 968 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp)); | ||
| 969 | return res; | ||
| 970 | } | ||
| 971 | |||
| 972 | #define INIT_FREXPF_FREXPL \ | ||
| 973 | COMMON_INTERCEPT_FUNCTION(frexpf); \ | ||
| 974 | COMMON_INTERCEPT_FUNCTION_LDBL(frexpl) | ||
| 975 | #else | ||
| 976 | #define INIT_FREXPF_FREXPL | ||
| 977 | #endif // SANITIZER_INTERCEPT_FREXPF_FREXPL | ||
| 978 | |||
| 979 | #if SI_POSIX | ||
| 980 | static void write_iovec(void *ctx, struct __sanitizer_iovec *iovec, | ||
| 981 | SIZE_T iovlen, SIZE_T maxlen) { | ||
| 982 | for (SIZE_T i = 0; i < iovlen && maxlen; ++i) { | ||
| 983 | SSIZE_T sz = Min(iovec[i].iov_len, maxlen); | ||
| 984 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec[i].iov_base, sz); | ||
| 985 | maxlen -= sz; | ||
| 986 | } | ||
| 987 | } | ||
| 988 | |||
| 989 | static void read_iovec(void *ctx, struct __sanitizer_iovec *iovec, | ||
| 990 | SIZE_T iovlen, SIZE_T maxlen) { | ||
| 991 | COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec) * iovlen); | ||
| 992 | for (SIZE_T i = 0; i < iovlen && maxlen; ++i) { | ||
| 993 | SSIZE_T sz = Min(iovec[i].iov_len, maxlen); | ||
| 994 | COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec[i].iov_base, sz); | ||
| 995 | maxlen -= sz; | ||
| 996 | } | ||
| 997 | } | ||
| 998 | #endif | ||
| 999 | |||
| 1000 | #if SANITIZER_INTERCEPT_READ | ||
| 1001 | INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) { | ||
| 1002 | void *ctx; | ||
| 1003 | COMMON_INTERCEPTOR_ENTER(ctx, read, fd, ptr, count); | ||
| 1004 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 1005 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 1006 | // its metadata. See | ||
| 1007 | // https://github.com/google/sanitizers/issues/321. | ||
| 1008 | SSIZE_T res = REAL(read)(fd, ptr, count); | ||
| 1009 | if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res); | ||
| 1010 | if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 1011 | return res; | ||
| 1012 | } | ||
| 1013 | #define INIT_READ COMMON_INTERCEPT_FUNCTION(read) | ||
| 1014 | #else | ||
| 1015 | #define INIT_READ | ||
| 1016 | #endif | ||
| 1017 | |||
| 1018 | #if SANITIZER_INTERCEPT_FREAD | ||
| 1019 | INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) { | ||
| 1020 | // libc file streams can call user-supplied functions, see fopencookie. | ||
| 1021 | void *ctx; | ||
| 1022 | COMMON_INTERCEPTOR_ENTER(ctx, fread, ptr, size, nmemb, file); | ||
| 1023 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 1024 | // its metadata. See | ||
| 1025 | // https://github.com/google/sanitizers/issues/321. | ||
| 1026 | SIZE_T res = REAL(fread)(ptr, size, nmemb, file); | ||
| 1027 | if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res * size); | ||
| 1028 | return res; | ||
| 1029 | } | ||
| 1030 | #define INIT_FREAD COMMON_INTERCEPT_FUNCTION(fread) | ||
| 1031 | #else | ||
| 1032 | #define INIT_FREAD | ||
| 1033 | #endif | ||
| 1034 | |||
| 1035 | #if SANITIZER_INTERCEPT_PREAD | ||
| 1036 | INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) { | ||
| 1037 | void *ctx; | ||
| 1038 | COMMON_INTERCEPTOR_ENTER(ctx, pread, fd, ptr, count, offset); | ||
| 1039 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 1040 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 1041 | // its metadata. See | ||
| 1042 | // https://github.com/google/sanitizers/issues/321. | ||
| 1043 | SSIZE_T res = REAL(pread)(fd, ptr, count, offset); | ||
| 1044 | if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res); | ||
| 1045 | if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 1046 | return res; | ||
| 1047 | } | ||
| 1048 | #define INIT_PREAD COMMON_INTERCEPT_FUNCTION(pread) | ||
| 1049 | #else | ||
| 1050 | #define INIT_PREAD | ||
| 1051 | #endif | ||
| 1052 | |||
| 1053 | #if SANITIZER_INTERCEPT_PREAD64 | ||
| 1054 | INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) { | ||
| 1055 | void *ctx; | ||
| 1056 | COMMON_INTERCEPTOR_ENTER(ctx, pread64, fd, ptr, count, offset); | ||
| 1057 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 1058 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 1059 | // its metadata. See | ||
| 1060 | // https://github.com/google/sanitizers/issues/321. | ||
| 1061 | SSIZE_T res = REAL(pread64)(fd, ptr, count, offset); | ||
| 1062 | if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res); | ||
| 1063 | if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 1064 | return res; | ||
| 1065 | } | ||
| 1066 | #define INIT_PREAD64 COMMON_INTERCEPT_FUNCTION(pread64) | ||
| 1067 | #else | ||
| 1068 | #define INIT_PREAD64 | ||
| 1069 | #endif | ||
| 1070 | |||
| 1071 | #if SANITIZER_INTERCEPT_READV | ||
| 1072 | INTERCEPTOR_WITH_SUFFIX(SSIZE_T, readv, int fd, __sanitizer_iovec *iov, | ||
| 1073 | int iovcnt) { | ||
| 1074 | void *ctx; | ||
| 1075 | COMMON_INTERCEPTOR_ENTER(ctx, readv, fd, iov, iovcnt); | ||
| 1076 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 1077 | SSIZE_T res = REAL(readv)(fd, iov, iovcnt); | ||
| 1078 | if (res > 0) write_iovec(ctx, iov, iovcnt, res); | ||
| 1079 | if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 1080 | return res; | ||
| 1081 | } | ||
| 1082 | #define INIT_READV COMMON_INTERCEPT_FUNCTION(readv) | ||
| 1083 | #else | ||
| 1084 | #define INIT_READV | ||
| 1085 | #endif | ||
| 1086 | |||
| 1087 | #if SANITIZER_INTERCEPT_PREADV | ||
| 1088 | INTERCEPTOR(SSIZE_T, preadv, int fd, __sanitizer_iovec *iov, int iovcnt, | ||
| 1089 | OFF_T offset) { | ||
| 1090 | void *ctx; | ||
| 1091 | COMMON_INTERCEPTOR_ENTER(ctx, preadv, fd, iov, iovcnt, offset); | ||
| 1092 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 1093 | SSIZE_T res = REAL(preadv)(fd, iov, iovcnt, offset); | ||
| 1094 | if (res > 0) write_iovec(ctx, iov, iovcnt, res); | ||
| 1095 | if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 1096 | return res; | ||
| 1097 | } | ||
| 1098 | #define INIT_PREADV COMMON_INTERCEPT_FUNCTION(preadv) | ||
| 1099 | #else | ||
| 1100 | #define INIT_PREADV | ||
| 1101 | #endif | ||
| 1102 | |||
| 1103 | #if SANITIZER_INTERCEPT_PREADV64 | ||
| 1104 | INTERCEPTOR(SSIZE_T, preadv64, int fd, __sanitizer_iovec *iov, int iovcnt, | ||
| 1105 | OFF64_T offset) { | ||
| 1106 | void *ctx; | ||
| 1107 | COMMON_INTERCEPTOR_ENTER(ctx, preadv64, fd, iov, iovcnt, offset); | ||
| 1108 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 1109 | SSIZE_T res = REAL(preadv64)(fd, iov, iovcnt, offset); | ||
| 1110 | if (res > 0) write_iovec(ctx, iov, iovcnt, res); | ||
| 1111 | if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 1112 | return res; | ||
| 1113 | } | ||
| 1114 | #define INIT_PREADV64 COMMON_INTERCEPT_FUNCTION(preadv64) | ||
| 1115 | #else | ||
| 1116 | #define INIT_PREADV64 | ||
| 1117 | #endif | ||
| 1118 | |||
| 1119 | #if SANITIZER_INTERCEPT_WRITE | ||
| 1120 | INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) { | ||
| 1121 | void *ctx; | ||
| 1122 | COMMON_INTERCEPTOR_ENTER(ctx, write, fd, ptr, count); | ||
| 1123 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 1124 | if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); | ||
| 1125 | SSIZE_T res = REAL(write)(fd, ptr, count); | ||
| 1126 | // FIXME: this check should be _before_ the call to REAL(write), not after | ||
| 1127 | if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res); | ||
| 1128 | return res; | ||
| 1129 | } | ||
| 1130 | #define INIT_WRITE COMMON_INTERCEPT_FUNCTION(write) | ||
| 1131 | #else | ||
| 1132 | #define INIT_WRITE | ||
| 1133 | #endif | ||
| 1134 | |||
| 1135 | #if SANITIZER_INTERCEPT_FWRITE | ||
| 1136 | INTERCEPTOR(SIZE_T, fwrite, const void *p, uptr size, uptr nmemb, void *file) { | ||
| 1137 | // libc file streams can call user-supplied functions, see fopencookie. | ||
| 1138 | void *ctx; | ||
| 1139 | COMMON_INTERCEPTOR_ENTER(ctx, fwrite, p, size, nmemb, file); | ||
| 1140 | SIZE_T res = REAL(fwrite)(p, size, nmemb, file); | ||
| 1141 | if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, p, res * size); | ||
| 1142 | return res; | ||
| 1143 | } | ||
| 1144 | #define INIT_FWRITE COMMON_INTERCEPT_FUNCTION(fwrite) | ||
| 1145 | #else | ||
| 1146 | #define INIT_FWRITE | ||
| 1147 | #endif | ||
| 1148 | |||
| 1149 | #if SANITIZER_INTERCEPT_PWRITE | ||
| 1150 | INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count, OFF_T offset) { | ||
| 1151 | void *ctx; | ||
| 1152 | COMMON_INTERCEPTOR_ENTER(ctx, pwrite, fd, ptr, count, offset); | ||
| 1153 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 1154 | if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); | ||
| 1155 | SSIZE_T res = REAL(pwrite)(fd, ptr, count, offset); | ||
| 1156 | if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res); | ||
| 1157 | return res; | ||
| 1158 | } | ||
| 1159 | #define INIT_PWRITE COMMON_INTERCEPT_FUNCTION(pwrite) | ||
| 1160 | #else | ||
| 1161 | #define INIT_PWRITE | ||
| 1162 | #endif | ||
| 1163 | |||
| 1164 | #if SANITIZER_INTERCEPT_PWRITE64 | ||
| 1165 | INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count, | ||
| 1166 | OFF64_T offset) { | ||
| 1167 | void *ctx; | ||
| 1168 | COMMON_INTERCEPTOR_ENTER(ctx, pwrite64, fd, ptr, count, offset); | ||
| 1169 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 1170 | if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); | ||
| 1171 | SSIZE_T res = REAL(pwrite64)(fd, ptr, count, offset); | ||
| 1172 | if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res); | ||
| 1173 | return res; | ||
| 1174 | } | ||
| 1175 | #define INIT_PWRITE64 COMMON_INTERCEPT_FUNCTION(pwrite64) | ||
| 1176 | #else | ||
| 1177 | #define INIT_PWRITE64 | ||
| 1178 | #endif | ||
| 1179 | |||
| 1180 | #if SANITIZER_INTERCEPT_WRITEV | ||
| 1181 | INTERCEPTOR_WITH_SUFFIX(SSIZE_T, writev, int fd, __sanitizer_iovec *iov, | ||
| 1182 | int iovcnt) { | ||
| 1183 | void *ctx; | ||
| 1184 | COMMON_INTERCEPTOR_ENTER(ctx, writev, fd, iov, iovcnt); | ||
| 1185 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 1186 | if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); | ||
| 1187 | SSIZE_T res = REAL(writev)(fd, iov, iovcnt); | ||
| 1188 | if (res > 0) read_iovec(ctx, iov, iovcnt, res); | ||
| 1189 | return res; | ||
| 1190 | } | ||
| 1191 | #define INIT_WRITEV COMMON_INTERCEPT_FUNCTION(writev) | ||
| 1192 | #else | ||
| 1193 | #define INIT_WRITEV | ||
| 1194 | #endif | ||
| 1195 | |||
| 1196 | #if SANITIZER_INTERCEPT_PWRITEV | ||
| 1197 | INTERCEPTOR(SSIZE_T, pwritev, int fd, __sanitizer_iovec *iov, int iovcnt, | ||
| 1198 | OFF_T offset) { | ||
| 1199 | void *ctx; | ||
| 1200 | COMMON_INTERCEPTOR_ENTER(ctx, pwritev, fd, iov, iovcnt, offset); | ||
| 1201 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 1202 | if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); | ||
| 1203 | SSIZE_T res = REAL(pwritev)(fd, iov, iovcnt, offset); | ||
| 1204 | if (res > 0) read_iovec(ctx, iov, iovcnt, res); | ||
| 1205 | return res; | ||
| 1206 | } | ||
| 1207 | #define INIT_PWRITEV COMMON_INTERCEPT_FUNCTION(pwritev) | ||
| 1208 | #else | ||
| 1209 | #define INIT_PWRITEV | ||
| 1210 | #endif | ||
| 1211 | |||
| 1212 | #if SANITIZER_INTERCEPT_PWRITEV64 | ||
| 1213 | INTERCEPTOR(SSIZE_T, pwritev64, int fd, __sanitizer_iovec *iov, int iovcnt, | ||
| 1214 | OFF64_T offset) { | ||
| 1215 | void *ctx; | ||
| 1216 | COMMON_INTERCEPTOR_ENTER(ctx, pwritev64, fd, iov, iovcnt, offset); | ||
| 1217 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 1218 | if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); | ||
| 1219 | SSIZE_T res = REAL(pwritev64)(fd, iov, iovcnt, offset); | ||
| 1220 | if (res > 0) read_iovec(ctx, iov, iovcnt, res); | ||
| 1221 | return res; | ||
| 1222 | } | ||
| 1223 | #define INIT_PWRITEV64 COMMON_INTERCEPT_FUNCTION(pwritev64) | ||
| 1224 | #else | ||
| 1225 | #define INIT_PWRITEV64 | ||
| 1226 | #endif | ||
| 1227 | |||
| 1228 | #if SANITIZER_INTERCEPT_FGETS | ||
| 1229 | INTERCEPTOR(char *, fgets, char *s, SIZE_T size, void *file) { | ||
| 1230 | // libc file streams can call user-supplied functions, see fopencookie. | ||
| 1231 | void *ctx; | ||
| 1232 | COMMON_INTERCEPTOR_ENTER(ctx, fgets, s, size, file); | ||
| 1233 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 1234 | // its metadata. See | ||
| 1235 | // https://github.com/google/sanitizers/issues/321. | ||
| 1236 | char *res = REAL(fgets)(s, size, file); | ||
| 1237 | if (res) | ||
| 1238 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1); | ||
| 1239 | return res; | ||
| 1240 | } | ||
| 1241 | #define INIT_FGETS COMMON_INTERCEPT_FUNCTION(fgets) | ||
| 1242 | #else | ||
| 1243 | #define INIT_FGETS | ||
| 1244 | #endif | ||
| 1245 | |||
| 1246 | #if SANITIZER_INTERCEPT_FPUTS | ||
| 1247 | INTERCEPTOR_WITH_SUFFIX(int, fputs, char *s, void *file) { | ||
| 1248 | // libc file streams can call user-supplied functions, see fopencookie. | ||
| 1249 | void *ctx; | ||
| 1250 | COMMON_INTERCEPTOR_ENTER(ctx, fputs, s, file); | ||
| 1251 | if (!SANITIZER_MAC || s) { // `fputs(NULL, file)` is supported on Darwin. | ||
| 1252 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1); | ||
| 1253 | } | ||
| 1254 | return REAL(fputs)(s, file); | ||
| 1255 | } | ||
| 1256 | #define INIT_FPUTS COMMON_INTERCEPT_FUNCTION(fputs) | ||
| 1257 | #else | ||
| 1258 | #define INIT_FPUTS | ||
| 1259 | #endif | ||
| 1260 | |||
| 1261 | #if SANITIZER_INTERCEPT_PUTS | ||
| 1262 | INTERCEPTOR(int, puts, char *s) { | ||
| 1263 | // libc file streams can call user-supplied functions, see fopencookie. | ||
| 1264 | void *ctx; | ||
| 1265 | COMMON_INTERCEPTOR_ENTER(ctx, puts, s); | ||
| 1266 | if (!SANITIZER_MAC || s) { // `puts(NULL)` is supported on Darwin. | ||
| 1267 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1); | ||
| 1268 | } | ||
| 1269 | return REAL(puts)(s); | ||
| 1270 | } | ||
| 1271 | #define INIT_PUTS COMMON_INTERCEPT_FUNCTION(puts) | ||
| 1272 | #else | ||
| 1273 | #define INIT_PUTS | ||
| 1274 | #endif | ||
| 1275 | |||
| 1276 | #if SANITIZER_INTERCEPT_PRCTL | ||
| 1277 | INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3, | ||
| 1278 | unsigned long arg4, unsigned long arg5) { | ||
| 1279 | void *ctx; | ||
| 1280 | COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5); | ||
| 1281 | static const int PR_SET_NAME = 15; | ||
| 1282 | int res = REAL(prctl(option, arg2, arg3, arg4, arg5)); | ||
| 1283 | if (option == PR_SET_NAME) { | ||
| 1284 | char buff[16]; | ||
| 1285 | internal_strncpy(buff, (char *)arg2, 15); | ||
| 1286 | buff[15] = 0; | ||
| 1287 | COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, buff); | ||
| 1288 | } | ||
| 1289 | return res; | ||
| 1290 | } | ||
| 1291 | #define INIT_PRCTL COMMON_INTERCEPT_FUNCTION(prctl) | ||
| 1292 | #else | ||
| 1293 | #define INIT_PRCTL | ||
| 1294 | #endif // SANITIZER_INTERCEPT_PRCTL | ||
| 1295 | |||
| 1296 | #if SANITIZER_INTERCEPT_TIME | ||
| 1297 | INTERCEPTOR(unsigned long, time, unsigned long *t) { | ||
| 1298 | void *ctx; | ||
| 1299 | COMMON_INTERCEPTOR_ENTER(ctx, time, t); | ||
| 1300 | unsigned long local_t; | ||
| 1301 | unsigned long res = REAL(time)(&local_t); | ||
| 1302 | if (t && res != (unsigned long)-1) { | ||
| 1303 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, t, sizeof(*t)); | ||
| 1304 | *t = local_t; | ||
| 1305 | } | ||
| 1306 | return res; | ||
| 1307 | } | ||
| 1308 | #define INIT_TIME COMMON_INTERCEPT_FUNCTION(time); | ||
| 1309 | #else | ||
| 1310 | #define INIT_TIME | ||
| 1311 | #endif // SANITIZER_INTERCEPT_TIME | ||
| 1312 | |||
| 1313 | #if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS | ||
| 1314 | static void unpoison_tm(void *ctx, __sanitizer_tm *tm) { | ||
| 1315 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm)); | ||
| 1316 | #if !SANITIZER_SOLARIS | ||
| 1317 | if (tm->tm_zone) { | ||
| 1318 | // Can not use COMMON_INTERCEPTOR_WRITE_RANGE here, because tm->tm_zone | ||
| 1319 | // can point to shared memory and tsan would report a data race. | ||
| 1320 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(tm->tm_zone, | ||
| 1321 | REAL(strlen(tm->tm_zone)) + 1); | ||
| 1322 | } | ||
| 1323 | #endif | ||
| 1324 | } | ||
| 1325 | INTERCEPTOR(__sanitizer_tm *, localtime, unsigned long *timep) { | ||
| 1326 | void *ctx; | ||
| 1327 | COMMON_INTERCEPTOR_ENTER(ctx, localtime, timep); | ||
| 1328 | __sanitizer_tm *res = REAL(localtime)(timep); | ||
| 1329 | if (res) { | ||
| 1330 | COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); | ||
| 1331 | unpoison_tm(ctx, res); | ||
| 1332 | } | ||
| 1333 | return res; | ||
| 1334 | } | ||
| 1335 | INTERCEPTOR(__sanitizer_tm *, localtime_r, unsigned long *timep, void *result) { | ||
| 1336 | void *ctx; | ||
| 1337 | COMMON_INTERCEPTOR_ENTER(ctx, localtime_r, timep, result); | ||
| 1338 | __sanitizer_tm *res = REAL(localtime_r)(timep, result); | ||
| 1339 | if (res) { | ||
| 1340 | COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); | ||
| 1341 | unpoison_tm(ctx, res); | ||
| 1342 | } | ||
| 1343 | return res; | ||
| 1344 | } | ||
| 1345 | INTERCEPTOR(__sanitizer_tm *, gmtime, unsigned long *timep) { | ||
| 1346 | void *ctx; | ||
| 1347 | COMMON_INTERCEPTOR_ENTER(ctx, gmtime, timep); | ||
| 1348 | __sanitizer_tm *res = REAL(gmtime)(timep); | ||
| 1349 | if (res) { | ||
| 1350 | COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); | ||
| 1351 | unpoison_tm(ctx, res); | ||
| 1352 | } | ||
| 1353 | return res; | ||
| 1354 | } | ||
| 1355 | INTERCEPTOR(__sanitizer_tm *, gmtime_r, unsigned long *timep, void *result) { | ||
| 1356 | void *ctx; | ||
| 1357 | COMMON_INTERCEPTOR_ENTER(ctx, gmtime_r, timep, result); | ||
| 1358 | __sanitizer_tm *res = REAL(gmtime_r)(timep, result); | ||
| 1359 | if (res) { | ||
| 1360 | COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); | ||
| 1361 | unpoison_tm(ctx, res); | ||
| 1362 | } | ||
| 1363 | return res; | ||
| 1364 | } | ||
| 1365 | INTERCEPTOR(char *, ctime, unsigned long *timep) { | ||
| 1366 | void *ctx; | ||
| 1367 | COMMON_INTERCEPTOR_ENTER(ctx, ctime, timep); | ||
| 1368 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 1369 | // its metadata. See | ||
| 1370 | // https://github.com/google/sanitizers/issues/321. | ||
| 1371 | char *res = REAL(ctime)(timep); | ||
| 1372 | if (res) { | ||
| 1373 | COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); | ||
| 1374 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); | ||
| 1375 | } | ||
| 1376 | return res; | ||
| 1377 | } | ||
| 1378 | INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) { | ||
| 1379 | void *ctx; | ||
| 1380 | COMMON_INTERCEPTOR_ENTER(ctx, ctime_r, timep, result); | ||
| 1381 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 1382 | // its metadata. See | ||
| 1383 | // https://github.com/google/sanitizers/issues/321. | ||
| 1384 | char *res = REAL(ctime_r)(timep, result); | ||
| 1385 | if (res) { | ||
| 1386 | COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); | ||
| 1387 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); | ||
| 1388 | } | ||
| 1389 | return res; | ||
| 1390 | } | ||
| 1391 | INTERCEPTOR(char *, asctime, __sanitizer_tm *tm) { | ||
| 1392 | void *ctx; | ||
| 1393 | COMMON_INTERCEPTOR_ENTER(ctx, asctime, tm); | ||
| 1394 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 1395 | // its metadata. See | ||
| 1396 | // https://github.com/google/sanitizers/issues/321. | ||
| 1397 | char *res = REAL(asctime)(tm); | ||
| 1398 | if (res) { | ||
| 1399 | COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm)); | ||
| 1400 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); | ||
| 1401 | } | ||
| 1402 | return res; | ||
| 1403 | } | ||
| 1404 | INTERCEPTOR(char *, asctime_r, __sanitizer_tm *tm, char *result) { | ||
| 1405 | void *ctx; | ||
| 1406 | COMMON_INTERCEPTOR_ENTER(ctx, asctime_r, tm, result); | ||
| 1407 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 1408 | // its metadata. See | ||
| 1409 | // https://github.com/google/sanitizers/issues/321. | ||
| 1410 | char *res = REAL(asctime_r)(tm, result); | ||
| 1411 | if (res) { | ||
| 1412 | COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm)); | ||
| 1413 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); | ||
| 1414 | } | ||
| 1415 | return res; | ||
| 1416 | } | ||
| 1417 | INTERCEPTOR(long, mktime, __sanitizer_tm *tm) { | ||
| 1418 | void *ctx; | ||
| 1419 | COMMON_INTERCEPTOR_ENTER(ctx, mktime, tm); | ||
| 1420 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_sec, sizeof(tm->tm_sec)); | ||
| 1421 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_min, sizeof(tm->tm_min)); | ||
| 1422 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_hour, sizeof(tm->tm_hour)); | ||
| 1423 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_mday, sizeof(tm->tm_mday)); | ||
| 1424 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_mon, sizeof(tm->tm_mon)); | ||
| 1425 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_year, sizeof(tm->tm_year)); | ||
| 1426 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_isdst, sizeof(tm->tm_isdst)); | ||
| 1427 | long res = REAL(mktime)(tm); | ||
| 1428 | if (res != -1) unpoison_tm(ctx, tm); | ||
| 1429 | return res; | ||
| 1430 | } | ||
| 1431 | #define INIT_LOCALTIME_AND_FRIENDS \ | ||
| 1432 | COMMON_INTERCEPT_FUNCTION(localtime); \ | ||
| 1433 | COMMON_INTERCEPT_FUNCTION(localtime_r); \ | ||
| 1434 | COMMON_INTERCEPT_FUNCTION(gmtime); \ | ||
| 1435 | COMMON_INTERCEPT_FUNCTION(gmtime_r); \ | ||
| 1436 | COMMON_INTERCEPT_FUNCTION(ctime); \ | ||
| 1437 | COMMON_INTERCEPT_FUNCTION(ctime_r); \ | ||
| 1438 | COMMON_INTERCEPT_FUNCTION(asctime); \ | ||
| 1439 | COMMON_INTERCEPT_FUNCTION(asctime_r); \ | ||
| 1440 | COMMON_INTERCEPT_FUNCTION(mktime); | ||
| 1441 | #else | ||
| 1442 | #define INIT_LOCALTIME_AND_FRIENDS | ||
| 1443 | #endif // SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS | ||
| 1444 | |||
| 1445 | #if SANITIZER_INTERCEPT_STRPTIME | ||
| 1446 | INTERCEPTOR(char *, strptime, char *s, char *format, __sanitizer_tm *tm) { | ||
| 1447 | void *ctx; | ||
| 1448 | COMMON_INTERCEPTOR_ENTER(ctx, strptime, s, format, tm); | ||
| 1449 | if (format) | ||
| 1450 | COMMON_INTERCEPTOR_READ_RANGE(ctx, format, REAL(strlen)(format) + 1); | ||
| 1451 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 1452 | // its metadata. See | ||
| 1453 | // https://github.com/google/sanitizers/issues/321. | ||
| 1454 | char *res = REAL(strptime)(s, format, tm); | ||
| 1455 | COMMON_INTERCEPTOR_READ_STRING(ctx, s, res ? res - s : 0); | ||
| 1456 | if (res && tm) { | ||
| 1457 | // Do not call unpoison_tm here, because strptime does not, in fact, | ||
| 1458 | // initialize the entire struct tm. For example, tm_zone pointer is left | ||
| 1459 | // uninitialized. | ||
| 1460 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm)); | ||
| 1461 | } | ||
| 1462 | return res; | ||
| 1463 | } | ||
| 1464 | #define INIT_STRPTIME COMMON_INTERCEPT_FUNCTION(strptime); | ||
| 1465 | #else | ||
| 1466 | #define INIT_STRPTIME | ||
| 1467 | #endif | ||
| 1468 | |||
| 1469 | #if SANITIZER_INTERCEPT_SCANF || SANITIZER_INTERCEPT_PRINTF | ||
| 1470 | #include "sanitizer_common_interceptors_format.inc" | ||
| 1471 | |||
| 1472 | #define FORMAT_INTERCEPTOR_IMPL(name, vname, ...) \ | ||
| 1473 | { \ | ||
| 1474 | void *ctx; \ | ||
| 1475 | va_list ap; \ | ||
| 1476 | va_start(ap, format); \ | ||
| 1477 | COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__, ap); \ | ||
| 1478 | int res = WRAP(vname)(__VA_ARGS__, ap); \ | ||
| 1479 | va_end(ap); \ | ||
| 1480 | return res; \ | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | #endif | ||
| 1484 | |||
| 1485 | #if SANITIZER_INTERCEPT_SCANF | ||
| 1486 | |||
| 1487 | #define VSCANF_INTERCEPTOR_IMPL(vname, allowGnuMalloc, ...) \ | ||
| 1488 | { \ | ||
| 1489 | void *ctx; \ | ||
| 1490 | COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__); \ | ||
| 1491 | va_list aq; \ | ||
| 1492 | va_copy(aq, ap); \ | ||
| 1493 | int res = REAL(vname)(__VA_ARGS__); \ | ||
| 1494 | if (res > 0) \ | ||
| 1495 | scanf_common(ctx, res, allowGnuMalloc, format, aq); \ | ||
| 1496 | va_end(aq); \ | ||
| 1497 | return res; \ | ||
| 1498 | } | ||
| 1499 | |||
| 1500 | INTERCEPTOR(int, vscanf, const char *format, va_list ap) | ||
| 1501 | VSCANF_INTERCEPTOR_IMPL(vscanf, true, format, ap) | ||
| 1502 | |||
| 1503 | INTERCEPTOR(int, vsscanf, const char *str, const char *format, va_list ap) | ||
| 1504 | VSCANF_INTERCEPTOR_IMPL(vsscanf, true, str, format, ap) | ||
| 1505 | |||
| 1506 | INTERCEPTOR(int, vfscanf, void *stream, const char *format, va_list ap) | ||
| 1507 | VSCANF_INTERCEPTOR_IMPL(vfscanf, true, stream, format, ap) | ||
| 1508 | |||
| 1509 | #if SANITIZER_INTERCEPT_ISOC99_SCANF | ||
| 1510 | INTERCEPTOR(int, __isoc99_vscanf, const char *format, va_list ap) | ||
| 1511 | VSCANF_INTERCEPTOR_IMPL(__isoc99_vscanf, false, format, ap) | ||
| 1512 | |||
| 1513 | INTERCEPTOR(int, __isoc99_vsscanf, const char *str, const char *format, | ||
| 1514 | va_list ap) | ||
| 1515 | VSCANF_INTERCEPTOR_IMPL(__isoc99_vsscanf, false, str, format, ap) | ||
| 1516 | |||
| 1517 | INTERCEPTOR(int, __isoc99_vfscanf, void *stream, const char *format, va_list ap) | ||
| 1518 | VSCANF_INTERCEPTOR_IMPL(__isoc99_vfscanf, false, stream, format, ap) | ||
| 1519 | #endif // SANITIZER_INTERCEPT_ISOC99_SCANF | ||
| 1520 | |||
| 1521 | INTERCEPTOR(int, scanf, const char *format, ...) | ||
| 1522 | FORMAT_INTERCEPTOR_IMPL(scanf, vscanf, format) | ||
| 1523 | |||
| 1524 | INTERCEPTOR(int, fscanf, void *stream, const char *format, ...) | ||
| 1525 | FORMAT_INTERCEPTOR_IMPL(fscanf, vfscanf, stream, format) | ||
| 1526 | |||
| 1527 | INTERCEPTOR(int, sscanf, const char *str, const char *format, ...) | ||
| 1528 | FORMAT_INTERCEPTOR_IMPL(sscanf, vsscanf, str, format) | ||
| 1529 | |||
| 1530 | #if SANITIZER_INTERCEPT_ISOC99_SCANF | ||
| 1531 | INTERCEPTOR(int, __isoc99_scanf, const char *format, ...) | ||
| 1532 | FORMAT_INTERCEPTOR_IMPL(__isoc99_scanf, __isoc99_vscanf, format) | ||
| 1533 | |||
| 1534 | INTERCEPTOR(int, __isoc99_fscanf, void *stream, const char *format, ...) | ||
| 1535 | FORMAT_INTERCEPTOR_IMPL(__isoc99_fscanf, __isoc99_vfscanf, stream, format) | ||
| 1536 | |||
| 1537 | INTERCEPTOR(int, __isoc99_sscanf, const char *str, const char *format, ...) | ||
| 1538 | FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format) | ||
| 1539 | #endif | ||
| 1540 | |||
| 1541 | #endif | ||
| 1542 | |||
| 1543 | #if SANITIZER_INTERCEPT_SCANF | ||
| 1544 | #define INIT_SCANF \ | ||
| 1545 | COMMON_INTERCEPT_FUNCTION_LDBL(scanf); \ | ||
| 1546 | COMMON_INTERCEPT_FUNCTION_LDBL(sscanf); \ | ||
| 1547 | COMMON_INTERCEPT_FUNCTION_LDBL(fscanf); \ | ||
| 1548 | COMMON_INTERCEPT_FUNCTION_LDBL(vscanf); \ | ||
| 1549 | COMMON_INTERCEPT_FUNCTION_LDBL(vsscanf); \ | ||
| 1550 | COMMON_INTERCEPT_FUNCTION_LDBL(vfscanf); | ||
| 1551 | #else | ||
| 1552 | #define INIT_SCANF | ||
| 1553 | #endif | ||
| 1554 | |||
| 1555 | #if SANITIZER_INTERCEPT_ISOC99_SCANF | ||
| 1556 | #define INIT_ISOC99_SCANF \ | ||
| 1557 | COMMON_INTERCEPT_FUNCTION(__isoc99_scanf); \ | ||
| 1558 | COMMON_INTERCEPT_FUNCTION(__isoc99_sscanf); \ | ||
| 1559 | COMMON_INTERCEPT_FUNCTION(__isoc99_fscanf); \ | ||
| 1560 | COMMON_INTERCEPT_FUNCTION(__isoc99_vscanf); \ | ||
| 1561 | COMMON_INTERCEPT_FUNCTION(__isoc99_vsscanf); \ | ||
| 1562 | COMMON_INTERCEPT_FUNCTION(__isoc99_vfscanf); | ||
| 1563 | #else | ||
| 1564 | #define INIT_ISOC99_SCANF | ||
| 1565 | #endif | ||
| 1566 | |||
| 1567 | #if SANITIZER_INTERCEPT_PRINTF | ||
| 1568 | |||
| 1569 | #define VPRINTF_INTERCEPTOR_ENTER(vname, ...) \ | ||
| 1570 | void *ctx; \ | ||
| 1571 | COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__); \ | ||
| 1572 | va_list aq; \ | ||
| 1573 | va_copy(aq, ap); | ||
| 1574 | |||
| 1575 | #define VPRINTF_INTERCEPTOR_RETURN() \ | ||
| 1576 | va_end(aq); | ||
| 1577 | |||
| 1578 | #define VPRINTF_INTERCEPTOR_IMPL(vname, ...) \ | ||
| 1579 | { \ | ||
| 1580 | VPRINTF_INTERCEPTOR_ENTER(vname, __VA_ARGS__); \ | ||
| 1581 | if (common_flags()->check_printf) \ | ||
| 1582 | printf_common(ctx, format, aq); \ | ||
| 1583 | int res = REAL(vname)(__VA_ARGS__); \ | ||
| 1584 | VPRINTF_INTERCEPTOR_RETURN(); \ | ||
| 1585 | return res; \ | ||
| 1586 | } | ||
| 1587 | |||
| 1588 | // FIXME: under ASan the REAL() call below may write to freed memory and | ||
| 1589 | // corrupt its metadata. See | ||
| 1590 | // https://github.com/google/sanitizers/issues/321. | ||
| 1591 | #define VSPRINTF_INTERCEPTOR_IMPL(vname, str, ...) \ | ||
| 1592 | { \ | ||
| 1593 | VPRINTF_INTERCEPTOR_ENTER(vname, str, __VA_ARGS__) \ | ||
| 1594 | if (common_flags()->check_printf) { \ | ||
| 1595 | printf_common(ctx, format, aq); \ | ||
| 1596 | } \ | ||
| 1597 | int res = REAL(vname)(str, __VA_ARGS__); \ | ||
| 1598 | if (res >= 0) { \ | ||
| 1599 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, res + 1); \ | ||
| 1600 | } \ | ||
| 1601 | VPRINTF_INTERCEPTOR_RETURN(); \ | ||
| 1602 | return res; \ | ||
| 1603 | } | ||
| 1604 | |||
| 1605 | // FIXME: under ASan the REAL() call below may write to freed memory and | ||
| 1606 | // corrupt its metadata. See | ||
| 1607 | // https://github.com/google/sanitizers/issues/321. | ||
| 1608 | #define VSNPRINTF_INTERCEPTOR_IMPL(vname, str, size, ...) \ | ||
| 1609 | { \ | ||
| 1610 | VPRINTF_INTERCEPTOR_ENTER(vname, str, size, __VA_ARGS__) \ | ||
| 1611 | if (common_flags()->check_printf) { \ | ||
| 1612 | printf_common(ctx, format, aq); \ | ||
| 1613 | } \ | ||
| 1614 | int res = REAL(vname)(str, size, __VA_ARGS__); \ | ||
| 1615 | if (res >= 0) { \ | ||
| 1616 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, Min(size, (SIZE_T)(res + 1))); \ | ||
| 1617 | } \ | ||
| 1618 | VPRINTF_INTERCEPTOR_RETURN(); \ | ||
| 1619 | return res; \ | ||
| 1620 | } | ||
| 1621 | |||
| 1622 | // FIXME: under ASan the REAL() call below may write to freed memory and | ||
| 1623 | // corrupt its metadata. See | ||
| 1624 | // https://github.com/google/sanitizers/issues/321. | ||
| 1625 | #define VASPRINTF_INTERCEPTOR_IMPL(vname, strp, ...) \ | ||
| 1626 | { \ | ||
| 1627 | VPRINTF_INTERCEPTOR_ENTER(vname, strp, __VA_ARGS__) \ | ||
| 1628 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, strp, sizeof(char *)); \ | ||
| 1629 | if (common_flags()->check_printf) { \ | ||
| 1630 | printf_common(ctx, format, aq); \ | ||
| 1631 | } \ | ||
| 1632 | int res = REAL(vname)(strp, __VA_ARGS__); \ | ||
| 1633 | if (res >= 0) { \ | ||
| 1634 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *strp, res + 1); \ | ||
| 1635 | } \ | ||
| 1636 | VPRINTF_INTERCEPTOR_RETURN(); \ | ||
| 1637 | return res; \ | ||
| 1638 | } | ||
| 1639 | |||
| 1640 | INTERCEPTOR(int, vprintf, const char *format, va_list ap) | ||
| 1641 | VPRINTF_INTERCEPTOR_IMPL(vprintf, format, ap) | ||
| 1642 | |||
| 1643 | INTERCEPTOR(int, vfprintf, __sanitizer_FILE *stream, const char *format, | ||
| 1644 | va_list ap) | ||
| 1645 | VPRINTF_INTERCEPTOR_IMPL(vfprintf, stream, format, ap) | ||
| 1646 | |||
| 1647 | INTERCEPTOR(int, vsnprintf, char *str, SIZE_T size, const char *format, | ||
| 1648 | va_list ap) | ||
| 1649 | VSNPRINTF_INTERCEPTOR_IMPL(vsnprintf, str, size, format, ap) | ||
| 1650 | |||
| 1651 | #if SANITIZER_INTERCEPT___PRINTF_CHK | ||
| 1652 | INTERCEPTOR(int, __vsnprintf_chk, char *str, SIZE_T size, int flag, | ||
| 1653 | SIZE_T size_to, const char *format, va_list ap) | ||
| 1654 | VSNPRINTF_INTERCEPTOR_IMPL(vsnprintf, str, size, format, ap) | ||
| 1655 | #endif | ||
| 1656 | |||
| 1657 | #if SANITIZER_INTERCEPT_PRINTF_L | ||
| 1658 | INTERCEPTOR(int, vsnprintf_l, char *str, SIZE_T size, void *loc, | ||
| 1659 | const char *format, va_list ap) | ||
| 1660 | VSNPRINTF_INTERCEPTOR_IMPL(vsnprintf_l, str, size, loc, format, ap) | ||
| 1661 | |||
| 1662 | INTERCEPTOR(int, snprintf_l, char *str, SIZE_T size, void *loc, | ||
| 1663 | const char *format, ...) | ||
| 1664 | FORMAT_INTERCEPTOR_IMPL(snprintf_l, vsnprintf_l, str, size, loc, format) | ||
| 1665 | #endif // SANITIZER_INTERCEPT_PRINTF_L | ||
| 1666 | |||
| 1667 | INTERCEPTOR(int, vsprintf, char *str, const char *format, va_list ap) | ||
| 1668 | VSPRINTF_INTERCEPTOR_IMPL(vsprintf, str, format, ap) | ||
| 1669 | |||
| 1670 | #if SANITIZER_INTERCEPT___PRINTF_CHK | ||
| 1671 | INTERCEPTOR(int, __vsprintf_chk, char *str, int flag, SIZE_T size_to, | ||
| 1672 | const char *format, va_list ap) | ||
| 1673 | VSPRINTF_INTERCEPTOR_IMPL(vsprintf, str, format, ap) | ||
| 1674 | #endif | ||
| 1675 | |||
| 1676 | INTERCEPTOR(int, vasprintf, char **strp, const char *format, va_list ap) | ||
| 1677 | VASPRINTF_INTERCEPTOR_IMPL(vasprintf, strp, format, ap) | ||
| 1678 | |||
| 1679 | #if SANITIZER_INTERCEPT_ISOC99_PRINTF | ||
| 1680 | INTERCEPTOR(int, __isoc99_vprintf, const char *format, va_list ap) | ||
| 1681 | VPRINTF_INTERCEPTOR_IMPL(__isoc99_vprintf, format, ap) | ||
| 1682 | |||
| 1683 | INTERCEPTOR(int, __isoc99_vfprintf, __sanitizer_FILE *stream, | ||
| 1684 | const char *format, va_list ap) | ||
| 1685 | VPRINTF_INTERCEPTOR_IMPL(__isoc99_vfprintf, stream, format, ap) | ||
| 1686 | |||
| 1687 | INTERCEPTOR(int, __isoc99_vsnprintf, char *str, SIZE_T size, const char *format, | ||
| 1688 | va_list ap) | ||
| 1689 | VSNPRINTF_INTERCEPTOR_IMPL(__isoc99_vsnprintf, str, size, format, ap) | ||
| 1690 | |||
| 1691 | INTERCEPTOR(int, __isoc99_vsprintf, char *str, const char *format, | ||
| 1692 | va_list ap) | ||
| 1693 | VSPRINTF_INTERCEPTOR_IMPL(__isoc99_vsprintf, str, format, | ||
| 1694 | ap) | ||
| 1695 | |||
| 1696 | #endif // SANITIZER_INTERCEPT_ISOC99_PRINTF | ||
| 1697 | |||
| 1698 | INTERCEPTOR(int, printf, const char *format, ...) | ||
| 1699 | FORMAT_INTERCEPTOR_IMPL(printf, vprintf, format) | ||
| 1700 | |||
| 1701 | INTERCEPTOR(int, fprintf, __sanitizer_FILE *stream, const char *format, ...) | ||
| 1702 | FORMAT_INTERCEPTOR_IMPL(fprintf, vfprintf, stream, format) | ||
| 1703 | |||
| 1704 | #if SANITIZER_INTERCEPT___PRINTF_CHK | ||
| 1705 | INTERCEPTOR(int, __fprintf_chk, __sanitizer_FILE *stream, SIZE_T size, | ||
| 1706 | const char *format, ...) | ||
| 1707 | FORMAT_INTERCEPTOR_IMPL(__fprintf_chk, vfprintf, stream, format) | ||
| 1708 | #endif | ||
| 1709 | |||
| 1710 | INTERCEPTOR(int, sprintf, char *str, const char *format, ...) | ||
| 1711 | FORMAT_INTERCEPTOR_IMPL(sprintf, vsprintf, str, format) | ||
| 1712 | |||
| 1713 | #if SANITIZER_INTERCEPT___PRINTF_CHK | ||
| 1714 | INTERCEPTOR(int, __sprintf_chk, char *str, int flag, SIZE_T size_to, | ||
| 1715 | const char *format, ...) | ||
| 1716 | FORMAT_INTERCEPTOR_IMPL(__sprintf_chk, vsprintf, str, format) | ||
| 1717 | #endif | ||
| 1718 | |||
| 1719 | INTERCEPTOR(int, snprintf, char *str, SIZE_T size, const char *format, ...) | ||
| 1720 | FORMAT_INTERCEPTOR_IMPL(snprintf, vsnprintf, str, size, format) | ||
| 1721 | |||
| 1722 | #if SANITIZER_INTERCEPT___PRINTF_CHK | ||
| 1723 | INTERCEPTOR(int, __snprintf_chk, char *str, SIZE_T size, int flag, | ||
| 1724 | SIZE_T size_to, const char *format, ...) | ||
| 1725 | FORMAT_INTERCEPTOR_IMPL(__snprintf_chk, vsnprintf, str, size, format) | ||
| 1726 | #endif | ||
| 1727 | |||
| 1728 | INTERCEPTOR(int, asprintf, char **strp, const char *format, ...) | ||
| 1729 | FORMAT_INTERCEPTOR_IMPL(asprintf, vasprintf, strp, format) | ||
| 1730 | |||
| 1731 | #if SANITIZER_INTERCEPT_ISOC99_PRINTF | ||
| 1732 | INTERCEPTOR(int, __isoc99_printf, const char *format, ...) | ||
| 1733 | FORMAT_INTERCEPTOR_IMPL(__isoc99_printf, __isoc99_vprintf, format) | ||
| 1734 | |||
| 1735 | INTERCEPTOR(int, __isoc99_fprintf, __sanitizer_FILE *stream, const char *format, | ||
| 1736 | ...) | ||
| 1737 | FORMAT_INTERCEPTOR_IMPL(__isoc99_fprintf, __isoc99_vfprintf, stream, format) | ||
| 1738 | |||
| 1739 | INTERCEPTOR(int, __isoc99_sprintf, char *str, const char *format, ...) | ||
| 1740 | FORMAT_INTERCEPTOR_IMPL(__isoc99_sprintf, __isoc99_vsprintf, str, format) | ||
| 1741 | |||
| 1742 | INTERCEPTOR(int, __isoc99_snprintf, char *str, SIZE_T size, | ||
| 1743 | const char *format, ...) | ||
| 1744 | FORMAT_INTERCEPTOR_IMPL(__isoc99_snprintf, __isoc99_vsnprintf, str, size, | ||
| 1745 | format) | ||
| 1746 | |||
| 1747 | #endif // SANITIZER_INTERCEPT_ISOC99_PRINTF | ||
| 1748 | |||
| 1749 | #endif // SANITIZER_INTERCEPT_PRINTF | ||
| 1750 | |||
| 1751 | #if SANITIZER_INTERCEPT_PRINTF | ||
| 1752 | #define INIT_PRINTF \ | ||
| 1753 | COMMON_INTERCEPT_FUNCTION_LDBL(printf); \ | ||
| 1754 | COMMON_INTERCEPT_FUNCTION_LDBL(sprintf); \ | ||
| 1755 | COMMON_INTERCEPT_FUNCTION_LDBL(snprintf); \ | ||
| 1756 | COMMON_INTERCEPT_FUNCTION_LDBL(asprintf); \ | ||
| 1757 | COMMON_INTERCEPT_FUNCTION_LDBL(fprintf); \ | ||
| 1758 | COMMON_INTERCEPT_FUNCTION_LDBL(vprintf); \ | ||
| 1759 | COMMON_INTERCEPT_FUNCTION_LDBL(vsprintf); \ | ||
| 1760 | COMMON_INTERCEPT_FUNCTION_LDBL(vsnprintf); \ | ||
| 1761 | COMMON_INTERCEPT_FUNCTION_LDBL(vasprintf); \ | ||
| 1762 | COMMON_INTERCEPT_FUNCTION_LDBL(vfprintf); | ||
| 1763 | #else | ||
| 1764 | #define INIT_PRINTF | ||
| 1765 | #endif | ||
| 1766 | |||
| 1767 | #if SANITIZER_INTERCEPT___PRINTF_CHK | ||
| 1768 | #define INIT___PRINTF_CHK \ | ||
| 1769 | COMMON_INTERCEPT_FUNCTION(__sprintf_chk); \ | ||
| 1770 | COMMON_INTERCEPT_FUNCTION(__snprintf_chk); \ | ||
| 1771 | COMMON_INTERCEPT_FUNCTION(__vsprintf_chk); \ | ||
| 1772 | COMMON_INTERCEPT_FUNCTION(__vsnprintf_chk); \ | ||
| 1773 | COMMON_INTERCEPT_FUNCTION(__fprintf_chk); | ||
| 1774 | #else | ||
| 1775 | #define INIT___PRINTF_CHK | ||
| 1776 | #endif | ||
| 1777 | |||
| 1778 | #if SANITIZER_INTERCEPT_PRINTF_L | ||
| 1779 | #define INIT_PRINTF_L \ | ||
| 1780 | COMMON_INTERCEPT_FUNCTION(snprintf_l); \ | ||
| 1781 | COMMON_INTERCEPT_FUNCTION(vsnprintf_l); | ||
| 1782 | #else | ||
| 1783 | #define INIT_PRINTF_L | ||
| 1784 | #endif | ||
| 1785 | |||
| 1786 | #if SANITIZER_INTERCEPT_ISOC99_PRINTF | ||
| 1787 | #define INIT_ISOC99_PRINTF \ | ||
| 1788 | COMMON_INTERCEPT_FUNCTION(__isoc99_printf); \ | ||
| 1789 | COMMON_INTERCEPT_FUNCTION(__isoc99_sprintf); \ | ||
| 1790 | COMMON_INTERCEPT_FUNCTION(__isoc99_snprintf); \ | ||
| 1791 | COMMON_INTERCEPT_FUNCTION(__isoc99_fprintf); \ | ||
| 1792 | COMMON_INTERCEPT_FUNCTION(__isoc99_vprintf); \ | ||
| 1793 | COMMON_INTERCEPT_FUNCTION(__isoc99_vsprintf); \ | ||
| 1794 | COMMON_INTERCEPT_FUNCTION(__isoc99_vsnprintf); \ | ||
| 1795 | COMMON_INTERCEPT_FUNCTION(__isoc99_vfprintf); | ||
| 1796 | #else | ||
| 1797 | #define INIT_ISOC99_PRINTF | ||
| 1798 | #endif | ||
| 1799 | |||
| 1800 | #if SANITIZER_INTERCEPT_IOCTL | ||
| 1801 | #include "sanitizer_common_interceptors_ioctl.inc" | ||
| 1802 | #include "sanitizer_interceptors_ioctl_netbsd.inc" | ||
| 1803 | INTERCEPTOR(int, ioctl, int d, unsigned long request, ...) { | ||
| 1804 | // We need a frame pointer, because we call into ioctl_common_[pre|post] which | ||
| 1805 | // can trigger a report and we need to be able to unwind through this | ||
| 1806 | // function. On Mac in debug mode we might not have a frame pointer, because | ||
| 1807 | // ioctl_common_[pre|post] doesn't get inlined here. | ||
| 1808 | ENABLE_FRAME_POINTER; | ||
| 1809 | |||
| 1810 | void *ctx; | ||
| 1811 | va_list ap; | ||
| 1812 | va_start(ap, request); | ||
| 1813 | void *arg = va_arg(ap, void *); | ||
| 1814 | va_end(ap); | ||
| 1815 | COMMON_INTERCEPTOR_ENTER(ctx, ioctl, d, request, arg); | ||
| 1816 | |||
| 1817 | CHECK(ioctl_initialized); | ||
| 1818 | |||
| 1819 | // Note: TSan does not use common flags, and they are zero-initialized. | ||
| 1820 | // This effectively disables ioctl handling in TSan. | ||
| 1821 | if (!common_flags()->handle_ioctl) return REAL(ioctl)(d, request, arg); | ||
| 1822 | |||
| 1823 | // Although request is unsigned long, the rest of the interceptor uses it | ||
| 1824 | // as just "unsigned" to save space, because we know that all values fit in | ||
| 1825 | // "unsigned" - they are compile-time constants. | ||
| 1826 | |||
| 1827 | const ioctl_desc *desc = ioctl_lookup(request); | ||
| 1828 | ioctl_desc decoded_desc; | ||
| 1829 | if (!desc) { | ||
| 1830 | VPrintf(2, "Decoding unknown ioctl 0x%x\n", request); | ||
| 1831 | if (!ioctl_decode(request, &decoded_desc)) | ||
| 1832 | Printf("WARNING: failed decoding unknown ioctl 0x%x\n", request); | ||
| 1833 | else | ||
| 1834 | desc = &decoded_desc; | ||
| 1835 | } | ||
| 1836 | |||
| 1837 | if (desc) ioctl_common_pre(ctx, desc, d, request, arg); | ||
| 1838 | int res = REAL(ioctl)(d, request, arg); | ||
| 1839 | // FIXME: some ioctls have different return values for success and failure. | ||
| 1840 | if (desc && res != -1) ioctl_common_post(ctx, desc, res, d, request, arg); | ||
| 1841 | return res; | ||
| 1842 | } | ||
| 1843 | #define INIT_IOCTL \ | ||
| 1844 | ioctl_init(); \ | ||
| 1845 | COMMON_INTERCEPT_FUNCTION(ioctl); | ||
| 1846 | #else | ||
| 1847 | #define INIT_IOCTL | ||
| 1848 | #endif | ||
| 1849 | |||
| 1850 | #if SANITIZER_POSIX | ||
| 1851 | UNUSED static void unpoison_passwd(void *ctx, __sanitizer_passwd *pwd) { | ||
| 1852 | if (pwd) { | ||
| 1853 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, sizeof(*pwd)); | ||
| 1854 | if (pwd->pw_name) | ||
| 1855 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_name, | ||
| 1856 | REAL(strlen)(pwd->pw_name) + 1); | ||
| 1857 | if (pwd->pw_passwd) | ||
| 1858 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_passwd, | ||
| 1859 | REAL(strlen)(pwd->pw_passwd) + 1); | ||
| 1860 | #if !SANITIZER_ANDROID | ||
| 1861 | if (pwd->pw_gecos) | ||
| 1862 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_gecos, | ||
| 1863 | REAL(strlen)(pwd->pw_gecos) + 1); | ||
| 1864 | #endif | ||
| 1865 | #if SANITIZER_MAC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD | ||
| 1866 | if (pwd->pw_class) | ||
| 1867 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_class, | ||
| 1868 | REAL(strlen)(pwd->pw_class) + 1); | ||
| 1869 | #endif | ||
| 1870 | if (pwd->pw_dir) | ||
| 1871 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_dir, | ||
| 1872 | REAL(strlen)(pwd->pw_dir) + 1); | ||
| 1873 | if (pwd->pw_shell) | ||
| 1874 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_shell, | ||
| 1875 | REAL(strlen)(pwd->pw_shell) + 1); | ||
| 1876 | } | ||
| 1877 | } | ||
| 1878 | |||
| 1879 | UNUSED static void unpoison_group(void *ctx, __sanitizer_group *grp) { | ||
| 1880 | if (grp) { | ||
| 1881 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, sizeof(*grp)); | ||
| 1882 | if (grp->gr_name) | ||
| 1883 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp->gr_name, | ||
| 1884 | REAL(strlen)(grp->gr_name) + 1); | ||
| 1885 | if (grp->gr_passwd) | ||
| 1886 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp->gr_passwd, | ||
| 1887 | REAL(strlen)(grp->gr_passwd) + 1); | ||
| 1888 | char **p = grp->gr_mem; | ||
| 1889 | for (; *p; ++p) { | ||
| 1890 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, REAL(strlen)(*p) + 1); | ||
| 1891 | } | ||
| 1892 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp->gr_mem, | ||
| 1893 | (p - grp->gr_mem + 1) * sizeof(*p)); | ||
| 1894 | } | ||
| 1895 | } | ||
| 1896 | #endif // SANITIZER_POSIX | ||
| 1897 | |||
| 1898 | #if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS | ||
| 1899 | INTERCEPTOR(__sanitizer_passwd *, getpwnam, const char *name) { | ||
| 1900 | void *ctx; | ||
| 1901 | COMMON_INTERCEPTOR_ENTER(ctx, getpwnam, name); | ||
| 1902 | if (name) | ||
| 1903 | COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 1904 | __sanitizer_passwd *res = REAL(getpwnam)(name); | ||
| 1905 | unpoison_passwd(ctx, res); | ||
| 1906 | return res; | ||
| 1907 | } | ||
| 1908 | INTERCEPTOR(__sanitizer_passwd *, getpwuid, u32 uid) { | ||
| 1909 | void *ctx; | ||
| 1910 | COMMON_INTERCEPTOR_ENTER(ctx, getpwuid, uid); | ||
| 1911 | __sanitizer_passwd *res = REAL(getpwuid)(uid); | ||
| 1912 | unpoison_passwd(ctx, res); | ||
| 1913 | return res; | ||
| 1914 | } | ||
| 1915 | INTERCEPTOR(__sanitizer_group *, getgrnam, const char *name) { | ||
| 1916 | void *ctx; | ||
| 1917 | COMMON_INTERCEPTOR_ENTER(ctx, getgrnam, name); | ||
| 1918 | COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 1919 | __sanitizer_group *res = REAL(getgrnam)(name); | ||
| 1920 | unpoison_group(ctx, res); | ||
| 1921 | return res; | ||
| 1922 | } | ||
| 1923 | INTERCEPTOR(__sanitizer_group *, getgrgid, u32 gid) { | ||
| 1924 | void *ctx; | ||
| 1925 | COMMON_INTERCEPTOR_ENTER(ctx, getgrgid, gid); | ||
| 1926 | __sanitizer_group *res = REAL(getgrgid)(gid); | ||
| 1927 | unpoison_group(ctx, res); | ||
| 1928 | return res; | ||
| 1929 | } | ||
| 1930 | #define INIT_GETPWNAM_AND_FRIENDS \ | ||
| 1931 | COMMON_INTERCEPT_FUNCTION(getpwnam); \ | ||
| 1932 | COMMON_INTERCEPT_FUNCTION(getpwuid); \ | ||
| 1933 | COMMON_INTERCEPT_FUNCTION(getgrnam); \ | ||
| 1934 | COMMON_INTERCEPT_FUNCTION(getgrgid); | ||
| 1935 | #else | ||
| 1936 | #define INIT_GETPWNAM_AND_FRIENDS | ||
| 1937 | #endif | ||
| 1938 | |||
| 1939 | #if SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS | ||
| 1940 | INTERCEPTOR(int, getpwnam_r, const char *name, __sanitizer_passwd *pwd, | ||
| 1941 | char *buf, SIZE_T buflen, __sanitizer_passwd **result) { | ||
| 1942 | void *ctx; | ||
| 1943 | COMMON_INTERCEPTOR_ENTER(ctx, getpwnam_r, name, pwd, buf, buflen, result); | ||
| 1944 | COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 1945 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 1946 | // its metadata. See | ||
| 1947 | // https://github.com/google/sanitizers/issues/321. | ||
| 1948 | int res = REAL(getpwnam_r)(name, pwd, buf, buflen, result); | ||
| 1949 | if (!res && result) | ||
| 1950 | unpoison_passwd(ctx, *result); | ||
| 1951 | if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); | ||
| 1952 | return res; | ||
| 1953 | } | ||
| 1954 | INTERCEPTOR(int, getpwuid_r, u32 uid, __sanitizer_passwd *pwd, char *buf, | ||
| 1955 | SIZE_T buflen, __sanitizer_passwd **result) { | ||
| 1956 | void *ctx; | ||
| 1957 | COMMON_INTERCEPTOR_ENTER(ctx, getpwuid_r, uid, pwd, buf, buflen, result); | ||
| 1958 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 1959 | // its metadata. See | ||
| 1960 | // https://github.com/google/sanitizers/issues/321. | ||
| 1961 | int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result); | ||
| 1962 | if (!res && result) | ||
| 1963 | unpoison_passwd(ctx, *result); | ||
| 1964 | if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); | ||
| 1965 | return res; | ||
| 1966 | } | ||
| 1967 | INTERCEPTOR(int, getgrnam_r, const char *name, __sanitizer_group *grp, | ||
| 1968 | char *buf, SIZE_T buflen, __sanitizer_group **result) { | ||
| 1969 | void *ctx; | ||
| 1970 | COMMON_INTERCEPTOR_ENTER(ctx, getgrnam_r, name, grp, buf, buflen, result); | ||
| 1971 | COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 1972 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 1973 | // its metadata. See | ||
| 1974 | // https://github.com/google/sanitizers/issues/321. | ||
| 1975 | int res = REAL(getgrnam_r)(name, grp, buf, buflen, result); | ||
| 1976 | if (!res && result) | ||
| 1977 | unpoison_group(ctx, *result); | ||
| 1978 | if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); | ||
| 1979 | return res; | ||
| 1980 | } | ||
| 1981 | INTERCEPTOR(int, getgrgid_r, u32 gid, __sanitizer_group *grp, char *buf, | ||
| 1982 | SIZE_T buflen, __sanitizer_group **result) { | ||
| 1983 | void *ctx; | ||
| 1984 | COMMON_INTERCEPTOR_ENTER(ctx, getgrgid_r, gid, grp, buf, buflen, result); | ||
| 1985 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 1986 | // its metadata. See | ||
| 1987 | // https://github.com/google/sanitizers/issues/321. | ||
| 1988 | int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result); | ||
| 1989 | if (!res && result) | ||
| 1990 | unpoison_group(ctx, *result); | ||
| 1991 | if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); | ||
| 1992 | return res; | ||
| 1993 | } | ||
| 1994 | #define INIT_GETPWNAM_R_AND_FRIENDS \ | ||
| 1995 | COMMON_INTERCEPT_FUNCTION(getpwnam_r); \ | ||
| 1996 | COMMON_INTERCEPT_FUNCTION(getpwuid_r); \ | ||
| 1997 | COMMON_INTERCEPT_FUNCTION(getgrnam_r); \ | ||
| 1998 | COMMON_INTERCEPT_FUNCTION(getgrgid_r); | ||
| 1999 | #else | ||
| 2000 | #define INIT_GETPWNAM_R_AND_FRIENDS | ||
| 2001 | #endif | ||
| 2002 | |||
| 2003 | #if SANITIZER_INTERCEPT_GETPWENT | ||
| 2004 | INTERCEPTOR(__sanitizer_passwd *, getpwent, int dummy) { | ||
| 2005 | void *ctx; | ||
| 2006 | COMMON_INTERCEPTOR_ENTER(ctx, getpwent, dummy); | ||
| 2007 | __sanitizer_passwd *res = REAL(getpwent)(dummy); | ||
| 2008 | unpoison_passwd(ctx, res); | ||
| 2009 | return res; | ||
| 2010 | } | ||
| 2011 | INTERCEPTOR(__sanitizer_group *, getgrent, int dummy) { | ||
| 2012 | void *ctx; | ||
| 2013 | COMMON_INTERCEPTOR_ENTER(ctx, getgrent, dummy); | ||
| 2014 | __sanitizer_group *res = REAL(getgrent)(dummy); | ||
| 2015 | unpoison_group(ctx, res); | ||
| 2016 | return res; | ||
| 2017 | } | ||
| 2018 | #define INIT_GETPWENT \ | ||
| 2019 | COMMON_INTERCEPT_FUNCTION(getpwent); \ | ||
| 2020 | COMMON_INTERCEPT_FUNCTION(getgrent); | ||
| 2021 | #else | ||
| 2022 | #define INIT_GETPWENT | ||
| 2023 | #endif | ||
| 2024 | |||
| 2025 | #if SANITIZER_INTERCEPT_FGETPWENT | ||
| 2026 | INTERCEPTOR(__sanitizer_passwd *, fgetpwent, void *fp) { | ||
| 2027 | void *ctx; | ||
| 2028 | COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent, fp); | ||
| 2029 | __sanitizer_passwd *res = REAL(fgetpwent)(fp); | ||
| 2030 | unpoison_passwd(ctx, res); | ||
| 2031 | return res; | ||
| 2032 | } | ||
| 2033 | INTERCEPTOR(__sanitizer_group *, fgetgrent, void *fp) { | ||
| 2034 | void *ctx; | ||
| 2035 | COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent, fp); | ||
| 2036 | __sanitizer_group *res = REAL(fgetgrent)(fp); | ||
| 2037 | unpoison_group(ctx, res); | ||
| 2038 | return res; | ||
| 2039 | } | ||
| 2040 | #define INIT_FGETPWENT \ | ||
| 2041 | COMMON_INTERCEPT_FUNCTION(fgetpwent); \ | ||
| 2042 | COMMON_INTERCEPT_FUNCTION(fgetgrent); | ||
| 2043 | #else | ||
| 2044 | #define INIT_FGETPWENT | ||
| 2045 | #endif | ||
| 2046 | |||
| 2047 | #if SANITIZER_INTERCEPT_GETPWENT_R | ||
| 2048 | INTERCEPTOR(int, getpwent_r, __sanitizer_passwd *pwbuf, char *buf, | ||
| 2049 | SIZE_T buflen, __sanitizer_passwd **pwbufp) { | ||
| 2050 | void *ctx; | ||
| 2051 | COMMON_INTERCEPTOR_ENTER(ctx, getpwent_r, pwbuf, buf, buflen, pwbufp); | ||
| 2052 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2053 | // its metadata. See | ||
| 2054 | // https://github.com/google/sanitizers/issues/321. | ||
| 2055 | int res = REAL(getpwent_r)(pwbuf, buf, buflen, pwbufp); | ||
| 2056 | if (!res && pwbufp) | ||
| 2057 | unpoison_passwd(ctx, *pwbufp); | ||
| 2058 | if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp)); | ||
| 2059 | return res; | ||
| 2060 | } | ||
| 2061 | INTERCEPTOR(int, getgrent_r, __sanitizer_group *pwbuf, char *buf, SIZE_T buflen, | ||
| 2062 | __sanitizer_group **pwbufp) { | ||
| 2063 | void *ctx; | ||
| 2064 | COMMON_INTERCEPTOR_ENTER(ctx, getgrent_r, pwbuf, buf, buflen, pwbufp); | ||
| 2065 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2066 | // its metadata. See | ||
| 2067 | // https://github.com/google/sanitizers/issues/321. | ||
| 2068 | int res = REAL(getgrent_r)(pwbuf, buf, buflen, pwbufp); | ||
| 2069 | if (!res && pwbufp) | ||
| 2070 | unpoison_group(ctx, *pwbufp); | ||
| 2071 | if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp)); | ||
| 2072 | return res; | ||
| 2073 | } | ||
| 2074 | #define INIT_GETPWENT_R \ | ||
| 2075 | COMMON_INTERCEPT_FUNCTION(getpwent_r); \ | ||
| 2076 | COMMON_INTERCEPT_FUNCTION(getgrent_r); | ||
| 2077 | #else | ||
| 2078 | #define INIT_GETPWENT_R | ||
| 2079 | #endif | ||
| 2080 | |||
| 2081 | #if SANITIZER_INTERCEPT_FGETPWENT_R | ||
| 2082 | INTERCEPTOR(int, fgetpwent_r, void *fp, __sanitizer_passwd *pwbuf, char *buf, | ||
| 2083 | SIZE_T buflen, __sanitizer_passwd **pwbufp) { | ||
| 2084 | void *ctx; | ||
| 2085 | COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent_r, fp, pwbuf, buf, buflen, pwbufp); | ||
| 2086 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2087 | // its metadata. See | ||
| 2088 | // https://github.com/google/sanitizers/issues/321. | ||
| 2089 | int res = REAL(fgetpwent_r)(fp, pwbuf, buf, buflen, pwbufp); | ||
| 2090 | if (!res && pwbufp) | ||
| 2091 | unpoison_passwd(ctx, *pwbufp); | ||
| 2092 | if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp)); | ||
| 2093 | return res; | ||
| 2094 | } | ||
| 2095 | #define INIT_FGETPWENT_R \ | ||
| 2096 | COMMON_INTERCEPT_FUNCTION(fgetpwent_r); | ||
| 2097 | #else | ||
| 2098 | #define INIT_FGETPWENT_R | ||
| 2099 | #endif | ||
| 2100 | |||
| 2101 | #if SANITIZER_INTERCEPT_FGETGRENT_R | ||
| 2102 | INTERCEPTOR(int, fgetgrent_r, void *fp, __sanitizer_group *pwbuf, char *buf, | ||
| 2103 | SIZE_T buflen, __sanitizer_group **pwbufp) { | ||
| 2104 | void *ctx; | ||
| 2105 | COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent_r, fp, pwbuf, buf, buflen, pwbufp); | ||
| 2106 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2107 | // its metadata. See | ||
| 2108 | // https://github.com/google/sanitizers/issues/321. | ||
| 2109 | int res = REAL(fgetgrent_r)(fp, pwbuf, buf, buflen, pwbufp); | ||
| 2110 | if (!res && pwbufp) | ||
| 2111 | unpoison_group(ctx, *pwbufp); | ||
| 2112 | if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp)); | ||
| 2113 | return res; | ||
| 2114 | } | ||
| 2115 | #define INIT_FGETGRENT_R \ | ||
| 2116 | COMMON_INTERCEPT_FUNCTION(fgetgrent_r); | ||
| 2117 | #else | ||
| 2118 | #define INIT_FGETGRENT_R | ||
| 2119 | #endif | ||
| 2120 | |||
| 2121 | #if SANITIZER_INTERCEPT_SETPWENT | ||
| 2122 | // The only thing these interceptors do is disable any nested interceptors. | ||
| 2123 | // These functions may open nss modules and call uninstrumented functions from | ||
| 2124 | // them, and we don't want things like strlen() to trigger. | ||
| 2125 | INTERCEPTOR(void, setpwent, int dummy) { | ||
| 2126 | void *ctx; | ||
| 2127 | COMMON_INTERCEPTOR_ENTER(ctx, setpwent, dummy); | ||
| 2128 | REAL(setpwent)(dummy); | ||
| 2129 | } | ||
| 2130 | INTERCEPTOR(void, endpwent, int dummy) { | ||
| 2131 | void *ctx; | ||
| 2132 | COMMON_INTERCEPTOR_ENTER(ctx, endpwent, dummy); | ||
| 2133 | REAL(endpwent)(dummy); | ||
| 2134 | } | ||
| 2135 | INTERCEPTOR(void, setgrent, int dummy) { | ||
| 2136 | void *ctx; | ||
| 2137 | COMMON_INTERCEPTOR_ENTER(ctx, setgrent, dummy); | ||
| 2138 | REAL(setgrent)(dummy); | ||
| 2139 | } | ||
| 2140 | INTERCEPTOR(void, endgrent, int dummy) { | ||
| 2141 | void *ctx; | ||
| 2142 | COMMON_INTERCEPTOR_ENTER(ctx, endgrent, dummy); | ||
| 2143 | REAL(endgrent)(dummy); | ||
| 2144 | } | ||
| 2145 | #define INIT_SETPWENT \ | ||
| 2146 | COMMON_INTERCEPT_FUNCTION(setpwent); \ | ||
| 2147 | COMMON_INTERCEPT_FUNCTION(endpwent); \ | ||
| 2148 | COMMON_INTERCEPT_FUNCTION(setgrent); \ | ||
| 2149 | COMMON_INTERCEPT_FUNCTION(endgrent); | ||
| 2150 | #else | ||
| 2151 | #define INIT_SETPWENT | ||
| 2152 | #endif | ||
| 2153 | |||
| 2154 | #if SANITIZER_INTERCEPT_CLOCK_GETTIME | ||
| 2155 | INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) { | ||
| 2156 | void *ctx; | ||
| 2157 | COMMON_INTERCEPTOR_ENTER(ctx, clock_getres, clk_id, tp); | ||
| 2158 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2159 | // its metadata. See | ||
| 2160 | // https://github.com/google/sanitizers/issues/321. | ||
| 2161 | int res = REAL(clock_getres)(clk_id, tp); | ||
| 2162 | if (!res && tp) { | ||
| 2163 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz); | ||
| 2164 | } | ||
| 2165 | return res; | ||
| 2166 | } | ||
| 2167 | INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) { | ||
| 2168 | void *ctx; | ||
| 2169 | COMMON_INTERCEPTOR_ENTER(ctx, clock_gettime, clk_id, tp); | ||
| 2170 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2171 | // its metadata. See | ||
| 2172 | // https://github.com/google/sanitizers/issues/321. | ||
| 2173 | int res = REAL(clock_gettime)(clk_id, tp); | ||
| 2174 | if (!res) { | ||
| 2175 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz); | ||
| 2176 | } | ||
| 2177 | return res; | ||
| 2178 | } | ||
| 2179 | namespace __sanitizer { | ||
| 2180 | extern "C" { | ||
| 2181 | int real_clock_gettime(u32 clk_id, void *tp) { | ||
| 2182 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) | ||
| 2183 | return internal_clock_gettime(clk_id, tp); | ||
| 2184 | return REAL(clock_gettime)(clk_id, tp); | ||
| 2185 | } | ||
| 2186 | } // extern "C" | ||
| 2187 | } // namespace __sanitizer | ||
| 2188 | INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) { | ||
| 2189 | void *ctx; | ||
| 2190 | COMMON_INTERCEPTOR_ENTER(ctx, clock_settime, clk_id, tp); | ||
| 2191 | COMMON_INTERCEPTOR_READ_RANGE(ctx, tp, struct_timespec_sz); | ||
| 2192 | return REAL(clock_settime)(clk_id, tp); | ||
| 2193 | } | ||
| 2194 | #define INIT_CLOCK_GETTIME \ | ||
| 2195 | COMMON_INTERCEPT_FUNCTION(clock_getres); \ | ||
| 2196 | COMMON_INTERCEPT_FUNCTION(clock_gettime); \ | ||
| 2197 | COMMON_INTERCEPT_FUNCTION(clock_settime); | ||
| 2198 | #else | ||
| 2199 | #define INIT_CLOCK_GETTIME | ||
| 2200 | #endif | ||
| 2201 | |||
| 2202 | #if SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID | ||
| 2203 | INTERCEPTOR(int, clock_getcpuclockid, pid_t pid, | ||
| 2204 | __sanitizer_clockid_t *clockid) { | ||
| 2205 | void *ctx; | ||
| 2206 | COMMON_INTERCEPTOR_ENTER(ctx, clock_getcpuclockid, pid, clockid); | ||
| 2207 | int res = REAL(clock_getcpuclockid)(pid, clockid); | ||
| 2208 | if (!res && clockid) { | ||
| 2209 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, clockid, sizeof *clockid); | ||
| 2210 | } | ||
| 2211 | return res; | ||
| 2212 | } | ||
| 2213 | |||
| 2214 | #define INIT_CLOCK_GETCPUCLOCKID \ | ||
| 2215 | COMMON_INTERCEPT_FUNCTION(clock_getcpuclockid); | ||
| 2216 | #else | ||
| 2217 | #define INIT_CLOCK_GETCPUCLOCKID | ||
| 2218 | #endif | ||
| 2219 | |||
| 2220 | #if SANITIZER_INTERCEPT_GETITIMER | ||
| 2221 | INTERCEPTOR(int, getitimer, int which, void *curr_value) { | ||
| 2222 | void *ctx; | ||
| 2223 | COMMON_INTERCEPTOR_ENTER(ctx, getitimer, which, curr_value); | ||
| 2224 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2225 | // its metadata. See | ||
| 2226 | // https://github.com/google/sanitizers/issues/321. | ||
| 2227 | int res = REAL(getitimer)(which, curr_value); | ||
| 2228 | if (!res && curr_value) { | ||
| 2229 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerval_sz); | ||
| 2230 | } | ||
| 2231 | return res; | ||
| 2232 | } | ||
| 2233 | INTERCEPTOR(int, setitimer, int which, const void *new_value, void *old_value) { | ||
| 2234 | void *ctx; | ||
| 2235 | COMMON_INTERCEPTOR_ENTER(ctx, setitimer, which, new_value, old_value); | ||
| 2236 | if (new_value) { | ||
| 2237 | // itimerval can contain padding that may be legitimately uninitialized | ||
| 2238 | const struct __sanitizer_itimerval *nv = | ||
| 2239 | (const struct __sanitizer_itimerval *)new_value; | ||
| 2240 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &nv->it_interval.tv_sec, | ||
| 2241 | sizeof(__sanitizer_time_t)); | ||
| 2242 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &nv->it_interval.tv_usec, | ||
| 2243 | sizeof(__sanitizer_suseconds_t)); | ||
| 2244 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &nv->it_value.tv_sec, | ||
| 2245 | sizeof(__sanitizer_time_t)); | ||
| 2246 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &nv->it_value.tv_usec, | ||
| 2247 | sizeof(__sanitizer_suseconds_t)); | ||
| 2248 | } | ||
| 2249 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2250 | // its metadata. See | ||
| 2251 | // https://github.com/google/sanitizers/issues/321. | ||
| 2252 | int res = REAL(setitimer)(which, new_value, old_value); | ||
| 2253 | if (!res && old_value) { | ||
| 2254 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerval_sz); | ||
| 2255 | } | ||
| 2256 | return res; | ||
| 2257 | } | ||
| 2258 | #define INIT_GETITIMER \ | ||
| 2259 | COMMON_INTERCEPT_FUNCTION(getitimer); \ | ||
| 2260 | COMMON_INTERCEPT_FUNCTION(setitimer); | ||
| 2261 | #else | ||
| 2262 | #define INIT_GETITIMER | ||
| 2263 | #endif | ||
| 2264 | |||
| 2265 | #if SANITIZER_INTERCEPT_GLOB | ||
| 2266 | static void unpoison_glob_t(void *ctx, __sanitizer_glob_t *pglob) { | ||
| 2267 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pglob, sizeof(*pglob)); | ||
| 2268 | // +1 for NULL pointer at the end. | ||
| 2269 | if (pglob->gl_pathv) | ||
| 2270 | COMMON_INTERCEPTOR_WRITE_RANGE( | ||
| 2271 | ctx, pglob->gl_pathv, (pglob->gl_pathc + 1) * sizeof(*pglob->gl_pathv)); | ||
| 2272 | for (SIZE_T i = 0; i < pglob->gl_pathc; ++i) { | ||
| 2273 | char *p = pglob->gl_pathv[i]; | ||
| 2274 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, REAL(strlen)(p) + 1); | ||
| 2275 | } | ||
| 2276 | } | ||
| 2277 | |||
| 2278 | #if SANITIZER_SOLARIS | ||
| 2279 | INTERCEPTOR(int, glob, const char *pattern, int flags, | ||
| 2280 | int (*errfunc)(const char *epath, int eerrno), | ||
| 2281 | __sanitizer_glob_t *pglob) { | ||
| 2282 | void *ctx; | ||
| 2283 | COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob); | ||
| 2284 | COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0); | ||
| 2285 | int res = REAL(glob)(pattern, flags, errfunc, pglob); | ||
| 2286 | if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob); | ||
| 2287 | return res; | ||
| 2288 | } | ||
| 2289 | #else | ||
| 2290 | static THREADLOCAL __sanitizer_glob_t *pglob_copy; | ||
| 2291 | |||
| 2292 | static void wrapped_gl_closedir(void *dir) { | ||
| 2293 | COMMON_INTERCEPTOR_UNPOISON_PARAM(1); | ||
| 2294 | pglob_copy->gl_closedir(dir); | ||
| 2295 | } | ||
| 2296 | |||
| 2297 | static void *wrapped_gl_readdir(void *dir) { | ||
| 2298 | COMMON_INTERCEPTOR_UNPOISON_PARAM(1); | ||
| 2299 | return pglob_copy->gl_readdir(dir); | ||
| 2300 | } | ||
| 2301 | |||
| 2302 | static void *wrapped_gl_opendir(const char *s) { | ||
| 2303 | COMMON_INTERCEPTOR_UNPOISON_PARAM(1); | ||
| 2304 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1); | ||
| 2305 | return pglob_copy->gl_opendir(s); | ||
| 2306 | } | ||
| 2307 | |||
| 2308 | static int wrapped_gl_lstat(const char *s, void *st) { | ||
| 2309 | COMMON_INTERCEPTOR_UNPOISON_PARAM(2); | ||
| 2310 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1); | ||
| 2311 | return pglob_copy->gl_lstat(s, st); | ||
| 2312 | } | ||
| 2313 | |||
| 2314 | static int wrapped_gl_stat(const char *s, void *st) { | ||
| 2315 | COMMON_INTERCEPTOR_UNPOISON_PARAM(2); | ||
| 2316 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1); | ||
| 2317 | return pglob_copy->gl_stat(s, st); | ||
| 2318 | } | ||
| 2319 | |||
| 2320 | static const __sanitizer_glob_t kGlobCopy = { | ||
| 2321 | 0, 0, 0, | ||
| 2322 | 0, wrapped_gl_closedir, wrapped_gl_readdir, | ||
| 2323 | wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat}; | ||
| 2324 | |||
| 2325 | INTERCEPTOR(int, glob, const char *pattern, int flags, | ||
| 2326 | int (*errfunc)(const char *epath, int eerrno), | ||
| 2327 | __sanitizer_glob_t *pglob) { | ||
| 2328 | void *ctx; | ||
| 2329 | COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob); | ||
| 2330 | COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0); | ||
| 2331 | __sanitizer_glob_t glob_copy; | ||
| 2332 | internal_memcpy(&glob_copy, &kGlobCopy, sizeof(glob_copy)); | ||
| 2333 | if (flags & glob_altdirfunc) { | ||
| 2334 | Swap(pglob->gl_closedir, glob_copy.gl_closedir); | ||
| 2335 | Swap(pglob->gl_readdir, glob_copy.gl_readdir); | ||
| 2336 | Swap(pglob->gl_opendir, glob_copy.gl_opendir); | ||
| 2337 | Swap(pglob->gl_lstat, glob_copy.gl_lstat); | ||
| 2338 | Swap(pglob->gl_stat, glob_copy.gl_stat); | ||
| 2339 | pglob_copy = &glob_copy; | ||
| 2340 | } | ||
| 2341 | int res = REAL(glob)(pattern, flags, errfunc, pglob); | ||
| 2342 | if (flags & glob_altdirfunc) { | ||
| 2343 | Swap(pglob->gl_closedir, glob_copy.gl_closedir); | ||
| 2344 | Swap(pglob->gl_readdir, glob_copy.gl_readdir); | ||
| 2345 | Swap(pglob->gl_opendir, glob_copy.gl_opendir); | ||
| 2346 | Swap(pglob->gl_lstat, glob_copy.gl_lstat); | ||
| 2347 | Swap(pglob->gl_stat, glob_copy.gl_stat); | ||
| 2348 | } | ||
| 2349 | pglob_copy = 0; | ||
| 2350 | if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob); | ||
| 2351 | return res; | ||
| 2352 | } | ||
| 2353 | #endif // SANITIZER_SOLARIS | ||
| 2354 | #define INIT_GLOB \ | ||
| 2355 | COMMON_INTERCEPT_FUNCTION(glob); | ||
| 2356 | #else // SANITIZER_INTERCEPT_GLOB | ||
| 2357 | #define INIT_GLOB | ||
| 2358 | #endif // SANITIZER_INTERCEPT_GLOB | ||
| 2359 | |||
| 2360 | #if SANITIZER_INTERCEPT_GLOB64 | ||
| 2361 | INTERCEPTOR(int, glob64, const char *pattern, int flags, | ||
| 2362 | int (*errfunc)(const char *epath, int eerrno), | ||
| 2363 | __sanitizer_glob_t *pglob) { | ||
| 2364 | void *ctx; | ||
| 2365 | COMMON_INTERCEPTOR_ENTER(ctx, glob64, pattern, flags, errfunc, pglob); | ||
| 2366 | COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0); | ||
| 2367 | __sanitizer_glob_t glob_copy; | ||
| 2368 | internal_memcpy(&glob_copy, &kGlobCopy, sizeof(glob_copy)); | ||
| 2369 | if (flags & glob_altdirfunc) { | ||
| 2370 | Swap(pglob->gl_closedir, glob_copy.gl_closedir); | ||
| 2371 | Swap(pglob->gl_readdir, glob_copy.gl_readdir); | ||
| 2372 | Swap(pglob->gl_opendir, glob_copy.gl_opendir); | ||
| 2373 | Swap(pglob->gl_lstat, glob_copy.gl_lstat); | ||
| 2374 | Swap(pglob->gl_stat, glob_copy.gl_stat); | ||
| 2375 | pglob_copy = &glob_copy; | ||
| 2376 | } | ||
| 2377 | int res = REAL(glob64)(pattern, flags, errfunc, pglob); | ||
| 2378 | if (flags & glob_altdirfunc) { | ||
| 2379 | Swap(pglob->gl_closedir, glob_copy.gl_closedir); | ||
| 2380 | Swap(pglob->gl_readdir, glob_copy.gl_readdir); | ||
| 2381 | Swap(pglob->gl_opendir, glob_copy.gl_opendir); | ||
| 2382 | Swap(pglob->gl_lstat, glob_copy.gl_lstat); | ||
| 2383 | Swap(pglob->gl_stat, glob_copy.gl_stat); | ||
| 2384 | } | ||
| 2385 | pglob_copy = 0; | ||
| 2386 | if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob); | ||
| 2387 | return res; | ||
| 2388 | } | ||
| 2389 | #define INIT_GLOB64 \ | ||
| 2390 | COMMON_INTERCEPT_FUNCTION(glob64); | ||
| 2391 | #else // SANITIZER_INTERCEPT_GLOB64 | ||
| 2392 | #define INIT_GLOB64 | ||
| 2393 | #endif // SANITIZER_INTERCEPT_GLOB64 | ||
| 2394 | |||
| 2395 | #if SANITIZER_INTERCEPT_WAIT | ||
| 2396 | // According to sys/wait.h, wait(), waitid(), waitpid() may have symbol version | ||
| 2397 | // suffixes on Darwin. See the declaration of INTERCEPTOR_WITH_SUFFIX for | ||
| 2398 | // details. | ||
| 2399 | INTERCEPTOR_WITH_SUFFIX(int, wait, int *status) { | ||
| 2400 | void *ctx; | ||
| 2401 | COMMON_INTERCEPTOR_ENTER(ctx, wait, status); | ||
| 2402 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2403 | // its metadata. See | ||
| 2404 | // https://github.com/google/sanitizers/issues/321. | ||
| 2405 | int res = REAL(wait)(status); | ||
| 2406 | if (res != -1 && status) | ||
| 2407 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); | ||
| 2408 | return res; | ||
| 2409 | } | ||
| 2410 | // On FreeBSD id_t is always 64-bit wide. | ||
| 2411 | #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) | ||
| 2412 | INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, long long id, void *infop, | ||
| 2413 | int options) { | ||
| 2414 | #else | ||
| 2415 | INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop, | ||
| 2416 | int options) { | ||
| 2417 | #endif | ||
| 2418 | void *ctx; | ||
| 2419 | COMMON_INTERCEPTOR_ENTER(ctx, waitid, idtype, id, infop, options); | ||
| 2420 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2421 | // its metadata. See | ||
| 2422 | // https://github.com/google/sanitizers/issues/321. | ||
| 2423 | int res = REAL(waitid)(idtype, id, infop, options); | ||
| 2424 | if (res != -1 && infop) | ||
| 2425 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, infop, siginfo_t_sz); | ||
| 2426 | return res; | ||
| 2427 | } | ||
| 2428 | INTERCEPTOR_WITH_SUFFIX(int, waitpid, int pid, int *status, int options) { | ||
| 2429 | void *ctx; | ||
| 2430 | COMMON_INTERCEPTOR_ENTER(ctx, waitpid, pid, status, options); | ||
| 2431 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2432 | // its metadata. See | ||
| 2433 | // https://github.com/google/sanitizers/issues/321. | ||
| 2434 | int res = REAL(waitpid)(pid, status, options); | ||
| 2435 | if (res != -1 && status) | ||
| 2436 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); | ||
| 2437 | return res; | ||
| 2438 | } | ||
| 2439 | INTERCEPTOR(int, wait3, int *status, int options, void *rusage) { | ||
| 2440 | void *ctx; | ||
| 2441 | COMMON_INTERCEPTOR_ENTER(ctx, wait3, status, options, rusage); | ||
| 2442 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2443 | // its metadata. See | ||
| 2444 | // https://github.com/google/sanitizers/issues/321. | ||
| 2445 | int res = REAL(wait3)(status, options, rusage); | ||
| 2446 | if (res != -1) { | ||
| 2447 | if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); | ||
| 2448 | if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz); | ||
| 2449 | } | ||
| 2450 | return res; | ||
| 2451 | } | ||
| 2452 | #if SANITIZER_ANDROID | ||
| 2453 | INTERCEPTOR(int, __wait4, int pid, int *status, int options, void *rusage) { | ||
| 2454 | void *ctx; | ||
| 2455 | COMMON_INTERCEPTOR_ENTER(ctx, __wait4, pid, status, options, rusage); | ||
| 2456 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2457 | // its metadata. See | ||
| 2458 | // https://github.com/google/sanitizers/issues/321. | ||
| 2459 | int res = REAL(__wait4)(pid, status, options, rusage); | ||
| 2460 | if (res != -1) { | ||
| 2461 | if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); | ||
| 2462 | if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz); | ||
| 2463 | } | ||
| 2464 | return res; | ||
| 2465 | } | ||
| 2466 | #define INIT_WAIT4 COMMON_INTERCEPT_FUNCTION(__wait4); | ||
| 2467 | #else | ||
| 2468 | INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) { | ||
| 2469 | void *ctx; | ||
| 2470 | COMMON_INTERCEPTOR_ENTER(ctx, wait4, pid, status, options, rusage); | ||
| 2471 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2472 | // its metadata. See | ||
| 2473 | // https://github.com/google/sanitizers/issues/321. | ||
| 2474 | int res = REAL(wait4)(pid, status, options, rusage); | ||
| 2475 | if (res != -1) { | ||
| 2476 | if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); | ||
| 2477 | if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz); | ||
| 2478 | } | ||
| 2479 | return res; | ||
| 2480 | } | ||
| 2481 | #define INIT_WAIT4 COMMON_INTERCEPT_FUNCTION(wait4); | ||
| 2482 | #endif // SANITIZER_ANDROID | ||
| 2483 | #define INIT_WAIT \ | ||
| 2484 | COMMON_INTERCEPT_FUNCTION(wait); \ | ||
| 2485 | COMMON_INTERCEPT_FUNCTION(waitid); \ | ||
| 2486 | COMMON_INTERCEPT_FUNCTION(waitpid); \ | ||
| 2487 | COMMON_INTERCEPT_FUNCTION(wait3); | ||
| 2488 | #else | ||
| 2489 | #define INIT_WAIT | ||
| 2490 | #define INIT_WAIT4 | ||
| 2491 | #endif | ||
| 2492 | |||
| 2493 | #if SANITIZER_INTERCEPT_INET | ||
| 2494 | INTERCEPTOR(char *, inet_ntop, int af, const void *src, char *dst, u32 size) { | ||
| 2495 | void *ctx; | ||
| 2496 | COMMON_INTERCEPTOR_ENTER(ctx, inet_ntop, af, src, dst, size); | ||
| 2497 | uptr sz = __sanitizer_in_addr_sz(af); | ||
| 2498 | if (sz) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sz); | ||
| 2499 | // FIXME: figure out read size based on the address family. | ||
| 2500 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2501 | // its metadata. See | ||
| 2502 | // https://github.com/google/sanitizers/issues/321. | ||
| 2503 | char *res = REAL(inet_ntop)(af, src, dst, size); | ||
| 2504 | if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); | ||
| 2505 | return res; | ||
| 2506 | } | ||
| 2507 | INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) { | ||
| 2508 | void *ctx; | ||
| 2509 | COMMON_INTERCEPTOR_ENTER(ctx, inet_pton, af, src, dst); | ||
| 2510 | COMMON_INTERCEPTOR_READ_STRING(ctx, src, 0); | ||
| 2511 | // FIXME: figure out read size based on the address family. | ||
| 2512 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2513 | // its metadata. See | ||
| 2514 | // https://github.com/google/sanitizers/issues/321. | ||
| 2515 | int res = REAL(inet_pton)(af, src, dst); | ||
| 2516 | if (res == 1) { | ||
| 2517 | uptr sz = __sanitizer_in_addr_sz(af); | ||
| 2518 | if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sz); | ||
| 2519 | } | ||
| 2520 | return res; | ||
| 2521 | } | ||
| 2522 | #define INIT_INET \ | ||
| 2523 | COMMON_INTERCEPT_FUNCTION(inet_ntop); \ | ||
| 2524 | COMMON_INTERCEPT_FUNCTION(inet_pton); | ||
| 2525 | #else | ||
| 2526 | #define INIT_INET | ||
| 2527 | #endif | ||
| 2528 | |||
| 2529 | #if SANITIZER_INTERCEPT_INET | ||
| 2530 | INTERCEPTOR(int, inet_aton, const char *cp, void *dst) { | ||
| 2531 | void *ctx; | ||
| 2532 | COMMON_INTERCEPTOR_ENTER(ctx, inet_aton, cp, dst); | ||
| 2533 | if (cp) COMMON_INTERCEPTOR_READ_RANGE(ctx, cp, REAL(strlen)(cp) + 1); | ||
| 2534 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2535 | // its metadata. See | ||
| 2536 | // https://github.com/google/sanitizers/issues/321. | ||
| 2537 | int res = REAL(inet_aton)(cp, dst); | ||
| 2538 | if (res != 0) { | ||
| 2539 | uptr sz = __sanitizer_in_addr_sz(af_inet); | ||
| 2540 | if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sz); | ||
| 2541 | } | ||
| 2542 | return res; | ||
| 2543 | } | ||
| 2544 | #define INIT_INET_ATON COMMON_INTERCEPT_FUNCTION(inet_aton); | ||
| 2545 | #else | ||
| 2546 | #define INIT_INET_ATON | ||
| 2547 | #endif | ||
| 2548 | |||
| 2549 | #if SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM | ||
| 2550 | INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) { | ||
| 2551 | void *ctx; | ||
| 2552 | COMMON_INTERCEPTOR_ENTER(ctx, pthread_getschedparam, thread, policy, param); | ||
| 2553 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2554 | // its metadata. See | ||
| 2555 | // https://github.com/google/sanitizers/issues/321. | ||
| 2556 | int res = REAL(pthread_getschedparam)(thread, policy, param); | ||
| 2557 | if (res == 0) { | ||
| 2558 | if (policy) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, policy, sizeof(*policy)); | ||
| 2559 | if (param) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, param, sizeof(*param)); | ||
| 2560 | } | ||
| 2561 | return res; | ||
| 2562 | } | ||
| 2563 | #define INIT_PTHREAD_GETSCHEDPARAM \ | ||
| 2564 | COMMON_INTERCEPT_FUNCTION(pthread_getschedparam); | ||
| 2565 | #else | ||
| 2566 | #define INIT_PTHREAD_GETSCHEDPARAM | ||
| 2567 | #endif | ||
| 2568 | |||
| 2569 | #if SANITIZER_INTERCEPT_GETADDRINFO | ||
| 2570 | INTERCEPTOR(int, getaddrinfo, char *node, char *service, | ||
| 2571 | struct __sanitizer_addrinfo *hints, | ||
| 2572 | struct __sanitizer_addrinfo **out) { | ||
| 2573 | void *ctx; | ||
| 2574 | COMMON_INTERCEPTOR_ENTER(ctx, getaddrinfo, node, service, hints, out); | ||
| 2575 | if (node) COMMON_INTERCEPTOR_READ_RANGE(ctx, node, REAL(strlen)(node) + 1); | ||
| 2576 | if (service) | ||
| 2577 | COMMON_INTERCEPTOR_READ_RANGE(ctx, service, REAL(strlen)(service) + 1); | ||
| 2578 | if (hints) | ||
| 2579 | COMMON_INTERCEPTOR_READ_RANGE(ctx, hints, sizeof(__sanitizer_addrinfo)); | ||
| 2580 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2581 | // its metadata. See | ||
| 2582 | // https://github.com/google/sanitizers/issues/321. | ||
| 2583 | int res = REAL(getaddrinfo)(node, service, hints, out); | ||
| 2584 | if (res == 0 && out) { | ||
| 2585 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, out, sizeof(*out)); | ||
| 2586 | struct __sanitizer_addrinfo *p = *out; | ||
| 2587 | while (p) { | ||
| 2588 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); | ||
| 2589 | if (p->ai_addr) | ||
| 2590 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_addr, p->ai_addrlen); | ||
| 2591 | if (p->ai_canonname) | ||
| 2592 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_canonname, | ||
| 2593 | REAL(strlen)(p->ai_canonname) + 1); | ||
| 2594 | p = p->ai_next; | ||
| 2595 | } | ||
| 2596 | } | ||
| 2597 | return res; | ||
| 2598 | } | ||
| 2599 | #define INIT_GETADDRINFO COMMON_INTERCEPT_FUNCTION(getaddrinfo); | ||
| 2600 | #else | ||
| 2601 | #define INIT_GETADDRINFO | ||
| 2602 | #endif | ||
| 2603 | |||
| 2604 | #if SANITIZER_INTERCEPT_GETNAMEINFO | ||
| 2605 | INTERCEPTOR(int, getnameinfo, void *sockaddr, unsigned salen, char *host, | ||
| 2606 | unsigned hostlen, char *serv, unsigned servlen, int flags) { | ||
| 2607 | void *ctx; | ||
| 2608 | COMMON_INTERCEPTOR_ENTER(ctx, getnameinfo, sockaddr, salen, host, hostlen, | ||
| 2609 | serv, servlen, flags); | ||
| 2610 | // FIXME: consider adding READ_RANGE(sockaddr, salen) | ||
| 2611 | // There is padding in in_addr that may make this too noisy | ||
| 2612 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2613 | // its metadata. See | ||
| 2614 | // https://github.com/google/sanitizers/issues/321. | ||
| 2615 | int res = | ||
| 2616 | REAL(getnameinfo)(sockaddr, salen, host, hostlen, serv, servlen, flags); | ||
| 2617 | if (res == 0) { | ||
| 2618 | if (host && hostlen) | ||
| 2619 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, host, REAL(strlen)(host) + 1); | ||
| 2620 | if (serv && servlen) | ||
| 2621 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, serv, REAL(strlen)(serv) + 1); | ||
| 2622 | } | ||
| 2623 | return res; | ||
| 2624 | } | ||
| 2625 | #define INIT_GETNAMEINFO COMMON_INTERCEPT_FUNCTION(getnameinfo); | ||
| 2626 | #else | ||
| 2627 | #define INIT_GETNAMEINFO | ||
| 2628 | #endif | ||
| 2629 | |||
| 2630 | #if SANITIZER_INTERCEPT_GETSOCKNAME | ||
| 2631 | INTERCEPTOR(int, getsockname, int sock_fd, void *addr, int *addrlen) { | ||
| 2632 | void *ctx; | ||
| 2633 | COMMON_INTERCEPTOR_ENTER(ctx, getsockname, sock_fd, addr, addrlen); | ||
| 2634 | COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); | ||
| 2635 | int addrlen_in = *addrlen; | ||
| 2636 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2637 | // its metadata. See | ||
| 2638 | // https://github.com/google/sanitizers/issues/321. | ||
| 2639 | int res = REAL(getsockname)(sock_fd, addr, addrlen); | ||
| 2640 | if (res == 0) { | ||
| 2641 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addrlen_in, *addrlen)); | ||
| 2642 | } | ||
| 2643 | return res; | ||
| 2644 | } | ||
| 2645 | #define INIT_GETSOCKNAME COMMON_INTERCEPT_FUNCTION(getsockname); | ||
| 2646 | #else | ||
| 2647 | #define INIT_GETSOCKNAME | ||
| 2648 | #endif | ||
| 2649 | |||
| 2650 | #if SANITIZER_INTERCEPT_GETHOSTBYNAME || SANITIZER_INTERCEPT_GETHOSTBYNAME_R | ||
| 2651 | static void write_hostent(void *ctx, struct __sanitizer_hostent *h) { | ||
| 2652 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h, sizeof(__sanitizer_hostent)); | ||
| 2653 | if (h->h_name) | ||
| 2654 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h->h_name, REAL(strlen)(h->h_name) + 1); | ||
| 2655 | char **p = h->h_aliases; | ||
| 2656 | while (*p) { | ||
| 2657 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, REAL(strlen)(*p) + 1); | ||
| 2658 | ++p; | ||
| 2659 | } | ||
| 2660 | COMMON_INTERCEPTOR_WRITE_RANGE( | ||
| 2661 | ctx, h->h_aliases, (p - h->h_aliases + 1) * sizeof(*h->h_aliases)); | ||
| 2662 | p = h->h_addr_list; | ||
| 2663 | while (*p) { | ||
| 2664 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, h->h_length); | ||
| 2665 | ++p; | ||
| 2666 | } | ||
| 2667 | COMMON_INTERCEPTOR_WRITE_RANGE( | ||
| 2668 | ctx, h->h_addr_list, (p - h->h_addr_list + 1) * sizeof(*h->h_addr_list)); | ||
| 2669 | } | ||
| 2670 | #endif | ||
| 2671 | |||
| 2672 | #if SANITIZER_INTERCEPT_GETHOSTBYNAME | ||
| 2673 | INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname, char *name) { | ||
| 2674 | void *ctx; | ||
| 2675 | COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname, name); | ||
| 2676 | struct __sanitizer_hostent *res = REAL(gethostbyname)(name); | ||
| 2677 | if (res) write_hostent(ctx, res); | ||
| 2678 | return res; | ||
| 2679 | } | ||
| 2680 | |||
| 2681 | INTERCEPTOR(struct __sanitizer_hostent *, gethostbyaddr, void *addr, int len, | ||
| 2682 | int type) { | ||
| 2683 | void *ctx; | ||
| 2684 | COMMON_INTERCEPTOR_ENTER(ctx, gethostbyaddr, addr, len, type); | ||
| 2685 | COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, len); | ||
| 2686 | struct __sanitizer_hostent *res = REAL(gethostbyaddr)(addr, len, type); | ||
| 2687 | if (res) write_hostent(ctx, res); | ||
| 2688 | return res; | ||
| 2689 | } | ||
| 2690 | |||
| 2691 | INTERCEPTOR(struct __sanitizer_hostent *, gethostent, int fake) { | ||
| 2692 | void *ctx; | ||
| 2693 | COMMON_INTERCEPTOR_ENTER(ctx, gethostent, fake); | ||
| 2694 | struct __sanitizer_hostent *res = REAL(gethostent)(fake); | ||
| 2695 | if (res) write_hostent(ctx, res); | ||
| 2696 | return res; | ||
| 2697 | } | ||
| 2698 | #define INIT_GETHOSTBYNAME \ | ||
| 2699 | COMMON_INTERCEPT_FUNCTION(gethostent); \ | ||
| 2700 | COMMON_INTERCEPT_FUNCTION(gethostbyaddr); \ | ||
| 2701 | COMMON_INTERCEPT_FUNCTION(gethostbyname); | ||
| 2702 | #else | ||
| 2703 | #define INIT_GETHOSTBYNAME | ||
| 2704 | #endif // SANITIZER_INTERCEPT_GETHOSTBYNAME | ||
| 2705 | |||
| 2706 | #if SANITIZER_INTERCEPT_GETHOSTBYNAME2 | ||
| 2707 | INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname2, char *name, int af) { | ||
| 2708 | void *ctx; | ||
| 2709 | COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname2, name, af); | ||
| 2710 | struct __sanitizer_hostent *res = REAL(gethostbyname2)(name, af); | ||
| 2711 | if (res) write_hostent(ctx, res); | ||
| 2712 | return res; | ||
| 2713 | } | ||
| 2714 | #define INIT_GETHOSTBYNAME2 COMMON_INTERCEPT_FUNCTION(gethostbyname2); | ||
| 2715 | #else | ||
| 2716 | #define INIT_GETHOSTBYNAME2 | ||
| 2717 | #endif // SANITIZER_INTERCEPT_GETHOSTBYNAME2 | ||
| 2718 | |||
| 2719 | #if SANITIZER_INTERCEPT_GETHOSTBYNAME_R | ||
| 2720 | INTERCEPTOR(int, gethostbyname_r, char *name, struct __sanitizer_hostent *ret, | ||
| 2721 | char *buf, SIZE_T buflen, __sanitizer_hostent **result, | ||
| 2722 | int *h_errnop) { | ||
| 2723 | void *ctx; | ||
| 2724 | COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname_r, name, ret, buf, buflen, result, | ||
| 2725 | h_errnop); | ||
| 2726 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2727 | // its metadata. See | ||
| 2728 | // https://github.com/google/sanitizers/issues/321. | ||
| 2729 | int res = REAL(gethostbyname_r)(name, ret, buf, buflen, result, h_errnop); | ||
| 2730 | if (result) { | ||
| 2731 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); | ||
| 2732 | if (res == 0 && *result) write_hostent(ctx, *result); | ||
| 2733 | } | ||
| 2734 | if (h_errnop) | ||
| 2735 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop)); | ||
| 2736 | return res; | ||
| 2737 | } | ||
| 2738 | #define INIT_GETHOSTBYNAME_R COMMON_INTERCEPT_FUNCTION(gethostbyname_r); | ||
| 2739 | #else | ||
| 2740 | #define INIT_GETHOSTBYNAME_R | ||
| 2741 | #endif | ||
| 2742 | |||
| 2743 | #if SANITIZER_INTERCEPT_GETHOSTENT_R | ||
| 2744 | INTERCEPTOR(int, gethostent_r, struct __sanitizer_hostent *ret, char *buf, | ||
| 2745 | SIZE_T buflen, __sanitizer_hostent **result, int *h_errnop) { | ||
| 2746 | void *ctx; | ||
| 2747 | COMMON_INTERCEPTOR_ENTER(ctx, gethostent_r, ret, buf, buflen, result, | ||
| 2748 | h_errnop); | ||
| 2749 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2750 | // its metadata. See | ||
| 2751 | // https://github.com/google/sanitizers/issues/321. | ||
| 2752 | int res = REAL(gethostent_r)(ret, buf, buflen, result, h_errnop); | ||
| 2753 | if (result) { | ||
| 2754 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); | ||
| 2755 | if (res == 0 && *result) write_hostent(ctx, *result); | ||
| 2756 | } | ||
| 2757 | if (h_errnop) | ||
| 2758 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop)); | ||
| 2759 | return res; | ||
| 2760 | } | ||
| 2761 | #define INIT_GETHOSTENT_R \ | ||
| 2762 | COMMON_INTERCEPT_FUNCTION(gethostent_r); | ||
| 2763 | #else | ||
| 2764 | #define INIT_GETHOSTENT_R | ||
| 2765 | #endif | ||
| 2766 | |||
| 2767 | #if SANITIZER_INTERCEPT_GETHOSTBYADDR_R | ||
| 2768 | INTERCEPTOR(int, gethostbyaddr_r, void *addr, int len, int type, | ||
| 2769 | struct __sanitizer_hostent *ret, char *buf, SIZE_T buflen, | ||
| 2770 | __sanitizer_hostent **result, int *h_errnop) { | ||
| 2771 | void *ctx; | ||
| 2772 | COMMON_INTERCEPTOR_ENTER(ctx, gethostbyaddr_r, addr, len, type, ret, buf, | ||
| 2773 | buflen, result, h_errnop); | ||
| 2774 | COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, len); | ||
| 2775 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2776 | // its metadata. See | ||
| 2777 | // https://github.com/google/sanitizers/issues/321. | ||
| 2778 | int res = REAL(gethostbyaddr_r)(addr, len, type, ret, buf, buflen, result, | ||
| 2779 | h_errnop); | ||
| 2780 | if (result) { | ||
| 2781 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); | ||
| 2782 | if (res == 0 && *result) write_hostent(ctx, *result); | ||
| 2783 | } | ||
| 2784 | if (h_errnop) | ||
| 2785 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop)); | ||
| 2786 | return res; | ||
| 2787 | } | ||
| 2788 | #define INIT_GETHOSTBYADDR_R \ | ||
| 2789 | COMMON_INTERCEPT_FUNCTION(gethostbyaddr_r); | ||
| 2790 | #else | ||
| 2791 | #define INIT_GETHOSTBYADDR_R | ||
| 2792 | #endif | ||
| 2793 | |||
| 2794 | #if SANITIZER_INTERCEPT_GETHOSTBYNAME2_R | ||
| 2795 | INTERCEPTOR(int, gethostbyname2_r, char *name, int af, | ||
| 2796 | struct __sanitizer_hostent *ret, char *buf, SIZE_T buflen, | ||
| 2797 | __sanitizer_hostent **result, int *h_errnop) { | ||
| 2798 | void *ctx; | ||
| 2799 | COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname2_r, name, af, ret, buf, buflen, | ||
| 2800 | result, h_errnop); | ||
| 2801 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2802 | // its metadata. See | ||
| 2803 | // https://github.com/google/sanitizers/issues/321. | ||
| 2804 | int res = | ||
| 2805 | REAL(gethostbyname2_r)(name, af, ret, buf, buflen, result, h_errnop); | ||
| 2806 | if (result) { | ||
| 2807 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); | ||
| 2808 | if (res == 0 && *result) write_hostent(ctx, *result); | ||
| 2809 | } | ||
| 2810 | if (h_errnop) | ||
| 2811 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop)); | ||
| 2812 | return res; | ||
| 2813 | } | ||
| 2814 | #define INIT_GETHOSTBYNAME2_R \ | ||
| 2815 | COMMON_INTERCEPT_FUNCTION(gethostbyname2_r); | ||
| 2816 | #else | ||
| 2817 | #define INIT_GETHOSTBYNAME2_R | ||
| 2818 | #endif | ||
| 2819 | |||
| 2820 | #if SANITIZER_INTERCEPT_GETSOCKOPT | ||
| 2821 | INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval, | ||
| 2822 | int *optlen) { | ||
| 2823 | void *ctx; | ||
| 2824 | COMMON_INTERCEPTOR_ENTER(ctx, getsockopt, sockfd, level, optname, optval, | ||
| 2825 | optlen); | ||
| 2826 | if (optlen) COMMON_INTERCEPTOR_READ_RANGE(ctx, optlen, sizeof(*optlen)); | ||
| 2827 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2828 | // its metadata. See | ||
| 2829 | // https://github.com/google/sanitizers/issues/321. | ||
| 2830 | int res = REAL(getsockopt)(sockfd, level, optname, optval, optlen); | ||
| 2831 | if (res == 0) | ||
| 2832 | if (optval && optlen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, optval, *optlen); | ||
| 2833 | return res; | ||
| 2834 | } | ||
| 2835 | #define INIT_GETSOCKOPT COMMON_INTERCEPT_FUNCTION(getsockopt); | ||
| 2836 | #else | ||
| 2837 | #define INIT_GETSOCKOPT | ||
| 2838 | #endif | ||
| 2839 | |||
| 2840 | #if SANITIZER_INTERCEPT_ACCEPT | ||
| 2841 | INTERCEPTOR(int, accept, int fd, void *addr, unsigned *addrlen) { | ||
| 2842 | void *ctx; | ||
| 2843 | COMMON_INTERCEPTOR_ENTER(ctx, accept, fd, addr, addrlen); | ||
| 2844 | unsigned addrlen0 = 0; | ||
| 2845 | if (addrlen) { | ||
| 2846 | COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); | ||
| 2847 | addrlen0 = *addrlen; | ||
| 2848 | } | ||
| 2849 | int fd2 = REAL(accept)(fd, addr, addrlen); | ||
| 2850 | if (fd2 >= 0) { | ||
| 2851 | if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2); | ||
| 2852 | if (addr && addrlen) | ||
| 2853 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0)); | ||
| 2854 | } | ||
| 2855 | return fd2; | ||
| 2856 | } | ||
| 2857 | #define INIT_ACCEPT COMMON_INTERCEPT_FUNCTION(accept); | ||
| 2858 | #else | ||
| 2859 | #define INIT_ACCEPT | ||
| 2860 | #endif | ||
| 2861 | |||
| 2862 | #if SANITIZER_INTERCEPT_ACCEPT4 | ||
| 2863 | INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) { | ||
| 2864 | void *ctx; | ||
| 2865 | COMMON_INTERCEPTOR_ENTER(ctx, accept4, fd, addr, addrlen, f); | ||
| 2866 | unsigned addrlen0 = 0; | ||
| 2867 | if (addrlen) { | ||
| 2868 | COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); | ||
| 2869 | addrlen0 = *addrlen; | ||
| 2870 | } | ||
| 2871 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2872 | // its metadata. See | ||
| 2873 | // https://github.com/google/sanitizers/issues/321. | ||
| 2874 | int fd2 = REAL(accept4)(fd, addr, addrlen, f); | ||
| 2875 | if (fd2 >= 0) { | ||
| 2876 | if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2); | ||
| 2877 | if (addr && addrlen) | ||
| 2878 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0)); | ||
| 2879 | } | ||
| 2880 | return fd2; | ||
| 2881 | } | ||
| 2882 | #define INIT_ACCEPT4 COMMON_INTERCEPT_FUNCTION(accept4); | ||
| 2883 | #else | ||
| 2884 | #define INIT_ACCEPT4 | ||
| 2885 | #endif | ||
| 2886 | |||
| 2887 | #if SANITIZER_INTERCEPT_PACCEPT | ||
| 2888 | INTERCEPTOR(int, paccept, int fd, void *addr, unsigned *addrlen, | ||
| 2889 | __sanitizer_sigset_t *set, int f) { | ||
| 2890 | void *ctx; | ||
| 2891 | COMMON_INTERCEPTOR_ENTER(ctx, paccept, fd, addr, addrlen, set, f); | ||
| 2892 | unsigned addrlen0 = 0; | ||
| 2893 | if (addrlen) { | ||
| 2894 | COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); | ||
| 2895 | addrlen0 = *addrlen; | ||
| 2896 | } | ||
| 2897 | if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); | ||
| 2898 | int fd2 = REAL(paccept)(fd, addr, addrlen, set, f); | ||
| 2899 | if (fd2 >= 0) { | ||
| 2900 | if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2); | ||
| 2901 | if (addr && addrlen) | ||
| 2902 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0)); | ||
| 2903 | } | ||
| 2904 | return fd2; | ||
| 2905 | } | ||
| 2906 | #define INIT_PACCEPT COMMON_INTERCEPT_FUNCTION(paccept); | ||
| 2907 | #else | ||
| 2908 | #define INIT_PACCEPT | ||
| 2909 | #endif | ||
| 2910 | |||
| 2911 | #if SANITIZER_INTERCEPT_MODF | ||
| 2912 | INTERCEPTOR(double, modf, double x, double *iptr) { | ||
| 2913 | void *ctx; | ||
| 2914 | COMMON_INTERCEPTOR_ENTER(ctx, modf, x, iptr); | ||
| 2915 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2916 | // its metadata. See | ||
| 2917 | // https://github.com/google/sanitizers/issues/321. | ||
| 2918 | double res = REAL(modf)(x, iptr); | ||
| 2919 | if (iptr) { | ||
| 2920 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr)); | ||
| 2921 | } | ||
| 2922 | return res; | ||
| 2923 | } | ||
| 2924 | INTERCEPTOR(float, modff, float x, float *iptr) { | ||
| 2925 | void *ctx; | ||
| 2926 | COMMON_INTERCEPTOR_ENTER(ctx, modff, x, iptr); | ||
| 2927 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2928 | // its metadata. See | ||
| 2929 | // https://github.com/google/sanitizers/issues/321. | ||
| 2930 | float res = REAL(modff)(x, iptr); | ||
| 2931 | if (iptr) { | ||
| 2932 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr)); | ||
| 2933 | } | ||
| 2934 | return res; | ||
| 2935 | } | ||
| 2936 | INTERCEPTOR(long double, modfl, long double x, long double *iptr) { | ||
| 2937 | void *ctx; | ||
| 2938 | COMMON_INTERCEPTOR_ENTER(ctx, modfl, x, iptr); | ||
| 2939 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2940 | // its metadata. See | ||
| 2941 | // https://github.com/google/sanitizers/issues/321. | ||
| 2942 | long double res = REAL(modfl)(x, iptr); | ||
| 2943 | if (iptr) { | ||
| 2944 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr)); | ||
| 2945 | } | ||
| 2946 | return res; | ||
| 2947 | } | ||
| 2948 | #define INIT_MODF \ | ||
| 2949 | COMMON_INTERCEPT_FUNCTION(modf); \ | ||
| 2950 | COMMON_INTERCEPT_FUNCTION(modff); \ | ||
| 2951 | COMMON_INTERCEPT_FUNCTION_LDBL(modfl); | ||
| 2952 | #else | ||
| 2953 | #define INIT_MODF | ||
| 2954 | #endif | ||
| 2955 | |||
| 2956 | #if SANITIZER_INTERCEPT_RECVMSG || SANITIZER_INTERCEPT_RECVMMSG | ||
| 2957 | static void write_msghdr(void *ctx, struct __sanitizer_msghdr *msg, | ||
| 2958 | SSIZE_T maxlen) { | ||
| 2959 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg, sizeof(*msg)); | ||
| 2960 | if (msg->msg_name && msg->msg_namelen) | ||
| 2961 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_name, msg->msg_namelen); | ||
| 2962 | if (msg->msg_iov && msg->msg_iovlen) | ||
| 2963 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_iov, | ||
| 2964 | sizeof(*msg->msg_iov) * msg->msg_iovlen); | ||
| 2965 | write_iovec(ctx, msg->msg_iov, msg->msg_iovlen, maxlen); | ||
| 2966 | if (msg->msg_control && msg->msg_controllen) | ||
| 2967 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_control, msg->msg_controllen); | ||
| 2968 | } | ||
| 2969 | #endif | ||
| 2970 | |||
| 2971 | #if SANITIZER_INTERCEPT_RECVMSG | ||
| 2972 | INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg, | ||
| 2973 | int flags) { | ||
| 2974 | void *ctx; | ||
| 2975 | COMMON_INTERCEPTOR_ENTER(ctx, recvmsg, fd, msg, flags); | ||
| 2976 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 2977 | // its metadata. See | ||
| 2978 | // https://github.com/google/sanitizers/issues/321. | ||
| 2979 | SSIZE_T res = REAL(recvmsg)(fd, msg, flags); | ||
| 2980 | if (res >= 0) { | ||
| 2981 | if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 2982 | if (msg) { | ||
| 2983 | write_msghdr(ctx, msg, res); | ||
| 2984 | COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg); | ||
| 2985 | } | ||
| 2986 | } | ||
| 2987 | return res; | ||
| 2988 | } | ||
| 2989 | #define INIT_RECVMSG COMMON_INTERCEPT_FUNCTION(recvmsg); | ||
| 2990 | #else | ||
| 2991 | #define INIT_RECVMSG | ||
| 2992 | #endif | ||
| 2993 | |||
| 2994 | #if SANITIZER_INTERCEPT_RECVMMSG | ||
| 2995 | INTERCEPTOR(int, recvmmsg, int fd, struct __sanitizer_mmsghdr *msgvec, | ||
| 2996 | unsigned int vlen, int flags, void *timeout) { | ||
| 2997 | void *ctx; | ||
| 2998 | COMMON_INTERCEPTOR_ENTER(ctx, recvmmsg, fd, msgvec, vlen, flags, timeout); | ||
| 2999 | if (timeout) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout, struct_timespec_sz); | ||
| 3000 | int res = REAL(recvmmsg)(fd, msgvec, vlen, flags, timeout); | ||
| 3001 | if (res >= 0) { | ||
| 3002 | if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 3003 | for (int i = 0; i < res; ++i) { | ||
| 3004 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &msgvec[i].msg_len, | ||
| 3005 | sizeof(msgvec[i].msg_len)); | ||
| 3006 | write_msghdr(ctx, &msgvec[i].msg_hdr, msgvec[i].msg_len); | ||
| 3007 | COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, &msgvec[i].msg_hdr); | ||
| 3008 | } | ||
| 3009 | } | ||
| 3010 | return res; | ||
| 3011 | } | ||
| 3012 | #define INIT_RECVMMSG COMMON_INTERCEPT_FUNCTION(recvmmsg); | ||
| 3013 | #else | ||
| 3014 | #define INIT_RECVMMSG | ||
| 3015 | #endif | ||
| 3016 | |||
| 3017 | #if SANITIZER_INTERCEPT_SENDMSG || SANITIZER_INTERCEPT_SENDMMSG | ||
| 3018 | static void read_msghdr_control(void *ctx, void *control, uptr controllen) { | ||
| 3019 | const unsigned kCmsgDataOffset = | ||
| 3020 | RoundUpTo(sizeof(__sanitizer_cmsghdr), sizeof(uptr)); | ||
| 3021 | |||
| 3022 | char *p = (char *)control; | ||
| 3023 | char *const control_end = p + controllen; | ||
| 3024 | while (true) { | ||
| 3025 | if (p + sizeof(__sanitizer_cmsghdr) > control_end) break; | ||
| 3026 | __sanitizer_cmsghdr *cmsg = (__sanitizer_cmsghdr *)p; | ||
| 3027 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &cmsg->cmsg_len, sizeof(cmsg->cmsg_len)); | ||
| 3028 | |||
| 3029 | if (p + RoundUpTo(cmsg->cmsg_len, sizeof(uptr)) > control_end) break; | ||
| 3030 | |||
| 3031 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &cmsg->cmsg_level, | ||
| 3032 | sizeof(cmsg->cmsg_level)); | ||
| 3033 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &cmsg->cmsg_type, | ||
| 3034 | sizeof(cmsg->cmsg_type)); | ||
| 3035 | |||
| 3036 | if (cmsg->cmsg_len > kCmsgDataOffset) { | ||
| 3037 | char *data = p + kCmsgDataOffset; | ||
| 3038 | unsigned data_len = cmsg->cmsg_len - kCmsgDataOffset; | ||
| 3039 | if (data_len > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, data, data_len); | ||
| 3040 | } | ||
| 3041 | |||
| 3042 | p += RoundUpTo(cmsg->cmsg_len, sizeof(uptr)); | ||
| 3043 | } | ||
| 3044 | } | ||
| 3045 | |||
| 3046 | static void read_msghdr(void *ctx, struct __sanitizer_msghdr *msg, | ||
| 3047 | SSIZE_T maxlen) { | ||
| 3048 | #define R(f) \ | ||
| 3049 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &msg->msg_##f, sizeof(msg->msg_##f)) | ||
| 3050 | R(name); | ||
| 3051 | R(namelen); | ||
| 3052 | R(iov); | ||
| 3053 | R(iovlen); | ||
| 3054 | R(control); | ||
| 3055 | R(controllen); | ||
| 3056 | R(flags); | ||
| 3057 | #undef R | ||
| 3058 | if (msg->msg_name && msg->msg_namelen) | ||
| 3059 | COMMON_INTERCEPTOR_READ_RANGE(ctx, msg->msg_name, msg->msg_namelen); | ||
| 3060 | if (msg->msg_iov && msg->msg_iovlen) | ||
| 3061 | COMMON_INTERCEPTOR_READ_RANGE(ctx, msg->msg_iov, | ||
| 3062 | sizeof(*msg->msg_iov) * msg->msg_iovlen); | ||
| 3063 | read_iovec(ctx, msg->msg_iov, msg->msg_iovlen, maxlen); | ||
| 3064 | if (msg->msg_control && msg->msg_controllen) | ||
| 3065 | read_msghdr_control(ctx, msg->msg_control, msg->msg_controllen); | ||
| 3066 | } | ||
| 3067 | #endif | ||
| 3068 | |||
| 3069 | #if SANITIZER_INTERCEPT_SENDMSG | ||
| 3070 | INTERCEPTOR(SSIZE_T, sendmsg, int fd, struct __sanitizer_msghdr *msg, | ||
| 3071 | int flags) { | ||
| 3072 | void *ctx; | ||
| 3073 | COMMON_INTERCEPTOR_ENTER(ctx, sendmsg, fd, msg, flags); | ||
| 3074 | if (fd >= 0) { | ||
| 3075 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 3076 | COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); | ||
| 3077 | } | ||
| 3078 | SSIZE_T res = REAL(sendmsg)(fd, msg, flags); | ||
| 3079 | if (common_flags()->intercept_send && res >= 0 && msg) | ||
| 3080 | read_msghdr(ctx, msg, res); | ||
| 3081 | return res; | ||
| 3082 | } | ||
| 3083 | #define INIT_SENDMSG COMMON_INTERCEPT_FUNCTION(sendmsg); | ||
| 3084 | #else | ||
| 3085 | #define INIT_SENDMSG | ||
| 3086 | #endif | ||
| 3087 | |||
| 3088 | #if SANITIZER_INTERCEPT_SENDMMSG | ||
| 3089 | INTERCEPTOR(int, sendmmsg, int fd, struct __sanitizer_mmsghdr *msgvec, | ||
| 3090 | unsigned vlen, int flags) { | ||
| 3091 | void *ctx; | ||
| 3092 | COMMON_INTERCEPTOR_ENTER(ctx, sendmmsg, fd, msgvec, vlen, flags); | ||
| 3093 | if (fd >= 0) { | ||
| 3094 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 3095 | COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); | ||
| 3096 | } | ||
| 3097 | int res = REAL(sendmmsg)(fd, msgvec, vlen, flags); | ||
| 3098 | if (res >= 0 && msgvec) { | ||
| 3099 | for (int i = 0; i < res; ++i) { | ||
| 3100 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &msgvec[i].msg_len, | ||
| 3101 | sizeof(msgvec[i].msg_len)); | ||
| 3102 | if (common_flags()->intercept_send) | ||
| 3103 | read_msghdr(ctx, &msgvec[i].msg_hdr, msgvec[i].msg_len); | ||
| 3104 | } | ||
| 3105 | } | ||
| 3106 | return res; | ||
| 3107 | } | ||
| 3108 | #define INIT_SENDMMSG COMMON_INTERCEPT_FUNCTION(sendmmsg); | ||
| 3109 | #else | ||
| 3110 | #define INIT_SENDMMSG | ||
| 3111 | #endif | ||
| 3112 | |||
| 3113 | #if SANITIZER_INTERCEPT_SYSMSG | ||
| 3114 | INTERCEPTOR(int, msgsnd, int msqid, const void *msgp, SIZE_T msgsz, | ||
| 3115 | int msgflg) { | ||
| 3116 | void *ctx; | ||
| 3117 | COMMON_INTERCEPTOR_ENTER(ctx, msgsnd, msqid, msgp, msgsz, msgflg); | ||
| 3118 | if (msgp) | ||
| 3119 | COMMON_INTERCEPTOR_READ_RANGE(ctx, msgp, sizeof(long) + msgsz); | ||
| 3120 | int res = REAL(msgsnd)(msqid, msgp, msgsz, msgflg); | ||
| 3121 | return res; | ||
| 3122 | } | ||
| 3123 | |||
| 3124 | INTERCEPTOR(SSIZE_T, msgrcv, int msqid, void *msgp, SIZE_T msgsz, | ||
| 3125 | long msgtyp, int msgflg) { | ||
| 3126 | void *ctx; | ||
| 3127 | COMMON_INTERCEPTOR_ENTER(ctx, msgrcv, msqid, msgp, msgsz, msgtyp, msgflg); | ||
| 3128 | SSIZE_T len = REAL(msgrcv)(msqid, msgp, msgsz, msgtyp, msgflg); | ||
| 3129 | if (len != -1) | ||
| 3130 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msgp, sizeof(long) + len); | ||
| 3131 | return len; | ||
| 3132 | } | ||
| 3133 | |||
| 3134 | #define INIT_SYSMSG \ | ||
| 3135 | COMMON_INTERCEPT_FUNCTION(msgsnd); \ | ||
| 3136 | COMMON_INTERCEPT_FUNCTION(msgrcv); | ||
| 3137 | #else | ||
| 3138 | #define INIT_SYSMSG | ||
| 3139 | #endif | ||
| 3140 | |||
| 3141 | #if SANITIZER_INTERCEPT_GETPEERNAME | ||
| 3142 | INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) { | ||
| 3143 | void *ctx; | ||
| 3144 | COMMON_INTERCEPTOR_ENTER(ctx, getpeername, sockfd, addr, addrlen); | ||
| 3145 | unsigned addr_sz; | ||
| 3146 | if (addrlen) addr_sz = *addrlen; | ||
| 3147 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3148 | // its metadata. See | ||
| 3149 | // https://github.com/google/sanitizers/issues/321. | ||
| 3150 | int res = REAL(getpeername)(sockfd, addr, addrlen); | ||
| 3151 | if (!res && addr && addrlen) | ||
| 3152 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen)); | ||
| 3153 | return res; | ||
| 3154 | } | ||
| 3155 | #define INIT_GETPEERNAME COMMON_INTERCEPT_FUNCTION(getpeername); | ||
| 3156 | #else | ||
| 3157 | #define INIT_GETPEERNAME | ||
| 3158 | #endif | ||
| 3159 | |||
| 3160 | #if SANITIZER_INTERCEPT_SYSINFO | ||
| 3161 | INTERCEPTOR(int, sysinfo, void *info) { | ||
| 3162 | void *ctx; | ||
| 3163 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3164 | // its metadata. See | ||
| 3165 | // https://github.com/google/sanitizers/issues/321. | ||
| 3166 | COMMON_INTERCEPTOR_ENTER(ctx, sysinfo, info); | ||
| 3167 | int res = REAL(sysinfo)(info); | ||
| 3168 | if (!res && info) | ||
| 3169 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, struct_sysinfo_sz); | ||
| 3170 | return res; | ||
| 3171 | } | ||
| 3172 | #define INIT_SYSINFO COMMON_INTERCEPT_FUNCTION(sysinfo); | ||
| 3173 | #else | ||
| 3174 | #define INIT_SYSINFO | ||
| 3175 | #endif | ||
| 3176 | |||
| 3177 | #if SANITIZER_INTERCEPT_READDIR | ||
| 3178 | INTERCEPTOR(__sanitizer_dirent *, opendir, const char *path) { | ||
| 3179 | void *ctx; | ||
| 3180 | COMMON_INTERCEPTOR_ENTER(ctx, opendir, path); | ||
| 3181 | COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 3182 | __sanitizer_dirent *res = REAL(opendir)(path); | ||
| 3183 | if (res) | ||
| 3184 | COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path); | ||
| 3185 | return res; | ||
| 3186 | } | ||
| 3187 | |||
| 3188 | INTERCEPTOR(__sanitizer_dirent *, readdir, void *dirp) { | ||
| 3189 | void *ctx; | ||
| 3190 | COMMON_INTERCEPTOR_ENTER(ctx, readdir, dirp); | ||
| 3191 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3192 | // its metadata. See | ||
| 3193 | // https://github.com/google/sanitizers/issues/321. | ||
| 3194 | __sanitizer_dirent *res = REAL(readdir)(dirp); | ||
| 3195 | if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen); | ||
| 3196 | return res; | ||
| 3197 | } | ||
| 3198 | |||
| 3199 | INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry, | ||
| 3200 | __sanitizer_dirent **result) { | ||
| 3201 | void *ctx; | ||
| 3202 | COMMON_INTERCEPTOR_ENTER(ctx, readdir_r, dirp, entry, result); | ||
| 3203 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3204 | // its metadata. See | ||
| 3205 | // https://github.com/google/sanitizers/issues/321. | ||
| 3206 | int res = REAL(readdir_r)(dirp, entry, result); | ||
| 3207 | if (!res) { | ||
| 3208 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); | ||
| 3209 | if (*result) | ||
| 3210 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *result, (*result)->d_reclen); | ||
| 3211 | } | ||
| 3212 | return res; | ||
| 3213 | } | ||
| 3214 | |||
| 3215 | #define INIT_READDIR \ | ||
| 3216 | COMMON_INTERCEPT_FUNCTION(opendir); \ | ||
| 3217 | COMMON_INTERCEPT_FUNCTION(readdir); \ | ||
| 3218 | COMMON_INTERCEPT_FUNCTION(readdir_r); | ||
| 3219 | #else | ||
| 3220 | #define INIT_READDIR | ||
| 3221 | #endif | ||
| 3222 | |||
| 3223 | #if SANITIZER_INTERCEPT_READDIR64 | ||
| 3224 | INTERCEPTOR(__sanitizer_dirent64 *, readdir64, void *dirp) { | ||
| 3225 | void *ctx; | ||
| 3226 | COMMON_INTERCEPTOR_ENTER(ctx, readdir64, dirp); | ||
| 3227 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3228 | // its metadata. See | ||
| 3229 | // https://github.com/google/sanitizers/issues/321. | ||
| 3230 | __sanitizer_dirent64 *res = REAL(readdir64)(dirp); | ||
| 3231 | if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen); | ||
| 3232 | return res; | ||
| 3233 | } | ||
| 3234 | |||
| 3235 | INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry, | ||
| 3236 | __sanitizer_dirent64 **result) { | ||
| 3237 | void *ctx; | ||
| 3238 | COMMON_INTERCEPTOR_ENTER(ctx, readdir64_r, dirp, entry, result); | ||
| 3239 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3240 | // its metadata. See | ||
| 3241 | // https://github.com/google/sanitizers/issues/321. | ||
| 3242 | int res = REAL(readdir64_r)(dirp, entry, result); | ||
| 3243 | if (!res) { | ||
| 3244 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); | ||
| 3245 | if (*result) | ||
| 3246 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *result, (*result)->d_reclen); | ||
| 3247 | } | ||
| 3248 | return res; | ||
| 3249 | } | ||
| 3250 | #define INIT_READDIR64 \ | ||
| 3251 | COMMON_INTERCEPT_FUNCTION(readdir64); \ | ||
| 3252 | COMMON_INTERCEPT_FUNCTION(readdir64_r); | ||
| 3253 | #else | ||
| 3254 | #define INIT_READDIR64 | ||
| 3255 | #endif | ||
| 3256 | |||
| 3257 | #if SANITIZER_INTERCEPT_PTRACE | ||
| 3258 | INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) { | ||
| 3259 | void *ctx; | ||
| 3260 | COMMON_INTERCEPTOR_ENTER(ctx, ptrace, request, pid, addr, data); | ||
| 3261 | __sanitizer_iovec local_iovec; | ||
| 3262 | |||
| 3263 | if (data) { | ||
| 3264 | if (request == ptrace_setregs) { | ||
| 3265 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_regs_struct_sz); | ||
| 3266 | } else if (request == ptrace_setfpregs) { | ||
| 3267 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpregs_struct_sz); | ||
| 3268 | } else if (request == ptrace_setfpxregs) { | ||
| 3269 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz); | ||
| 3270 | } else if (request == ptrace_setvfpregs) { | ||
| 3271 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_vfpregs_struct_sz); | ||
| 3272 | } else if (request == ptrace_setsiginfo) { | ||
| 3273 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz); | ||
| 3274 | |||
| 3275 | // Some kernel might zero the iovec::iov_base in case of invalid | ||
| 3276 | // write access. In this case copy the invalid address for further | ||
| 3277 | // inspection. | ||
| 3278 | } else if (request == ptrace_setregset || request == ptrace_getregset) { | ||
| 3279 | __sanitizer_iovec *iovec = (__sanitizer_iovec*)data; | ||
| 3280 | COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec)); | ||
| 3281 | local_iovec = *iovec; | ||
| 3282 | if (request == ptrace_setregset) | ||
| 3283 | COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec->iov_base, iovec->iov_len); | ||
| 3284 | } | ||
| 3285 | } | ||
| 3286 | |||
| 3287 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3288 | // its metadata. See | ||
| 3289 | // https://github.com/google/sanitizers/issues/321. | ||
| 3290 | uptr res = REAL(ptrace)(request, pid, addr, data); | ||
| 3291 | |||
| 3292 | if (!res && data) { | ||
| 3293 | // Note that PEEK* requests assign different meaning to the return value. | ||
| 3294 | // This function does not handle them (nor does it need to). | ||
| 3295 | if (request == ptrace_getregs) { | ||
| 3296 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_regs_struct_sz); | ||
| 3297 | } else if (request == ptrace_getfpregs) { | ||
| 3298 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpregs_struct_sz); | ||
| 3299 | } else if (request == ptrace_getfpxregs) { | ||
| 3300 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_struct_sz); | ||
| 3301 | } else if (request == ptrace_getvfpregs) { | ||
| 3302 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_vfpregs_struct_sz); | ||
| 3303 | } else if (request == ptrace_getsiginfo) { | ||
| 3304 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, siginfo_t_sz); | ||
| 3305 | } else if (request == ptrace_geteventmsg) { | ||
| 3306 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(unsigned long)); | ||
| 3307 | } else if (request == ptrace_getregset) { | ||
| 3308 | __sanitizer_iovec *iovec = (__sanitizer_iovec*)data; | ||
| 3309 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec, sizeof(*iovec)); | ||
| 3310 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, local_iovec.iov_base, | ||
| 3311 | local_iovec.iov_len); | ||
| 3312 | } | ||
| 3313 | } | ||
| 3314 | return res; | ||
| 3315 | } | ||
| 3316 | |||
| 3317 | #define INIT_PTRACE COMMON_INTERCEPT_FUNCTION(ptrace); | ||
| 3318 | #else | ||
| 3319 | #define INIT_PTRACE | ||
| 3320 | #endif | ||
| 3321 | |||
| 3322 | #if SANITIZER_INTERCEPT_SETLOCALE | ||
| 3323 | static void unpoison_ctype_arrays(void *ctx) { | ||
| 3324 | #if SANITIZER_NETBSD | ||
| 3325 | // These arrays contain 256 regular elements in unsigned char range + 1 EOF | ||
| 3326 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, _ctype_tab_, 257 * sizeof(short)); | ||
| 3327 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, _toupper_tab_, 257 * sizeof(short)); | ||
| 3328 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, _tolower_tab_, 257 * sizeof(short)); | ||
| 3329 | #endif | ||
| 3330 | } | ||
| 3331 | |||
| 3332 | INTERCEPTOR(char *, setlocale, int category, char *locale) { | ||
| 3333 | void *ctx; | ||
| 3334 | COMMON_INTERCEPTOR_ENTER(ctx, setlocale, category, locale); | ||
| 3335 | if (locale) | ||
| 3336 | COMMON_INTERCEPTOR_READ_RANGE(ctx, locale, REAL(strlen)(locale) + 1); | ||
| 3337 | char *res = REAL(setlocale)(category, locale); | ||
| 3338 | if (res) { | ||
| 3339 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); | ||
| 3340 | unpoison_ctype_arrays(ctx); | ||
| 3341 | } | ||
| 3342 | return res; | ||
| 3343 | } | ||
| 3344 | |||
| 3345 | #define INIT_SETLOCALE COMMON_INTERCEPT_FUNCTION(setlocale); | ||
| 3346 | #else | ||
| 3347 | #define INIT_SETLOCALE | ||
| 3348 | #endif | ||
| 3349 | |||
| 3350 | #if SANITIZER_INTERCEPT_GETCWD | ||
| 3351 | INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) { | ||
| 3352 | void *ctx; | ||
| 3353 | COMMON_INTERCEPTOR_ENTER(ctx, getcwd, buf, size); | ||
| 3354 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3355 | // its metadata. See | ||
| 3356 | // https://github.com/google/sanitizers/issues/321. | ||
| 3357 | char *res = REAL(getcwd)(buf, size); | ||
| 3358 | if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); | ||
| 3359 | return res; | ||
| 3360 | } | ||
| 3361 | #define INIT_GETCWD COMMON_INTERCEPT_FUNCTION(getcwd); | ||
| 3362 | #else | ||
| 3363 | #define INIT_GETCWD | ||
| 3364 | #endif | ||
| 3365 | |||
| 3366 | #if SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME | ||
| 3367 | INTERCEPTOR(char *, get_current_dir_name, int fake) { | ||
| 3368 | void *ctx; | ||
| 3369 | COMMON_INTERCEPTOR_ENTER(ctx, get_current_dir_name, fake); | ||
| 3370 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3371 | // its metadata. See | ||
| 3372 | // https://github.com/google/sanitizers/issues/321. | ||
| 3373 | char *res = REAL(get_current_dir_name)(fake); | ||
| 3374 | if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); | ||
| 3375 | return res; | ||
| 3376 | } | ||
| 3377 | |||
| 3378 | #define INIT_GET_CURRENT_DIR_NAME \ | ||
| 3379 | COMMON_INTERCEPT_FUNCTION(get_current_dir_name); | ||
| 3380 | #else | ||
| 3381 | #define INIT_GET_CURRENT_DIR_NAME | ||
| 3382 | #endif | ||
| 3383 | |||
| 3384 | UNUSED static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) { | ||
| 3385 | CHECK(endptr); | ||
| 3386 | if (nptr == *endptr) { | ||
| 3387 | // No digits were found at strtol call, we need to find out the last | ||
| 3388 | // symbol accessed by strtoll on our own. | ||
| 3389 | // We get this symbol by skipping leading blanks and optional +/- sign. | ||
| 3390 | while (IsSpace(*nptr)) nptr++; | ||
| 3391 | if (*nptr == '+' || *nptr == '-') nptr++; | ||
| 3392 | *endptr = const_cast<char *>(nptr); | ||
| 3393 | } | ||
| 3394 | CHECK(*endptr >= nptr); | ||
| 3395 | } | ||
| 3396 | |||
| 3397 | UNUSED static inline void StrtolFixAndCheck(void *ctx, const char *nptr, | ||
| 3398 | char **endptr, char *real_endptr, int base) { | ||
| 3399 | if (endptr) { | ||
| 3400 | *endptr = real_endptr; | ||
| 3401 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr)); | ||
| 3402 | } | ||
| 3403 | // If base has unsupported value, strtol can exit with EINVAL | ||
| 3404 | // without reading any characters. So do additional checks only | ||
| 3405 | // if base is valid. | ||
| 3406 | bool is_valid_base = (base == 0) || (2 <= base && base <= 36); | ||
| 3407 | if (is_valid_base) { | ||
| 3408 | FixRealStrtolEndptr(nptr, &real_endptr); | ||
| 3409 | } | ||
| 3410 | COMMON_INTERCEPTOR_READ_STRING(ctx, nptr, is_valid_base ? | ||
| 3411 | (real_endptr - nptr) + 1 : 0); | ||
| 3412 | } | ||
| 3413 | |||
| 3414 | |||
| 3415 | #if SANITIZER_INTERCEPT_STRTOIMAX | ||
| 3416 | INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) { | ||
| 3417 | void *ctx; | ||
| 3418 | COMMON_INTERCEPTOR_ENTER(ctx, strtoimax, nptr, endptr, base); | ||
| 3419 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3420 | // its metadata. See | ||
| 3421 | // https://github.com/google/sanitizers/issues/321. | ||
| 3422 | char *real_endptr; | ||
| 3423 | INTMAX_T res = REAL(strtoimax)(nptr, &real_endptr, base); | ||
| 3424 | StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); | ||
| 3425 | return res; | ||
| 3426 | } | ||
| 3427 | |||
| 3428 | INTERCEPTOR(UINTMAX_T, strtoumax, const char *nptr, char **endptr, int base) { | ||
| 3429 | void *ctx; | ||
| 3430 | COMMON_INTERCEPTOR_ENTER(ctx, strtoumax, nptr, endptr, base); | ||
| 3431 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3432 | // its metadata. See | ||
| 3433 | // https://github.com/google/sanitizers/issues/321. | ||
| 3434 | char *real_endptr; | ||
| 3435 | UINTMAX_T res = REAL(strtoumax)(nptr, &real_endptr, base); | ||
| 3436 | StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); | ||
| 3437 | return res; | ||
| 3438 | } | ||
| 3439 | |||
| 3440 | #define INIT_STRTOIMAX \ | ||
| 3441 | COMMON_INTERCEPT_FUNCTION(strtoimax); \ | ||
| 3442 | COMMON_INTERCEPT_FUNCTION(strtoumax); | ||
| 3443 | #else | ||
| 3444 | #define INIT_STRTOIMAX | ||
| 3445 | #endif | ||
| 3446 | |||
| 3447 | #if SANITIZER_INTERCEPT_MBSTOWCS | ||
| 3448 | INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T len) { | ||
| 3449 | void *ctx; | ||
| 3450 | COMMON_INTERCEPTOR_ENTER(ctx, mbstowcs, dest, src, len); | ||
| 3451 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3452 | // its metadata. See | ||
| 3453 | // https://github.com/google/sanitizers/issues/321. | ||
| 3454 | SIZE_T res = REAL(mbstowcs)(dest, src, len); | ||
| 3455 | if (res != (SIZE_T) - 1 && dest) { | ||
| 3456 | SIZE_T write_cnt = res + (res < len); | ||
| 3457 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t)); | ||
| 3458 | } | ||
| 3459 | return res; | ||
| 3460 | } | ||
| 3461 | |||
| 3462 | INTERCEPTOR(SIZE_T, mbsrtowcs, wchar_t *dest, const char **src, SIZE_T len, | ||
| 3463 | void *ps) { | ||
| 3464 | void *ctx; | ||
| 3465 | COMMON_INTERCEPTOR_ENTER(ctx, mbsrtowcs, dest, src, len, ps); | ||
| 3466 | if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); | ||
| 3467 | if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); | ||
| 3468 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3469 | // its metadata. See | ||
| 3470 | // https://github.com/google/sanitizers/issues/321. | ||
| 3471 | SIZE_T res = REAL(mbsrtowcs)(dest, src, len, ps); | ||
| 3472 | if (res != (SIZE_T)(-1) && dest && src) { | ||
| 3473 | // This function, and several others, may or may not write the terminating | ||
| 3474 | // \0 character. They write it iff they clear *src. | ||
| 3475 | SIZE_T write_cnt = res + !*src; | ||
| 3476 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t)); | ||
| 3477 | } | ||
| 3478 | return res; | ||
| 3479 | } | ||
| 3480 | |||
| 3481 | #define INIT_MBSTOWCS \ | ||
| 3482 | COMMON_INTERCEPT_FUNCTION(mbstowcs); \ | ||
| 3483 | COMMON_INTERCEPT_FUNCTION(mbsrtowcs); | ||
| 3484 | #else | ||
| 3485 | #define INIT_MBSTOWCS | ||
| 3486 | #endif | ||
| 3487 | |||
| 3488 | #if SANITIZER_INTERCEPT_MBSNRTOWCS | ||
| 3489 | INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms, | ||
| 3490 | SIZE_T len, void *ps) { | ||
| 3491 | void *ctx; | ||
| 3492 | COMMON_INTERCEPTOR_ENTER(ctx, mbsnrtowcs, dest, src, nms, len, ps); | ||
| 3493 | if (src) { | ||
| 3494 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); | ||
| 3495 | if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms); | ||
| 3496 | } | ||
| 3497 | if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); | ||
| 3498 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3499 | // its metadata. See | ||
| 3500 | // https://github.com/google/sanitizers/issues/321. | ||
| 3501 | SIZE_T res = REAL(mbsnrtowcs)(dest, src, nms, len, ps); | ||
| 3502 | if (res != (SIZE_T)(-1) && dest && src) { | ||
| 3503 | SIZE_T write_cnt = res + !*src; | ||
| 3504 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t)); | ||
| 3505 | } | ||
| 3506 | return res; | ||
| 3507 | } | ||
| 3508 | |||
| 3509 | #define INIT_MBSNRTOWCS COMMON_INTERCEPT_FUNCTION(mbsnrtowcs); | ||
| 3510 | #else | ||
| 3511 | #define INIT_MBSNRTOWCS | ||
| 3512 | #endif | ||
| 3513 | |||
| 3514 | #if SANITIZER_INTERCEPT_WCSTOMBS | ||
| 3515 | INTERCEPTOR(SIZE_T, wcstombs, char *dest, const wchar_t *src, SIZE_T len) { | ||
| 3516 | void *ctx; | ||
| 3517 | COMMON_INTERCEPTOR_ENTER(ctx, wcstombs, dest, src, len); | ||
| 3518 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3519 | // its metadata. See | ||
| 3520 | // https://github.com/google/sanitizers/issues/321. | ||
| 3521 | SIZE_T res = REAL(wcstombs)(dest, src, len); | ||
| 3522 | if (res != (SIZE_T) - 1 && dest) { | ||
| 3523 | SIZE_T write_cnt = res + (res < len); | ||
| 3524 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt); | ||
| 3525 | } | ||
| 3526 | return res; | ||
| 3527 | } | ||
| 3528 | |||
| 3529 | INTERCEPTOR(SIZE_T, wcsrtombs, char *dest, const wchar_t **src, SIZE_T len, | ||
| 3530 | void *ps) { | ||
| 3531 | void *ctx; | ||
| 3532 | COMMON_INTERCEPTOR_ENTER(ctx, wcsrtombs, dest, src, len, ps); | ||
| 3533 | if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); | ||
| 3534 | if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); | ||
| 3535 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3536 | // its metadata. See | ||
| 3537 | // https://github.com/google/sanitizers/issues/321. | ||
| 3538 | SIZE_T res = REAL(wcsrtombs)(dest, src, len, ps); | ||
| 3539 | if (res != (SIZE_T) - 1 && dest && src) { | ||
| 3540 | SIZE_T write_cnt = res + !*src; | ||
| 3541 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt); | ||
| 3542 | } | ||
| 3543 | return res; | ||
| 3544 | } | ||
| 3545 | |||
| 3546 | #define INIT_WCSTOMBS \ | ||
| 3547 | COMMON_INTERCEPT_FUNCTION(wcstombs); \ | ||
| 3548 | COMMON_INTERCEPT_FUNCTION(wcsrtombs); | ||
| 3549 | #else | ||
| 3550 | #define INIT_WCSTOMBS | ||
| 3551 | #endif | ||
| 3552 | |||
| 3553 | #if SANITIZER_INTERCEPT_WCSNRTOMBS | ||
| 3554 | INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms, | ||
| 3555 | SIZE_T len, void *ps) { | ||
| 3556 | void *ctx; | ||
| 3557 | COMMON_INTERCEPTOR_ENTER(ctx, wcsnrtombs, dest, src, nms, len, ps); | ||
| 3558 | if (src) { | ||
| 3559 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); | ||
| 3560 | if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms); | ||
| 3561 | } | ||
| 3562 | if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); | ||
| 3563 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3564 | // its metadata. See | ||
| 3565 | // https://github.com/google/sanitizers/issues/321. | ||
| 3566 | SIZE_T res = REAL(wcsnrtombs)(dest, src, nms, len, ps); | ||
| 3567 | if (res != ((SIZE_T)-1) && dest && src) { | ||
| 3568 | SIZE_T write_cnt = res + !*src; | ||
| 3569 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt); | ||
| 3570 | } | ||
| 3571 | return res; | ||
| 3572 | } | ||
| 3573 | |||
| 3574 | #define INIT_WCSNRTOMBS COMMON_INTERCEPT_FUNCTION(wcsnrtombs); | ||
| 3575 | #else | ||
| 3576 | #define INIT_WCSNRTOMBS | ||
| 3577 | #endif | ||
| 3578 | |||
| 3579 | |||
| 3580 | #if SANITIZER_INTERCEPT_WCRTOMB | ||
| 3581 | INTERCEPTOR(SIZE_T, wcrtomb, char *dest, wchar_t src, void *ps) { | ||
| 3582 | void *ctx; | ||
| 3583 | COMMON_INTERCEPTOR_ENTER(ctx, wcrtomb, dest, src, ps); | ||
| 3584 | if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); | ||
| 3585 | |||
| 3586 | if (!dest) | ||
| 3587 | return REAL(wcrtomb)(dest, src, ps); | ||
| 3588 | |||
| 3589 | char local_dest[32]; | ||
| 3590 | SIZE_T res = REAL(wcrtomb)(local_dest, src, ps); | ||
| 3591 | if (res != ((SIZE_T)-1)) { | ||
| 3592 | CHECK_LE(res, sizeof(local_dest)); | ||
| 3593 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, res); | ||
| 3594 | REAL(memcpy)(dest, local_dest, res); | ||
| 3595 | } | ||
| 3596 | return res; | ||
| 3597 | } | ||
| 3598 | |||
| 3599 | #define INIT_WCRTOMB COMMON_INTERCEPT_FUNCTION(wcrtomb); | ||
| 3600 | #else | ||
| 3601 | #define INIT_WCRTOMB | ||
| 3602 | #endif | ||
| 3603 | |||
| 3604 | #if SANITIZER_INTERCEPT_WCTOMB | ||
| 3605 | INTERCEPTOR(int, wctomb, char *dest, wchar_t src) { | ||
| 3606 | void *ctx; | ||
| 3607 | COMMON_INTERCEPTOR_ENTER(ctx, wctomb, dest, src); | ||
| 3608 | if (!dest) | ||
| 3609 | return REAL(wctomb)(dest, src); | ||
| 3610 | |||
| 3611 | char local_dest[32]; | ||
| 3612 | int res = REAL(wctomb)(local_dest, src); | ||
| 3613 | if (res != -1) { | ||
| 3614 | CHECK_LE(res, sizeof(local_dest)); | ||
| 3615 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, res); | ||
| 3616 | REAL(memcpy)(dest, local_dest, res); | ||
| 3617 | } | ||
| 3618 | return res; | ||
| 3619 | } | ||
| 3620 | |||
| 3621 | #define INIT_WCTOMB COMMON_INTERCEPT_FUNCTION(wctomb); | ||
| 3622 | #else | ||
| 3623 | #define INIT_WCTOMB | ||
| 3624 | #endif | ||
| 3625 | |||
| 3626 | #if SANITIZER_INTERCEPT_TCGETATTR | ||
| 3627 | INTERCEPTOR(int, tcgetattr, int fd, void *termios_p) { | ||
| 3628 | void *ctx; | ||
| 3629 | COMMON_INTERCEPTOR_ENTER(ctx, tcgetattr, fd, termios_p); | ||
| 3630 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3631 | // its metadata. See | ||
| 3632 | // https://github.com/google/sanitizers/issues/321. | ||
| 3633 | int res = REAL(tcgetattr)(fd, termios_p); | ||
| 3634 | if (!res && termios_p) | ||
| 3635 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, termios_p, struct_termios_sz); | ||
| 3636 | return res; | ||
| 3637 | } | ||
| 3638 | |||
| 3639 | #define INIT_TCGETATTR COMMON_INTERCEPT_FUNCTION(tcgetattr); | ||
| 3640 | #else | ||
| 3641 | #define INIT_TCGETATTR | ||
| 3642 | #endif | ||
| 3643 | |||
| 3644 | #if SANITIZER_INTERCEPT_REALPATH | ||
| 3645 | INTERCEPTOR(char *, realpath, const char *path, char *resolved_path) { | ||
| 3646 | void *ctx; | ||
| 3647 | COMMON_INTERCEPTOR_ENTER(ctx, realpath, path, resolved_path); | ||
| 3648 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 3649 | |||
| 3650 | // Workaround a bug in glibc where dlsym(RTLD_NEXT, ...) returns the oldest | ||
| 3651 | // version of a versioned symbol. For realpath(), this gives us something | ||
| 3652 | // (called __old_realpath) that does not handle NULL in the second argument. | ||
| 3653 | // Handle it as part of the interceptor. | ||
| 3654 | char *allocated_path = nullptr; | ||
| 3655 | if (!resolved_path) | ||
| 3656 | allocated_path = resolved_path = (char *)WRAP(malloc)(path_max + 1); | ||
| 3657 | |||
| 3658 | char *res = REAL(realpath)(path, resolved_path); | ||
| 3659 | if (allocated_path && !res) WRAP(free)(allocated_path); | ||
| 3660 | if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); | ||
| 3661 | return res; | ||
| 3662 | } | ||
| 3663 | #define INIT_REALPATH COMMON_INTERCEPT_FUNCTION(realpath); | ||
| 3664 | #else | ||
| 3665 | #define INIT_REALPATH | ||
| 3666 | #endif | ||
| 3667 | |||
| 3668 | #if SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME | ||
| 3669 | INTERCEPTOR(char *, canonicalize_file_name, const char *path) { | ||
| 3670 | void *ctx; | ||
| 3671 | COMMON_INTERCEPTOR_ENTER(ctx, canonicalize_file_name, path); | ||
| 3672 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 3673 | char *res = REAL(canonicalize_file_name)(path); | ||
| 3674 | if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); | ||
| 3675 | return res; | ||
| 3676 | } | ||
| 3677 | #define INIT_CANONICALIZE_FILE_NAME \ | ||
| 3678 | COMMON_INTERCEPT_FUNCTION(canonicalize_file_name); | ||
| 3679 | #else | ||
| 3680 | #define INIT_CANONICALIZE_FILE_NAME | ||
| 3681 | #endif | ||
| 3682 | |||
| 3683 | #if SANITIZER_INTERCEPT_CONFSTR | ||
| 3684 | INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) { | ||
| 3685 | void *ctx; | ||
| 3686 | COMMON_INTERCEPTOR_ENTER(ctx, confstr, name, buf, len); | ||
| 3687 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3688 | // its metadata. See | ||
| 3689 | // https://github.com/google/sanitizers/issues/321. | ||
| 3690 | SIZE_T res = REAL(confstr)(name, buf, len); | ||
| 3691 | if (buf && res) | ||
| 3692 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res < len ? res : len); | ||
| 3693 | return res; | ||
| 3694 | } | ||
| 3695 | #define INIT_CONFSTR COMMON_INTERCEPT_FUNCTION(confstr); | ||
| 3696 | #else | ||
| 3697 | #define INIT_CONFSTR | ||
| 3698 | #endif | ||
| 3699 | |||
| 3700 | #if SANITIZER_INTERCEPT_SCHED_GETAFFINITY | ||
| 3701 | INTERCEPTOR(int, sched_getaffinity, int pid, SIZE_T cpusetsize, void *mask) { | ||
| 3702 | void *ctx; | ||
| 3703 | COMMON_INTERCEPTOR_ENTER(ctx, sched_getaffinity, pid, cpusetsize, mask); | ||
| 3704 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3705 | // its metadata. See | ||
| 3706 | // https://github.com/google/sanitizers/issues/321. | ||
| 3707 | int res = REAL(sched_getaffinity)(pid, cpusetsize, mask); | ||
| 3708 | if (mask && !res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mask, cpusetsize); | ||
| 3709 | return res; | ||
| 3710 | } | ||
| 3711 | #define INIT_SCHED_GETAFFINITY COMMON_INTERCEPT_FUNCTION(sched_getaffinity); | ||
| 3712 | #else | ||
| 3713 | #define INIT_SCHED_GETAFFINITY | ||
| 3714 | #endif | ||
| 3715 | |||
| 3716 | #if SANITIZER_INTERCEPT_SCHED_GETPARAM | ||
| 3717 | INTERCEPTOR(int, sched_getparam, int pid, void *param) { | ||
| 3718 | void *ctx; | ||
| 3719 | COMMON_INTERCEPTOR_ENTER(ctx, sched_getparam, pid, param); | ||
| 3720 | int res = REAL(sched_getparam)(pid, param); | ||
| 3721 | if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, param, struct_sched_param_sz); | ||
| 3722 | return res; | ||
| 3723 | } | ||
| 3724 | #define INIT_SCHED_GETPARAM COMMON_INTERCEPT_FUNCTION(sched_getparam); | ||
| 3725 | #else | ||
| 3726 | #define INIT_SCHED_GETPARAM | ||
| 3727 | #endif | ||
| 3728 | |||
| 3729 | #if SANITIZER_INTERCEPT_STRERROR | ||
| 3730 | INTERCEPTOR(char *, strerror, int errnum) { | ||
| 3731 | void *ctx; | ||
| 3732 | COMMON_INTERCEPTOR_ENTER(ctx, strerror, errnum); | ||
| 3733 | COMMON_INTERCEPTOR_STRERROR(); | ||
| 3734 | char *res = REAL(strerror)(errnum); | ||
| 3735 | if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); | ||
| 3736 | return res; | ||
| 3737 | } | ||
| 3738 | #define INIT_STRERROR COMMON_INTERCEPT_FUNCTION(strerror); | ||
| 3739 | #else | ||
| 3740 | #define INIT_STRERROR | ||
| 3741 | #endif | ||
| 3742 | |||
| 3743 | #if SANITIZER_INTERCEPT_STRERROR_R | ||
| 3744 | // There are 2 versions of strerror_r: | ||
| 3745 | // * POSIX version returns 0 on success, negative error code on failure, | ||
| 3746 | // writes message to buf. | ||
| 3747 | // * GNU version returns message pointer, which points to either buf or some | ||
| 3748 | // static storage. | ||
| 3749 | #if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || \ | ||
| 3750 | SANITIZER_MAC || SANITIZER_ANDROID || SANITIZER_NETBSD || \ | ||
| 3751 | SANITIZER_FREEBSD || SANITIZER_OPENBSD | ||
| 3752 | // POSIX version. Spec is not clear on whether buf is NULL-terminated. | ||
| 3753 | // At least on OSX, buf contents are valid even when the call fails. | ||
| 3754 | INTERCEPTOR(int, strerror_r, int errnum, char *buf, SIZE_T buflen) { | ||
| 3755 | void *ctx; | ||
| 3756 | COMMON_INTERCEPTOR_ENTER(ctx, strerror_r, errnum, buf, buflen); | ||
| 3757 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3758 | // its metadata. See | ||
| 3759 | // https://github.com/google/sanitizers/issues/321. | ||
| 3760 | int res = REAL(strerror_r)(errnum, buf, buflen); | ||
| 3761 | |||
| 3762 | SIZE_T sz = internal_strnlen(buf, buflen); | ||
| 3763 | if (sz < buflen) ++sz; | ||
| 3764 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz); | ||
| 3765 | return res; | ||
| 3766 | } | ||
| 3767 | #else | ||
| 3768 | // GNU version. | ||
| 3769 | INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) { | ||
| 3770 | void *ctx; | ||
| 3771 | COMMON_INTERCEPTOR_ENTER(ctx, strerror_r, errnum, buf, buflen); | ||
| 3772 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3773 | // its metadata. See | ||
| 3774 | // https://github.com/google/sanitizers/issues/321. | ||
| 3775 | char *res = REAL(strerror_r)(errnum, buf, buflen); | ||
| 3776 | if (res == buf) | ||
| 3777 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); | ||
| 3778 | else | ||
| 3779 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); | ||
| 3780 | return res; | ||
| 3781 | } | ||
| 3782 | #endif //(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE || | ||
| 3783 | //SANITIZER_MAC | ||
| 3784 | #define INIT_STRERROR_R COMMON_INTERCEPT_FUNCTION(strerror_r); | ||
| 3785 | #else | ||
| 3786 | #define INIT_STRERROR_R | ||
| 3787 | #endif | ||
| 3788 | |||
| 3789 | #if SANITIZER_INTERCEPT_XPG_STRERROR_R | ||
| 3790 | INTERCEPTOR(int, __xpg_strerror_r, int errnum, char *buf, SIZE_T buflen) { | ||
| 3791 | void *ctx; | ||
| 3792 | COMMON_INTERCEPTOR_ENTER(ctx, __xpg_strerror_r, errnum, buf, buflen); | ||
| 3793 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3794 | // its metadata. See | ||
| 3795 | // https://github.com/google/sanitizers/issues/321. | ||
| 3796 | int res = REAL(__xpg_strerror_r)(errnum, buf, buflen); | ||
| 3797 | // This version always returns a null-terminated string. | ||
| 3798 | if (buf && buflen) | ||
| 3799 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, REAL(strlen)(buf) + 1); | ||
| 3800 | return res; | ||
| 3801 | } | ||
| 3802 | #define INIT_XPG_STRERROR_R COMMON_INTERCEPT_FUNCTION(__xpg_strerror_r); | ||
| 3803 | #else | ||
| 3804 | #define INIT_XPG_STRERROR_R | ||
| 3805 | #endif | ||
| 3806 | |||
| 3807 | #if SANITIZER_INTERCEPT_SCANDIR | ||
| 3808 | typedef int (*scandir_filter_f)(const struct __sanitizer_dirent *); | ||
| 3809 | typedef int (*scandir_compar_f)(const struct __sanitizer_dirent **, | ||
| 3810 | const struct __sanitizer_dirent **); | ||
| 3811 | |||
| 3812 | static THREADLOCAL scandir_filter_f scandir_filter; | ||
| 3813 | static THREADLOCAL scandir_compar_f scandir_compar; | ||
| 3814 | |||
| 3815 | static int wrapped_scandir_filter(const struct __sanitizer_dirent *dir) { | ||
| 3816 | COMMON_INTERCEPTOR_UNPOISON_PARAM(1); | ||
| 3817 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, dir->d_reclen); | ||
| 3818 | return scandir_filter(dir); | ||
| 3819 | } | ||
| 3820 | |||
| 3821 | static int wrapped_scandir_compar(const struct __sanitizer_dirent **a, | ||
| 3822 | const struct __sanitizer_dirent **b) { | ||
| 3823 | COMMON_INTERCEPTOR_UNPOISON_PARAM(2); | ||
| 3824 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, sizeof(*a)); | ||
| 3825 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(*a, (*a)->d_reclen); | ||
| 3826 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, sizeof(*b)); | ||
| 3827 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(*b, (*b)->d_reclen); | ||
| 3828 | return scandir_compar(a, b); | ||
| 3829 | } | ||
| 3830 | |||
| 3831 | INTERCEPTOR(int, scandir, char *dirp, __sanitizer_dirent ***namelist, | ||
| 3832 | scandir_filter_f filter, scandir_compar_f compar) { | ||
| 3833 | void *ctx; | ||
| 3834 | COMMON_INTERCEPTOR_ENTER(ctx, scandir, dirp, namelist, filter, compar); | ||
| 3835 | if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, REAL(strlen)(dirp) + 1); | ||
| 3836 | scandir_filter = filter; | ||
| 3837 | scandir_compar = compar; | ||
| 3838 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3839 | // its metadata. See | ||
| 3840 | // https://github.com/google/sanitizers/issues/321. | ||
| 3841 | int res = REAL(scandir)(dirp, namelist, | ||
| 3842 | filter ? wrapped_scandir_filter : nullptr, | ||
| 3843 | compar ? wrapped_scandir_compar : nullptr); | ||
| 3844 | scandir_filter = nullptr; | ||
| 3845 | scandir_compar = nullptr; | ||
| 3846 | if (namelist && res > 0) { | ||
| 3847 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist)); | ||
| 3848 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res); | ||
| 3849 | for (int i = 0; i < res; ++i) | ||
| 3850 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (*namelist)[i], | ||
| 3851 | (*namelist)[i]->d_reclen); | ||
| 3852 | } | ||
| 3853 | return res; | ||
| 3854 | } | ||
| 3855 | #define INIT_SCANDIR COMMON_INTERCEPT_FUNCTION(scandir); | ||
| 3856 | #else | ||
| 3857 | #define INIT_SCANDIR | ||
| 3858 | #endif | ||
| 3859 | |||
| 3860 | #if SANITIZER_INTERCEPT_SCANDIR64 | ||
| 3861 | typedef int (*scandir64_filter_f)(const struct __sanitizer_dirent64 *); | ||
| 3862 | typedef int (*scandir64_compar_f)(const struct __sanitizer_dirent64 **, | ||
| 3863 | const struct __sanitizer_dirent64 **); | ||
| 3864 | |||
| 3865 | static THREADLOCAL scandir64_filter_f scandir64_filter; | ||
| 3866 | static THREADLOCAL scandir64_compar_f scandir64_compar; | ||
| 3867 | |||
| 3868 | static int wrapped_scandir64_filter(const struct __sanitizer_dirent64 *dir) { | ||
| 3869 | COMMON_INTERCEPTOR_UNPOISON_PARAM(1); | ||
| 3870 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, dir->d_reclen); | ||
| 3871 | return scandir64_filter(dir); | ||
| 3872 | } | ||
| 3873 | |||
| 3874 | static int wrapped_scandir64_compar(const struct __sanitizer_dirent64 **a, | ||
| 3875 | const struct __sanitizer_dirent64 **b) { | ||
| 3876 | COMMON_INTERCEPTOR_UNPOISON_PARAM(2); | ||
| 3877 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, sizeof(*a)); | ||
| 3878 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(*a, (*a)->d_reclen); | ||
| 3879 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, sizeof(*b)); | ||
| 3880 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(*b, (*b)->d_reclen); | ||
| 3881 | return scandir64_compar(a, b); | ||
| 3882 | } | ||
| 3883 | |||
| 3884 | INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist, | ||
| 3885 | scandir64_filter_f filter, scandir64_compar_f compar) { | ||
| 3886 | void *ctx; | ||
| 3887 | COMMON_INTERCEPTOR_ENTER(ctx, scandir64, dirp, namelist, filter, compar); | ||
| 3888 | if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, REAL(strlen)(dirp) + 1); | ||
| 3889 | scandir64_filter = filter; | ||
| 3890 | scandir64_compar = compar; | ||
| 3891 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3892 | // its metadata. See | ||
| 3893 | // https://github.com/google/sanitizers/issues/321. | ||
| 3894 | int res = | ||
| 3895 | REAL(scandir64)(dirp, namelist, | ||
| 3896 | filter ? wrapped_scandir64_filter : nullptr, | ||
| 3897 | compar ? wrapped_scandir64_compar : nullptr); | ||
| 3898 | scandir64_filter = nullptr; | ||
| 3899 | scandir64_compar = nullptr; | ||
| 3900 | if (namelist && res > 0) { | ||
| 3901 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist)); | ||
| 3902 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res); | ||
| 3903 | for (int i = 0; i < res; ++i) | ||
| 3904 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (*namelist)[i], | ||
| 3905 | (*namelist)[i]->d_reclen); | ||
| 3906 | } | ||
| 3907 | return res; | ||
| 3908 | } | ||
| 3909 | #define INIT_SCANDIR64 COMMON_INTERCEPT_FUNCTION(scandir64); | ||
| 3910 | #else | ||
| 3911 | #define INIT_SCANDIR64 | ||
| 3912 | #endif | ||
| 3913 | |||
| 3914 | #if SANITIZER_INTERCEPT_GETGROUPS | ||
| 3915 | INTERCEPTOR(int, getgroups, int size, u32 *lst) { | ||
| 3916 | void *ctx; | ||
| 3917 | COMMON_INTERCEPTOR_ENTER(ctx, getgroups, size, lst); | ||
| 3918 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3919 | // its metadata. See | ||
| 3920 | // https://github.com/google/sanitizers/issues/321. | ||
| 3921 | int res = REAL(getgroups)(size, lst); | ||
| 3922 | if (res >= 0 && lst && size > 0) | ||
| 3923 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst)); | ||
| 3924 | return res; | ||
| 3925 | } | ||
| 3926 | #define INIT_GETGROUPS COMMON_INTERCEPT_FUNCTION(getgroups); | ||
| 3927 | #else | ||
| 3928 | #define INIT_GETGROUPS | ||
| 3929 | #endif | ||
| 3930 | |||
| 3931 | #if SANITIZER_INTERCEPT_POLL | ||
| 3932 | static void read_pollfd(void *ctx, __sanitizer_pollfd *fds, | ||
| 3933 | __sanitizer_nfds_t nfds) { | ||
| 3934 | for (unsigned i = 0; i < nfds; ++i) { | ||
| 3935 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &fds[i].fd, sizeof(fds[i].fd)); | ||
| 3936 | COMMON_INTERCEPTOR_READ_RANGE(ctx, &fds[i].events, sizeof(fds[i].events)); | ||
| 3937 | } | ||
| 3938 | } | ||
| 3939 | |||
| 3940 | static void write_pollfd(void *ctx, __sanitizer_pollfd *fds, | ||
| 3941 | __sanitizer_nfds_t nfds) { | ||
| 3942 | for (unsigned i = 0; i < nfds; ++i) | ||
| 3943 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &fds[i].revents, | ||
| 3944 | sizeof(fds[i].revents)); | ||
| 3945 | } | ||
| 3946 | |||
| 3947 | INTERCEPTOR(int, poll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds, | ||
| 3948 | int timeout) { | ||
| 3949 | void *ctx; | ||
| 3950 | COMMON_INTERCEPTOR_ENTER(ctx, poll, fds, nfds, timeout); | ||
| 3951 | if (fds && nfds) read_pollfd(ctx, fds, nfds); | ||
| 3952 | int res = COMMON_INTERCEPTOR_BLOCK_REAL(poll)(fds, nfds, timeout); | ||
| 3953 | if (fds && nfds) write_pollfd(ctx, fds, nfds); | ||
| 3954 | return res; | ||
| 3955 | } | ||
| 3956 | #define INIT_POLL COMMON_INTERCEPT_FUNCTION(poll); | ||
| 3957 | #else | ||
| 3958 | #define INIT_POLL | ||
| 3959 | #endif | ||
| 3960 | |||
| 3961 | #if SANITIZER_INTERCEPT_PPOLL | ||
| 3962 | INTERCEPTOR(int, ppoll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds, | ||
| 3963 | void *timeout_ts, __sanitizer_sigset_t *sigmask) { | ||
| 3964 | void *ctx; | ||
| 3965 | COMMON_INTERCEPTOR_ENTER(ctx, ppoll, fds, nfds, timeout_ts, sigmask); | ||
| 3966 | if (fds && nfds) read_pollfd(ctx, fds, nfds); | ||
| 3967 | if (timeout_ts) | ||
| 3968 | COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout_ts, struct_timespec_sz); | ||
| 3969 | if (sigmask) COMMON_INTERCEPTOR_READ_RANGE(ctx, sigmask, sizeof(*sigmask)); | ||
| 3970 | int res = | ||
| 3971 | COMMON_INTERCEPTOR_BLOCK_REAL(ppoll)(fds, nfds, timeout_ts, sigmask); | ||
| 3972 | if (fds && nfds) write_pollfd(ctx, fds, nfds); | ||
| 3973 | return res; | ||
| 3974 | } | ||
| 3975 | #define INIT_PPOLL COMMON_INTERCEPT_FUNCTION(ppoll); | ||
| 3976 | #else | ||
| 3977 | #define INIT_PPOLL | ||
| 3978 | #endif | ||
| 3979 | |||
| 3980 | #if SANITIZER_INTERCEPT_WORDEXP | ||
| 3981 | INTERCEPTOR(int, wordexp, char *s, __sanitizer_wordexp_t *p, int flags) { | ||
| 3982 | void *ctx; | ||
| 3983 | COMMON_INTERCEPTOR_ENTER(ctx, wordexp, s, p, flags); | ||
| 3984 | if (s) COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1); | ||
| 3985 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 3986 | // its metadata. See | ||
| 3987 | // https://github.com/google/sanitizers/issues/321. | ||
| 3988 | int res = REAL(wordexp)(s, p, flags); | ||
| 3989 | if (!res && p) { | ||
| 3990 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); | ||
| 3991 | if (p->we_wordc) | ||
| 3992 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->we_wordv, | ||
| 3993 | sizeof(*p->we_wordv) * p->we_wordc); | ||
| 3994 | for (uptr i = 0; i < p->we_wordc; ++i) { | ||
| 3995 | char *w = p->we_wordv[i]; | ||
| 3996 | if (w) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, w, REAL(strlen)(w) + 1); | ||
| 3997 | } | ||
| 3998 | } | ||
| 3999 | return res; | ||
| 4000 | } | ||
| 4001 | #define INIT_WORDEXP COMMON_INTERCEPT_FUNCTION(wordexp); | ||
| 4002 | #else | ||
| 4003 | #define INIT_WORDEXP | ||
| 4004 | #endif | ||
| 4005 | |||
| 4006 | #if SANITIZER_INTERCEPT_SIGWAIT | ||
| 4007 | INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) { | ||
| 4008 | void *ctx; | ||
| 4009 | COMMON_INTERCEPTOR_ENTER(ctx, sigwait, set, sig); | ||
| 4010 | if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); | ||
| 4011 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4012 | // its metadata. See | ||
| 4013 | // https://github.com/google/sanitizers/issues/321. | ||
| 4014 | int res = REAL(sigwait)(set, sig); | ||
| 4015 | if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig)); | ||
| 4016 | return res; | ||
| 4017 | } | ||
| 4018 | #define INIT_SIGWAIT COMMON_INTERCEPT_FUNCTION(sigwait); | ||
| 4019 | #else | ||
| 4020 | #define INIT_SIGWAIT | ||
| 4021 | #endif | ||
| 4022 | |||
| 4023 | #if SANITIZER_INTERCEPT_SIGWAITINFO | ||
| 4024 | INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) { | ||
| 4025 | void *ctx; | ||
| 4026 | COMMON_INTERCEPTOR_ENTER(ctx, sigwaitinfo, set, info); | ||
| 4027 | if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); | ||
| 4028 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4029 | // its metadata. See | ||
| 4030 | // https://github.com/google/sanitizers/issues/321. | ||
| 4031 | int res = REAL(sigwaitinfo)(set, info); | ||
| 4032 | if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz); | ||
| 4033 | return res; | ||
| 4034 | } | ||
| 4035 | #define INIT_SIGWAITINFO COMMON_INTERCEPT_FUNCTION(sigwaitinfo); | ||
| 4036 | #else | ||
| 4037 | #define INIT_SIGWAITINFO | ||
| 4038 | #endif | ||
| 4039 | |||
| 4040 | #if SANITIZER_INTERCEPT_SIGTIMEDWAIT | ||
| 4041 | INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info, | ||
| 4042 | void *timeout) { | ||
| 4043 | void *ctx; | ||
| 4044 | COMMON_INTERCEPTOR_ENTER(ctx, sigtimedwait, set, info, timeout); | ||
| 4045 | if (timeout) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout, struct_timespec_sz); | ||
| 4046 | if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); | ||
| 4047 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4048 | // its metadata. See | ||
| 4049 | // https://github.com/google/sanitizers/issues/321. | ||
| 4050 | int res = REAL(sigtimedwait)(set, info, timeout); | ||
| 4051 | if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz); | ||
| 4052 | return res; | ||
| 4053 | } | ||
| 4054 | #define INIT_SIGTIMEDWAIT COMMON_INTERCEPT_FUNCTION(sigtimedwait); | ||
| 4055 | #else | ||
| 4056 | #define INIT_SIGTIMEDWAIT | ||
| 4057 | #endif | ||
| 4058 | |||
| 4059 | #if SANITIZER_INTERCEPT_SIGSETOPS | ||
| 4060 | INTERCEPTOR(int, sigemptyset, __sanitizer_sigset_t *set) { | ||
| 4061 | void *ctx; | ||
| 4062 | COMMON_INTERCEPTOR_ENTER(ctx, sigemptyset, set); | ||
| 4063 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4064 | // its metadata. See | ||
| 4065 | // https://github.com/google/sanitizers/issues/321. | ||
| 4066 | int res = REAL(sigemptyset)(set); | ||
| 4067 | if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set)); | ||
| 4068 | return res; | ||
| 4069 | } | ||
| 4070 | |||
| 4071 | INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) { | ||
| 4072 | void *ctx; | ||
| 4073 | COMMON_INTERCEPTOR_ENTER(ctx, sigfillset, set); | ||
| 4074 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4075 | // its metadata. See | ||
| 4076 | // https://github.com/google/sanitizers/issues/321. | ||
| 4077 | int res = REAL(sigfillset)(set); | ||
| 4078 | if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set)); | ||
| 4079 | return res; | ||
| 4080 | } | ||
| 4081 | #define INIT_SIGSETOPS \ | ||
| 4082 | COMMON_INTERCEPT_FUNCTION(sigemptyset); \ | ||
| 4083 | COMMON_INTERCEPT_FUNCTION(sigfillset); | ||
| 4084 | #else | ||
| 4085 | #define INIT_SIGSETOPS | ||
| 4086 | #endif | ||
| 4087 | |||
| 4088 | #if SANITIZER_INTERCEPT_SIGPENDING | ||
| 4089 | INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) { | ||
| 4090 | void *ctx; | ||
| 4091 | COMMON_INTERCEPTOR_ENTER(ctx, sigpending, set); | ||
| 4092 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4093 | // its metadata. See | ||
| 4094 | // https://github.com/google/sanitizers/issues/321. | ||
| 4095 | int res = REAL(sigpending)(set); | ||
| 4096 | if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set)); | ||
| 4097 | return res; | ||
| 4098 | } | ||
| 4099 | #define INIT_SIGPENDING COMMON_INTERCEPT_FUNCTION(sigpending); | ||
| 4100 | #else | ||
| 4101 | #define INIT_SIGPENDING | ||
| 4102 | #endif | ||
| 4103 | |||
| 4104 | #if SANITIZER_INTERCEPT_SIGPROCMASK | ||
| 4105 | INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set, | ||
| 4106 | __sanitizer_sigset_t *oldset) { | ||
| 4107 | void *ctx; | ||
| 4108 | COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset); | ||
| 4109 | if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); | ||
| 4110 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4111 | // its metadata. See | ||
| 4112 | // https://github.com/google/sanitizers/issues/321. | ||
| 4113 | int res = REAL(sigprocmask)(how, set, oldset); | ||
| 4114 | if (!res && oldset) | ||
| 4115 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); | ||
| 4116 | return res; | ||
| 4117 | } | ||
| 4118 | #define INIT_SIGPROCMASK COMMON_INTERCEPT_FUNCTION(sigprocmask); | ||
| 4119 | #else | ||
| 4120 | #define INIT_SIGPROCMASK | ||
| 4121 | #endif | ||
| 4122 | |||
| 4123 | #if SANITIZER_INTERCEPT_PTHREAD_SIGMASK | ||
| 4124 | INTERCEPTOR(int, pthread_sigmask, int how, __sanitizer_sigset_t *set, | ||
| 4125 | __sanitizer_sigset_t *oldset) { | ||
| 4126 | void *ctx; | ||
| 4127 | COMMON_INTERCEPTOR_ENTER(ctx, pthread_sigmask, how, set, oldset); | ||
| 4128 | if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set)); | ||
| 4129 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4130 | // its metadata. See | ||
| 4131 | // https://github.com/google/sanitizers/issues/321. | ||
| 4132 | int res = REAL(pthread_sigmask)(how, set, oldset); | ||
| 4133 | if (!res && oldset) | ||
| 4134 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); | ||
| 4135 | return res; | ||
| 4136 | } | ||
| 4137 | #define INIT_PTHREAD_SIGMASK COMMON_INTERCEPT_FUNCTION(pthread_sigmask); | ||
| 4138 | #else | ||
| 4139 | #define INIT_PTHREAD_SIGMASK | ||
| 4140 | #endif | ||
| 4141 | |||
| 4142 | #if SANITIZER_INTERCEPT_BACKTRACE | ||
| 4143 | INTERCEPTOR(int, backtrace, void **buffer, int size) { | ||
| 4144 | void *ctx; | ||
| 4145 | COMMON_INTERCEPTOR_ENTER(ctx, backtrace, buffer, size); | ||
| 4146 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4147 | // its metadata. See | ||
| 4148 | // https://github.com/google/sanitizers/issues/321. | ||
| 4149 | int res = REAL(backtrace)(buffer, size); | ||
| 4150 | if (res && buffer) | ||
| 4151 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buffer, res * sizeof(*buffer)); | ||
| 4152 | return res; | ||
| 4153 | } | ||
| 4154 | |||
| 4155 | INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) { | ||
| 4156 | void *ctx; | ||
| 4157 | COMMON_INTERCEPTOR_ENTER(ctx, backtrace_symbols, buffer, size); | ||
| 4158 | if (buffer && size) | ||
| 4159 | COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, size * sizeof(*buffer)); | ||
| 4160 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4161 | // its metadata. See | ||
| 4162 | // https://github.com/google/sanitizers/issues/321. | ||
| 4163 | char **res = REAL(backtrace_symbols)(buffer, size); | ||
| 4164 | if (res && size) { | ||
| 4165 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, size * sizeof(*res)); | ||
| 4166 | for (int i = 0; i < size; ++i) | ||
| 4167 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res[i], REAL(strlen(res[i])) + 1); | ||
| 4168 | } | ||
| 4169 | return res; | ||
| 4170 | } | ||
| 4171 | #define INIT_BACKTRACE \ | ||
| 4172 | COMMON_INTERCEPT_FUNCTION(backtrace); \ | ||
| 4173 | COMMON_INTERCEPT_FUNCTION(backtrace_symbols); | ||
| 4174 | #else | ||
| 4175 | #define INIT_BACKTRACE | ||
| 4176 | #endif | ||
| 4177 | |||
| 4178 | #if SANITIZER_INTERCEPT__EXIT | ||
| 4179 | INTERCEPTOR(void, _exit, int status) { | ||
| 4180 | void *ctx; | ||
| 4181 | COMMON_INTERCEPTOR_ENTER(ctx, _exit, status); | ||
| 4182 | COMMON_INTERCEPTOR_USER_CALLBACK_START(); | ||
| 4183 | int status1 = COMMON_INTERCEPTOR_ON_EXIT(ctx); | ||
| 4184 | COMMON_INTERCEPTOR_USER_CALLBACK_END(); | ||
| 4185 | if (status == 0) status = status1; | ||
| 4186 | REAL(_exit)(status); | ||
| 4187 | } | ||
| 4188 | #define INIT__EXIT COMMON_INTERCEPT_FUNCTION(_exit); | ||
| 4189 | #else | ||
| 4190 | #define INIT__EXIT | ||
| 4191 | #endif | ||
| 4192 | |||
| 4193 | #if SANITIZER_INTERCEPT_PTHREAD_MUTEX | ||
| 4194 | INTERCEPTOR(int, pthread_mutex_lock, void *m) { | ||
| 4195 | void *ctx; | ||
| 4196 | COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_lock, m); | ||
| 4197 | COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m); | ||
| 4198 | int res = REAL(pthread_mutex_lock)(m); | ||
| 4199 | if (res == errno_EOWNERDEAD) | ||
| 4200 | COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m); | ||
| 4201 | if (res == 0 || res == errno_EOWNERDEAD) | ||
| 4202 | COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m); | ||
| 4203 | if (res == errno_EINVAL) | ||
| 4204 | COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m); | ||
| 4205 | return res; | ||
| 4206 | } | ||
| 4207 | |||
| 4208 | INTERCEPTOR(int, pthread_mutex_unlock, void *m) { | ||
| 4209 | void *ctx; | ||
| 4210 | COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_unlock, m); | ||
| 4211 | COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m); | ||
| 4212 | int res = REAL(pthread_mutex_unlock)(m); | ||
| 4213 | if (res == errno_EINVAL) | ||
| 4214 | COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m); | ||
| 4215 | return res; | ||
| 4216 | } | ||
| 4217 | |||
| 4218 | #define INIT_PTHREAD_MUTEX_LOCK COMMON_INTERCEPT_FUNCTION(pthread_mutex_lock) | ||
| 4219 | #define INIT_PTHREAD_MUTEX_UNLOCK \ | ||
| 4220 | COMMON_INTERCEPT_FUNCTION(pthread_mutex_unlock) | ||
| 4221 | #else | ||
| 4222 | #define INIT_PTHREAD_MUTEX_LOCK | ||
| 4223 | #define INIT_PTHREAD_MUTEX_UNLOCK | ||
| 4224 | #endif | ||
| 4225 | |||
| 4226 | #if SANITIZER_INTERCEPT___PTHREAD_MUTEX | ||
| 4227 | INTERCEPTOR(int, __pthread_mutex_lock, void *m) { | ||
| 4228 | void *ctx; | ||
| 4229 | COMMON_INTERCEPTOR_ENTER(ctx, __pthread_mutex_lock, m); | ||
| 4230 | COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m); | ||
| 4231 | int res = REAL(__pthread_mutex_lock)(m); | ||
| 4232 | if (res == errno_EOWNERDEAD) | ||
| 4233 | COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m); | ||
| 4234 | if (res == 0 || res == errno_EOWNERDEAD) | ||
| 4235 | COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m); | ||
| 4236 | if (res == errno_EINVAL) | ||
| 4237 | COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m); | ||
| 4238 | return res; | ||
| 4239 | } | ||
| 4240 | |||
| 4241 | INTERCEPTOR(int, __pthread_mutex_unlock, void *m) { | ||
| 4242 | void *ctx; | ||
| 4243 | COMMON_INTERCEPTOR_ENTER(ctx, __pthread_mutex_unlock, m); | ||
| 4244 | COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m); | ||
| 4245 | int res = REAL(__pthread_mutex_unlock)(m); | ||
| 4246 | if (res == errno_EINVAL) | ||
| 4247 | COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m); | ||
| 4248 | return res; | ||
| 4249 | } | ||
| 4250 | |||
| 4251 | #define INIT___PTHREAD_MUTEX_LOCK \ | ||
| 4252 | COMMON_INTERCEPT_FUNCTION(__pthread_mutex_lock) | ||
| 4253 | #define INIT___PTHREAD_MUTEX_UNLOCK \ | ||
| 4254 | COMMON_INTERCEPT_FUNCTION(__pthread_mutex_unlock) | ||
| 4255 | #else | ||
| 4256 | #define INIT___PTHREAD_MUTEX_LOCK | ||
| 4257 | #define INIT___PTHREAD_MUTEX_UNLOCK | ||
| 4258 | #endif | ||
| 4259 | |||
| 4260 | #if SANITIZER_INTERCEPT___LIBC_MUTEX | ||
| 4261 | INTERCEPTOR(int, __libc_mutex_lock, void *m) | ||
| 4262 | ALIAS(WRAPPER_NAME(pthread_mutex_lock)); | ||
| 4263 | |||
| 4264 | INTERCEPTOR(int, __libc_mutex_unlock, void *m) | ||
| 4265 | ALIAS(WRAPPER_NAME(pthread_mutex_unlock)); | ||
| 4266 | |||
| 4267 | INTERCEPTOR(int, __libc_thr_setcancelstate, int state, int *oldstate) | ||
| 4268 | ALIAS(WRAPPER_NAME(pthread_setcancelstate)); | ||
| 4269 | |||
| 4270 | #define INIT___LIBC_MUTEX_LOCK COMMON_INTERCEPT_FUNCTION(__libc_mutex_lock) | ||
| 4271 | #define INIT___LIBC_MUTEX_UNLOCK COMMON_INTERCEPT_FUNCTION(__libc_mutex_unlock) | ||
| 4272 | #define INIT___LIBC_THR_SETCANCELSTATE \ | ||
| 4273 | COMMON_INTERCEPT_FUNCTION(__libc_thr_setcancelstate) | ||
| 4274 | #else | ||
| 4275 | #define INIT___LIBC_MUTEX_LOCK | ||
| 4276 | #define INIT___LIBC_MUTEX_UNLOCK | ||
| 4277 | #define INIT___LIBC_THR_SETCANCELSTATE | ||
| 4278 | #endif | ||
| 4279 | |||
| 4280 | #if SANITIZER_INTERCEPT_GETMNTENT || SANITIZER_INTERCEPT_GETMNTENT_R | ||
| 4281 | static void write_mntent(void *ctx, __sanitizer_mntent *mnt) { | ||
| 4282 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt, sizeof(*mnt)); | ||
| 4283 | if (mnt->mnt_fsname) | ||
| 4284 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_fsname, | ||
| 4285 | REAL(strlen)(mnt->mnt_fsname) + 1); | ||
| 4286 | if (mnt->mnt_dir) | ||
| 4287 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_dir, | ||
| 4288 | REAL(strlen)(mnt->mnt_dir) + 1); | ||
| 4289 | if (mnt->mnt_type) | ||
| 4290 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_type, | ||
| 4291 | REAL(strlen)(mnt->mnt_type) + 1); | ||
| 4292 | if (mnt->mnt_opts) | ||
| 4293 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_opts, | ||
| 4294 | REAL(strlen)(mnt->mnt_opts) + 1); | ||
| 4295 | } | ||
| 4296 | #endif | ||
| 4297 | |||
| 4298 | #if SANITIZER_INTERCEPT_GETMNTENT | ||
| 4299 | INTERCEPTOR(__sanitizer_mntent *, getmntent, void *fp) { | ||
| 4300 | void *ctx; | ||
| 4301 | COMMON_INTERCEPTOR_ENTER(ctx, getmntent, fp); | ||
| 4302 | __sanitizer_mntent *res = REAL(getmntent)(fp); | ||
| 4303 | if (res) write_mntent(ctx, res); | ||
| 4304 | return res; | ||
| 4305 | } | ||
| 4306 | #define INIT_GETMNTENT COMMON_INTERCEPT_FUNCTION(getmntent); | ||
| 4307 | #else | ||
| 4308 | #define INIT_GETMNTENT | ||
| 4309 | #endif | ||
| 4310 | |||
| 4311 | #if SANITIZER_INTERCEPT_GETMNTENT_R | ||
| 4312 | INTERCEPTOR(__sanitizer_mntent *, getmntent_r, void *fp, | ||
| 4313 | __sanitizer_mntent *mntbuf, char *buf, int buflen) { | ||
| 4314 | void *ctx; | ||
| 4315 | COMMON_INTERCEPTOR_ENTER(ctx, getmntent_r, fp, mntbuf, buf, buflen); | ||
| 4316 | __sanitizer_mntent *res = REAL(getmntent_r)(fp, mntbuf, buf, buflen); | ||
| 4317 | if (res) write_mntent(ctx, res); | ||
| 4318 | return res; | ||
| 4319 | } | ||
| 4320 | #define INIT_GETMNTENT_R COMMON_INTERCEPT_FUNCTION(getmntent_r); | ||
| 4321 | #else | ||
| 4322 | #define INIT_GETMNTENT_R | ||
| 4323 | #endif | ||
| 4324 | |||
| 4325 | #if SANITIZER_INTERCEPT_STATFS | ||
| 4326 | INTERCEPTOR(int, statfs, char *path, void *buf) { | ||
| 4327 | void *ctx; | ||
| 4328 | COMMON_INTERCEPTOR_ENTER(ctx, statfs, path, buf); | ||
| 4329 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 4330 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4331 | // its metadata. See | ||
| 4332 | // https://github.com/google/sanitizers/issues/321. | ||
| 4333 | int res = REAL(statfs)(path, buf); | ||
| 4334 | if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz); | ||
| 4335 | return res; | ||
| 4336 | } | ||
| 4337 | INTERCEPTOR(int, fstatfs, int fd, void *buf) { | ||
| 4338 | void *ctx; | ||
| 4339 | COMMON_INTERCEPTOR_ENTER(ctx, fstatfs, fd, buf); | ||
| 4340 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4341 | // its metadata. See | ||
| 4342 | // https://github.com/google/sanitizers/issues/321. | ||
| 4343 | int res = REAL(fstatfs)(fd, buf); | ||
| 4344 | if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz); | ||
| 4345 | return res; | ||
| 4346 | } | ||
| 4347 | #define INIT_STATFS \ | ||
| 4348 | COMMON_INTERCEPT_FUNCTION(statfs); \ | ||
| 4349 | COMMON_INTERCEPT_FUNCTION(fstatfs); | ||
| 4350 | #else | ||
| 4351 | #define INIT_STATFS | ||
| 4352 | #endif | ||
| 4353 | |||
| 4354 | #if SANITIZER_INTERCEPT_STATFS64 | ||
| 4355 | INTERCEPTOR(int, statfs64, char *path, void *buf) { | ||
| 4356 | void *ctx; | ||
| 4357 | COMMON_INTERCEPTOR_ENTER(ctx, statfs64, path, buf); | ||
| 4358 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 4359 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4360 | // its metadata. See | ||
| 4361 | // https://github.com/google/sanitizers/issues/321. | ||
| 4362 | int res = REAL(statfs64)(path, buf); | ||
| 4363 | if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz); | ||
| 4364 | return res; | ||
| 4365 | } | ||
| 4366 | INTERCEPTOR(int, fstatfs64, int fd, void *buf) { | ||
| 4367 | void *ctx; | ||
| 4368 | COMMON_INTERCEPTOR_ENTER(ctx, fstatfs64, fd, buf); | ||
| 4369 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4370 | // its metadata. See | ||
| 4371 | // https://github.com/google/sanitizers/issues/321. | ||
| 4372 | int res = REAL(fstatfs64)(fd, buf); | ||
| 4373 | if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz); | ||
| 4374 | return res; | ||
| 4375 | } | ||
| 4376 | #define INIT_STATFS64 \ | ||
| 4377 | COMMON_INTERCEPT_FUNCTION(statfs64); \ | ||
| 4378 | COMMON_INTERCEPT_FUNCTION(fstatfs64); | ||
| 4379 | #else | ||
| 4380 | #define INIT_STATFS64 | ||
| 4381 | #endif | ||
| 4382 | |||
| 4383 | #if SANITIZER_INTERCEPT_STATVFS | ||
| 4384 | INTERCEPTOR(int, statvfs, char *path, void *buf) { | ||
| 4385 | void *ctx; | ||
| 4386 | COMMON_INTERCEPTOR_ENTER(ctx, statvfs, path, buf); | ||
| 4387 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 4388 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4389 | // its metadata. See | ||
| 4390 | // https://github.com/google/sanitizers/issues/321. | ||
| 4391 | int res = REAL(statvfs)(path, buf); | ||
| 4392 | if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz); | ||
| 4393 | return res; | ||
| 4394 | } | ||
| 4395 | INTERCEPTOR(int, fstatvfs, int fd, void *buf) { | ||
| 4396 | void *ctx; | ||
| 4397 | COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf); | ||
| 4398 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 4399 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4400 | // its metadata. See | ||
| 4401 | // https://github.com/google/sanitizers/issues/321. | ||
| 4402 | int res = REAL(fstatvfs)(fd, buf); | ||
| 4403 | if (!res) { | ||
| 4404 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz); | ||
| 4405 | if (fd >= 0) | ||
| 4406 | COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 4407 | } | ||
| 4408 | return res; | ||
| 4409 | } | ||
| 4410 | #define INIT_STATVFS \ | ||
| 4411 | COMMON_INTERCEPT_FUNCTION(statvfs); \ | ||
| 4412 | COMMON_INTERCEPT_FUNCTION(fstatvfs); | ||
| 4413 | #else | ||
| 4414 | #define INIT_STATVFS | ||
| 4415 | #endif | ||
| 4416 | |||
| 4417 | #if SANITIZER_INTERCEPT_STATVFS64 | ||
| 4418 | INTERCEPTOR(int, statvfs64, char *path, void *buf) { | ||
| 4419 | void *ctx; | ||
| 4420 | COMMON_INTERCEPTOR_ENTER(ctx, statvfs64, path, buf); | ||
| 4421 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 4422 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4423 | // its metadata. See | ||
| 4424 | // https://github.com/google/sanitizers/issues/321. | ||
| 4425 | int res = REAL(statvfs64)(path, buf); | ||
| 4426 | if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz); | ||
| 4427 | return res; | ||
| 4428 | } | ||
| 4429 | INTERCEPTOR(int, fstatvfs64, int fd, void *buf) { | ||
| 4430 | void *ctx; | ||
| 4431 | COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs64, fd, buf); | ||
| 4432 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4433 | // its metadata. See | ||
| 4434 | // https://github.com/google/sanitizers/issues/321. | ||
| 4435 | int res = REAL(fstatvfs64)(fd, buf); | ||
| 4436 | if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz); | ||
| 4437 | return res; | ||
| 4438 | } | ||
| 4439 | #define INIT_STATVFS64 \ | ||
| 4440 | COMMON_INTERCEPT_FUNCTION(statvfs64); \ | ||
| 4441 | COMMON_INTERCEPT_FUNCTION(fstatvfs64); | ||
| 4442 | #else | ||
| 4443 | #define INIT_STATVFS64 | ||
| 4444 | #endif | ||
| 4445 | |||
| 4446 | #if SANITIZER_INTERCEPT_INITGROUPS | ||
| 4447 | INTERCEPTOR(int, initgroups, char *user, u32 group) { | ||
| 4448 | void *ctx; | ||
| 4449 | COMMON_INTERCEPTOR_ENTER(ctx, initgroups, user, group); | ||
| 4450 | if (user) COMMON_INTERCEPTOR_READ_RANGE(ctx, user, REAL(strlen)(user) + 1); | ||
| 4451 | int res = REAL(initgroups)(user, group); | ||
| 4452 | return res; | ||
| 4453 | } | ||
| 4454 | #define INIT_INITGROUPS COMMON_INTERCEPT_FUNCTION(initgroups); | ||
| 4455 | #else | ||
| 4456 | #define INIT_INITGROUPS | ||
| 4457 | #endif | ||
| 4458 | |||
| 4459 | #if SANITIZER_INTERCEPT_ETHER_NTOA_ATON | ||
| 4460 | INTERCEPTOR(char *, ether_ntoa, __sanitizer_ether_addr *addr) { | ||
| 4461 | void *ctx; | ||
| 4462 | COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa, addr); | ||
| 4463 | if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr)); | ||
| 4464 | char *res = REAL(ether_ntoa)(addr); | ||
| 4465 | if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); | ||
| 4466 | return res; | ||
| 4467 | } | ||
| 4468 | INTERCEPTOR(__sanitizer_ether_addr *, ether_aton, char *buf) { | ||
| 4469 | void *ctx; | ||
| 4470 | COMMON_INTERCEPTOR_ENTER(ctx, ether_aton, buf); | ||
| 4471 | if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1); | ||
| 4472 | __sanitizer_ether_addr *res = REAL(ether_aton)(buf); | ||
| 4473 | if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, sizeof(*res)); | ||
| 4474 | return res; | ||
| 4475 | } | ||
| 4476 | #define INIT_ETHER_NTOA_ATON \ | ||
| 4477 | COMMON_INTERCEPT_FUNCTION(ether_ntoa); \ | ||
| 4478 | COMMON_INTERCEPT_FUNCTION(ether_aton); | ||
| 4479 | #else | ||
| 4480 | #define INIT_ETHER_NTOA_ATON | ||
| 4481 | #endif | ||
| 4482 | |||
| 4483 | #if SANITIZER_INTERCEPT_ETHER_HOST | ||
| 4484 | INTERCEPTOR(int, ether_ntohost, char *hostname, __sanitizer_ether_addr *addr) { | ||
| 4485 | void *ctx; | ||
| 4486 | COMMON_INTERCEPTOR_ENTER(ctx, ether_ntohost, hostname, addr); | ||
| 4487 | if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr)); | ||
| 4488 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4489 | // its metadata. See | ||
| 4490 | // https://github.com/google/sanitizers/issues/321. | ||
| 4491 | int res = REAL(ether_ntohost)(hostname, addr); | ||
| 4492 | if (!res && hostname) | ||
| 4493 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1); | ||
| 4494 | return res; | ||
| 4495 | } | ||
| 4496 | INTERCEPTOR(int, ether_hostton, char *hostname, __sanitizer_ether_addr *addr) { | ||
| 4497 | void *ctx; | ||
| 4498 | COMMON_INTERCEPTOR_ENTER(ctx, ether_hostton, hostname, addr); | ||
| 4499 | if (hostname) | ||
| 4500 | COMMON_INTERCEPTOR_READ_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1); | ||
| 4501 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4502 | // its metadata. See | ||
| 4503 | // https://github.com/google/sanitizers/issues/321. | ||
| 4504 | int res = REAL(ether_hostton)(hostname, addr); | ||
| 4505 | if (!res && addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr)); | ||
| 4506 | return res; | ||
| 4507 | } | ||
| 4508 | INTERCEPTOR(int, ether_line, char *line, __sanitizer_ether_addr *addr, | ||
| 4509 | char *hostname) { | ||
| 4510 | void *ctx; | ||
| 4511 | COMMON_INTERCEPTOR_ENTER(ctx, ether_line, line, addr, hostname); | ||
| 4512 | if (line) COMMON_INTERCEPTOR_READ_RANGE(ctx, line, REAL(strlen)(line) + 1); | ||
| 4513 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4514 | // its metadata. See | ||
| 4515 | // https://github.com/google/sanitizers/issues/321. | ||
| 4516 | int res = REAL(ether_line)(line, addr, hostname); | ||
| 4517 | if (!res) { | ||
| 4518 | if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr)); | ||
| 4519 | if (hostname) | ||
| 4520 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1); | ||
| 4521 | } | ||
| 4522 | return res; | ||
| 4523 | } | ||
| 4524 | #define INIT_ETHER_HOST \ | ||
| 4525 | COMMON_INTERCEPT_FUNCTION(ether_ntohost); \ | ||
| 4526 | COMMON_INTERCEPT_FUNCTION(ether_hostton); \ | ||
| 4527 | COMMON_INTERCEPT_FUNCTION(ether_line); | ||
| 4528 | #else | ||
| 4529 | #define INIT_ETHER_HOST | ||
| 4530 | #endif | ||
| 4531 | |||
| 4532 | #if SANITIZER_INTERCEPT_ETHER_R | ||
| 4533 | INTERCEPTOR(char *, ether_ntoa_r, __sanitizer_ether_addr *addr, char *buf) { | ||
| 4534 | void *ctx; | ||
| 4535 | COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa_r, addr, buf); | ||
| 4536 | if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr)); | ||
| 4537 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4538 | // its metadata. See | ||
| 4539 | // https://github.com/google/sanitizers/issues/321. | ||
| 4540 | char *res = REAL(ether_ntoa_r)(addr, buf); | ||
| 4541 | if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); | ||
| 4542 | return res; | ||
| 4543 | } | ||
| 4544 | INTERCEPTOR(__sanitizer_ether_addr *, ether_aton_r, char *buf, | ||
| 4545 | __sanitizer_ether_addr *addr) { | ||
| 4546 | void *ctx; | ||
| 4547 | COMMON_INTERCEPTOR_ENTER(ctx, ether_aton_r, buf, addr); | ||
| 4548 | if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1); | ||
| 4549 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4550 | // its metadata. See | ||
| 4551 | // https://github.com/google/sanitizers/issues/321. | ||
| 4552 | __sanitizer_ether_addr *res = REAL(ether_aton_r)(buf, addr); | ||
| 4553 | if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(*res)); | ||
| 4554 | return res; | ||
| 4555 | } | ||
| 4556 | #define INIT_ETHER_R \ | ||
| 4557 | COMMON_INTERCEPT_FUNCTION(ether_ntoa_r); \ | ||
| 4558 | COMMON_INTERCEPT_FUNCTION(ether_aton_r); | ||
| 4559 | #else | ||
| 4560 | #define INIT_ETHER_R | ||
| 4561 | #endif | ||
| 4562 | |||
| 4563 | #if SANITIZER_INTERCEPT_SHMCTL | ||
| 4564 | INTERCEPTOR(int, shmctl, int shmid, int cmd, void *buf) { | ||
| 4565 | void *ctx; | ||
| 4566 | COMMON_INTERCEPTOR_ENTER(ctx, shmctl, shmid, cmd, buf); | ||
| 4567 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4568 | // its metadata. See | ||
| 4569 | // https://github.com/google/sanitizers/issues/321. | ||
| 4570 | int res = REAL(shmctl)(shmid, cmd, buf); | ||
| 4571 | if (res >= 0) { | ||
| 4572 | unsigned sz = 0; | ||
| 4573 | if (cmd == shmctl_ipc_stat || cmd == shmctl_shm_stat) | ||
| 4574 | sz = sizeof(__sanitizer_shmid_ds); | ||
| 4575 | else if (cmd == shmctl_ipc_info) | ||
| 4576 | sz = struct_shminfo_sz; | ||
| 4577 | else if (cmd == shmctl_shm_info) | ||
| 4578 | sz = struct_shm_info_sz; | ||
| 4579 | if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz); | ||
| 4580 | } | ||
| 4581 | return res; | ||
| 4582 | } | ||
| 4583 | #define INIT_SHMCTL COMMON_INTERCEPT_FUNCTION(shmctl); | ||
| 4584 | #else | ||
| 4585 | #define INIT_SHMCTL | ||
| 4586 | #endif | ||
| 4587 | |||
| 4588 | #if SANITIZER_INTERCEPT_RANDOM_R | ||
| 4589 | INTERCEPTOR(int, random_r, void *buf, u32 *result) { | ||
| 4590 | void *ctx; | ||
| 4591 | COMMON_INTERCEPTOR_ENTER(ctx, random_r, buf, result); | ||
| 4592 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4593 | // its metadata. See | ||
| 4594 | // https://github.com/google/sanitizers/issues/321. | ||
| 4595 | int res = REAL(random_r)(buf, result); | ||
| 4596 | if (!res && result) | ||
| 4597 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); | ||
| 4598 | return res; | ||
| 4599 | } | ||
| 4600 | #define INIT_RANDOM_R COMMON_INTERCEPT_FUNCTION(random_r); | ||
| 4601 | #else | ||
| 4602 | #define INIT_RANDOM_R | ||
| 4603 | #endif | ||
| 4604 | |||
| 4605 | // FIXME: under ASan the REAL() call below may write to freed memory and corrupt | ||
| 4606 | // its metadata. See | ||
| 4607 | // https://github.com/google/sanitizers/issues/321. | ||
| 4608 | #if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET || \ | ||
| 4609 | SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED || \ | ||
| 4610 | SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSSCHED || \ | ||
| 4611 | SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GET || \ | ||
| 4612 | SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GET || \ | ||
| 4613 | SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GET || \ | ||
| 4614 | SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GET | ||
| 4615 | #define INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(fn, sz) \ | ||
| 4616 | INTERCEPTOR(int, fn, void *attr, void *r) { \ | ||
| 4617 | void *ctx; \ | ||
| 4618 | COMMON_INTERCEPTOR_ENTER(ctx, fn, attr, r); \ | ||
| 4619 | int res = REAL(fn)(attr, r); \ | ||
| 4620 | if (!res && r) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, r, sz); \ | ||
| 4621 | return res; \ | ||
| 4622 | } | ||
| 4623 | #define INTERCEPTOR_PTHREAD_ATTR_GET(what, sz) \ | ||
| 4624 | INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_attr_get##what, sz) | ||
| 4625 | #define INTERCEPTOR_PTHREAD_MUTEXATTR_GET(what, sz) \ | ||
| 4626 | INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_mutexattr_get##what, sz) | ||
| 4627 | #define INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(what, sz) \ | ||
| 4628 | INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_rwlockattr_get##what, sz) | ||
| 4629 | #define INTERCEPTOR_PTHREAD_CONDATTR_GET(what, sz) \ | ||
| 4630 | INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_condattr_get##what, sz) | ||
| 4631 | #define INTERCEPTOR_PTHREAD_BARRIERATTR_GET(what, sz) \ | ||
| 4632 | INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_barrierattr_get##what, sz) | ||
| 4633 | #endif | ||
| 4634 | |||
| 4635 | #if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET | ||
| 4636 | INTERCEPTOR_PTHREAD_ATTR_GET(detachstate, sizeof(int)) | ||
| 4637 | INTERCEPTOR_PTHREAD_ATTR_GET(guardsize, sizeof(SIZE_T)) | ||
| 4638 | INTERCEPTOR_PTHREAD_ATTR_GET(scope, sizeof(int)) | ||
| 4639 | INTERCEPTOR_PTHREAD_ATTR_GET(stacksize, sizeof(SIZE_T)) | ||
| 4640 | INTERCEPTOR(int, pthread_attr_getstack, void *attr, void **addr, SIZE_T *size) { | ||
| 4641 | void *ctx; | ||
| 4642 | COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getstack, attr, addr, size); | ||
| 4643 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4644 | // its metadata. See | ||
| 4645 | // https://github.com/google/sanitizers/issues/321. | ||
| 4646 | int res = REAL(pthread_attr_getstack)(attr, addr, size); | ||
| 4647 | if (!res) { | ||
| 4648 | if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr)); | ||
| 4649 | if (size) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, size, sizeof(*size)); | ||
| 4650 | } | ||
| 4651 | return res; | ||
| 4652 | } | ||
| 4653 | |||
| 4654 | // We may need to call the real pthread_attr_getstack from the run-time | ||
| 4655 | // in sanitizer_common, but we don't want to include the interception headers | ||
| 4656 | // there. So, just define this function here. | ||
| 4657 | namespace __sanitizer { | ||
| 4658 | extern "C" { | ||
| 4659 | int real_pthread_attr_getstack(void *attr, void **addr, SIZE_T *size) { | ||
| 4660 | return REAL(pthread_attr_getstack)(attr, addr, size); | ||
| 4661 | } | ||
| 4662 | } // extern "C" | ||
| 4663 | } // namespace __sanitizer | ||
| 4664 | |||
| 4665 | #define INIT_PTHREAD_ATTR_GET \ | ||
| 4666 | COMMON_INTERCEPT_FUNCTION(pthread_attr_getdetachstate); \ | ||
| 4667 | COMMON_INTERCEPT_FUNCTION(pthread_attr_getguardsize); \ | ||
| 4668 | COMMON_INTERCEPT_FUNCTION(pthread_attr_getscope); \ | ||
| 4669 | COMMON_INTERCEPT_FUNCTION(pthread_attr_getstacksize); \ | ||
| 4670 | COMMON_INTERCEPT_FUNCTION(pthread_attr_getstack); | ||
| 4671 | #else | ||
| 4672 | #define INIT_PTHREAD_ATTR_GET | ||
| 4673 | #endif | ||
| 4674 | |||
| 4675 | #if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED | ||
| 4676 | INTERCEPTOR_PTHREAD_ATTR_GET(schedparam, struct_sched_param_sz) | ||
| 4677 | INTERCEPTOR_PTHREAD_ATTR_GET(schedpolicy, sizeof(int)) | ||
| 4678 | |||
| 4679 | #define INIT_PTHREAD_ATTR_GET_SCHED \ | ||
| 4680 | COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedparam); \ | ||
| 4681 | COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedpolicy); | ||
| 4682 | #else | ||
| 4683 | #define INIT_PTHREAD_ATTR_GET_SCHED | ||
| 4684 | #endif | ||
| 4685 | |||
| 4686 | #if SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED | ||
| 4687 | INTERCEPTOR_PTHREAD_ATTR_GET(inheritsched, sizeof(int)) | ||
| 4688 | |||
| 4689 | #define INIT_PTHREAD_ATTR_GETINHERITSCHED \ | ||
| 4690 | COMMON_INTERCEPT_FUNCTION(pthread_attr_getinheritsched); | ||
| 4691 | #else | ||
| 4692 | #define INIT_PTHREAD_ATTR_GETINHERITSCHED | ||
| 4693 | #endif | ||
| 4694 | |||
| 4695 | #if SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP | ||
| 4696 | INTERCEPTOR(int, pthread_attr_getaffinity_np, void *attr, SIZE_T cpusetsize, | ||
| 4697 | void *cpuset) { | ||
| 4698 | void *ctx; | ||
| 4699 | COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getaffinity_np, attr, cpusetsize, | ||
| 4700 | cpuset); | ||
| 4701 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4702 | // its metadata. See | ||
| 4703 | // https://github.com/google/sanitizers/issues/321. | ||
| 4704 | int res = REAL(pthread_attr_getaffinity_np)(attr, cpusetsize, cpuset); | ||
| 4705 | if (!res && cpusetsize && cpuset) | ||
| 4706 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cpuset, cpusetsize); | ||
| 4707 | return res; | ||
| 4708 | } | ||
| 4709 | |||
| 4710 | #define INIT_PTHREAD_ATTR_GETAFFINITY_NP \ | ||
| 4711 | COMMON_INTERCEPT_FUNCTION(pthread_attr_getaffinity_np); | ||
| 4712 | #else | ||
| 4713 | #define INIT_PTHREAD_ATTR_GETAFFINITY_NP | ||
| 4714 | #endif | ||
| 4715 | |||
| 4716 | #if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED | ||
| 4717 | INTERCEPTOR_PTHREAD_MUTEXATTR_GET(pshared, sizeof(int)) | ||
| 4718 | #define INIT_PTHREAD_MUTEXATTR_GETPSHARED \ | ||
| 4719 | COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getpshared); | ||
| 4720 | #else | ||
| 4721 | #define INIT_PTHREAD_MUTEXATTR_GETPSHARED | ||
| 4722 | #endif | ||
| 4723 | |||
| 4724 | #if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE | ||
| 4725 | INTERCEPTOR_PTHREAD_MUTEXATTR_GET(type, sizeof(int)) | ||
| 4726 | #define INIT_PTHREAD_MUTEXATTR_GETTYPE \ | ||
| 4727 | COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_gettype); | ||
| 4728 | #else | ||
| 4729 | #define INIT_PTHREAD_MUTEXATTR_GETTYPE | ||
| 4730 | #endif | ||
| 4731 | |||
| 4732 | #if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL | ||
| 4733 | INTERCEPTOR_PTHREAD_MUTEXATTR_GET(protocol, sizeof(int)) | ||
| 4734 | #define INIT_PTHREAD_MUTEXATTR_GETPROTOCOL \ | ||
| 4735 | COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getprotocol); | ||
| 4736 | #else | ||
| 4737 | #define INIT_PTHREAD_MUTEXATTR_GETPROTOCOL | ||
| 4738 | #endif | ||
| 4739 | |||
| 4740 | #if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING | ||
| 4741 | INTERCEPTOR_PTHREAD_MUTEXATTR_GET(prioceiling, sizeof(int)) | ||
| 4742 | #define INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING \ | ||
| 4743 | COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getprioceiling); | ||
| 4744 | #else | ||
| 4745 | #define INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING | ||
| 4746 | #endif | ||
| 4747 | |||
| 4748 | #if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST | ||
| 4749 | INTERCEPTOR_PTHREAD_MUTEXATTR_GET(robust, sizeof(int)) | ||
| 4750 | #define INIT_PTHREAD_MUTEXATTR_GETROBUST \ | ||
| 4751 | COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getrobust); | ||
| 4752 | #else | ||
| 4753 | #define INIT_PTHREAD_MUTEXATTR_GETROBUST | ||
| 4754 | #endif | ||
| 4755 | |||
| 4756 | #if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP | ||
| 4757 | INTERCEPTOR_PTHREAD_MUTEXATTR_GET(robust_np, sizeof(int)) | ||
| 4758 | #define INIT_PTHREAD_MUTEXATTR_GETROBUST_NP \ | ||
| 4759 | COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getrobust_np); | ||
| 4760 | #else | ||
| 4761 | #define INIT_PTHREAD_MUTEXATTR_GETROBUST_NP | ||
| 4762 | #endif | ||
| 4763 | |||
| 4764 | #if SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED | ||
| 4765 | INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(pshared, sizeof(int)) | ||
| 4766 | #define INIT_PTHREAD_RWLOCKATTR_GETPSHARED \ | ||
| 4767 | COMMON_INTERCEPT_FUNCTION(pthread_rwlockattr_getpshared); | ||
| 4768 | #else | ||
| 4769 | #define INIT_PTHREAD_RWLOCKATTR_GETPSHARED | ||
| 4770 | #endif | ||
| 4771 | |||
| 4772 | #if SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP | ||
| 4773 | INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(kind_np, sizeof(int)) | ||
| 4774 | #define INIT_PTHREAD_RWLOCKATTR_GETKIND_NP \ | ||
| 4775 | COMMON_INTERCEPT_FUNCTION(pthread_rwlockattr_getkind_np); | ||
| 4776 | #else | ||
| 4777 | #define INIT_PTHREAD_RWLOCKATTR_GETKIND_NP | ||
| 4778 | #endif | ||
| 4779 | |||
| 4780 | #if SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED | ||
| 4781 | INTERCEPTOR_PTHREAD_CONDATTR_GET(pshared, sizeof(int)) | ||
| 4782 | #define INIT_PTHREAD_CONDATTR_GETPSHARED \ | ||
| 4783 | COMMON_INTERCEPT_FUNCTION(pthread_condattr_getpshared); | ||
| 4784 | #else | ||
| 4785 | #define INIT_PTHREAD_CONDATTR_GETPSHARED | ||
| 4786 | #endif | ||
| 4787 | |||
| 4788 | #if SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK | ||
| 4789 | INTERCEPTOR_PTHREAD_CONDATTR_GET(clock, sizeof(int)) | ||
| 4790 | #define INIT_PTHREAD_CONDATTR_GETCLOCK \ | ||
| 4791 | COMMON_INTERCEPT_FUNCTION(pthread_condattr_getclock); | ||
| 4792 | #else | ||
| 4793 | #define INIT_PTHREAD_CONDATTR_GETCLOCK | ||
| 4794 | #endif | ||
| 4795 | |||
| 4796 | #if SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED | ||
| 4797 | INTERCEPTOR_PTHREAD_BARRIERATTR_GET(pshared, sizeof(int)) // !mac !android | ||
| 4798 | #define INIT_PTHREAD_BARRIERATTR_GETPSHARED \ | ||
| 4799 | COMMON_INTERCEPT_FUNCTION(pthread_barrierattr_getpshared); | ||
| 4800 | #else | ||
| 4801 | #define INIT_PTHREAD_BARRIERATTR_GETPSHARED | ||
| 4802 | #endif | ||
| 4803 | |||
| 4804 | #if SANITIZER_INTERCEPT_TMPNAM | ||
| 4805 | INTERCEPTOR(char *, tmpnam, char *s) { | ||
| 4806 | void *ctx; | ||
| 4807 | COMMON_INTERCEPTOR_ENTER(ctx, tmpnam, s); | ||
| 4808 | char *res = REAL(tmpnam)(s); | ||
| 4809 | if (res) { | ||
| 4810 | if (s) | ||
| 4811 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4812 | // its metadata. See | ||
| 4813 | // https://github.com/google/sanitizers/issues/321. | ||
| 4814 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1); | ||
| 4815 | else | ||
| 4816 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); | ||
| 4817 | } | ||
| 4818 | return res; | ||
| 4819 | } | ||
| 4820 | #define INIT_TMPNAM COMMON_INTERCEPT_FUNCTION(tmpnam); | ||
| 4821 | #else | ||
| 4822 | #define INIT_TMPNAM | ||
| 4823 | #endif | ||
| 4824 | |||
| 4825 | #if SANITIZER_INTERCEPT_TMPNAM_R | ||
| 4826 | INTERCEPTOR(char *, tmpnam_r, char *s) { | ||
| 4827 | void *ctx; | ||
| 4828 | COMMON_INTERCEPTOR_ENTER(ctx, tmpnam_r, s); | ||
| 4829 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4830 | // its metadata. See | ||
| 4831 | // https://github.com/google/sanitizers/issues/321. | ||
| 4832 | char *res = REAL(tmpnam_r)(s); | ||
| 4833 | if (res && s) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1); | ||
| 4834 | return res; | ||
| 4835 | } | ||
| 4836 | #define INIT_TMPNAM_R COMMON_INTERCEPT_FUNCTION(tmpnam_r); | ||
| 4837 | #else | ||
| 4838 | #define INIT_TMPNAM_R | ||
| 4839 | #endif | ||
| 4840 | |||
| 4841 | #if SANITIZER_INTERCEPT_TTYNAME | ||
| 4842 | INTERCEPTOR(char *, ttyname, int fd) { | ||
| 4843 | void *ctx; | ||
| 4844 | COMMON_INTERCEPTOR_ENTER(ctx, ttyname, fd); | ||
| 4845 | char *res = REAL(ttyname)(fd); | ||
| 4846 | if (res != nullptr) | ||
| 4847 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); | ||
| 4848 | return res; | ||
| 4849 | } | ||
| 4850 | #define INIT_TTYNAME COMMON_INTERCEPT_FUNCTION(ttyname); | ||
| 4851 | #else | ||
| 4852 | #define INIT_TTYNAME | ||
| 4853 | #endif | ||
| 4854 | |||
| 4855 | #if SANITIZER_INTERCEPT_TTYNAME_R | ||
| 4856 | INTERCEPTOR(int, ttyname_r, int fd, char *name, SIZE_T namesize) { | ||
| 4857 | void *ctx; | ||
| 4858 | COMMON_INTERCEPTOR_ENTER(ctx, ttyname_r, fd, name, namesize); | ||
| 4859 | int res = REAL(ttyname_r)(fd, name, namesize); | ||
| 4860 | if (res == 0) | ||
| 4861 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 4862 | return res; | ||
| 4863 | } | ||
| 4864 | #define INIT_TTYNAME_R COMMON_INTERCEPT_FUNCTION(ttyname_r); | ||
| 4865 | #else | ||
| 4866 | #define INIT_TTYNAME_R | ||
| 4867 | #endif | ||
| 4868 | |||
| 4869 | #if SANITIZER_INTERCEPT_TEMPNAM | ||
| 4870 | INTERCEPTOR(char *, tempnam, char *dir, char *pfx) { | ||
| 4871 | void *ctx; | ||
| 4872 | COMMON_INTERCEPTOR_ENTER(ctx, tempnam, dir, pfx); | ||
| 4873 | if (dir) COMMON_INTERCEPTOR_READ_RANGE(ctx, dir, REAL(strlen)(dir) + 1); | ||
| 4874 | if (pfx) COMMON_INTERCEPTOR_READ_RANGE(ctx, pfx, REAL(strlen)(pfx) + 1); | ||
| 4875 | char *res = REAL(tempnam)(dir, pfx); | ||
| 4876 | if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); | ||
| 4877 | return res; | ||
| 4878 | } | ||
| 4879 | #define INIT_TEMPNAM COMMON_INTERCEPT_FUNCTION(tempnam); | ||
| 4880 | #else | ||
| 4881 | #define INIT_TEMPNAM | ||
| 4882 | #endif | ||
| 4883 | |||
| 4884 | #if SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP && !SANITIZER_NETBSD | ||
| 4885 | INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name) { | ||
| 4886 | void *ctx; | ||
| 4887 | COMMON_INTERCEPTOR_ENTER(ctx, pthread_setname_np, thread, name); | ||
| 4888 | COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); | ||
| 4889 | COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name); | ||
| 4890 | return REAL(pthread_setname_np)(thread, name); | ||
| 4891 | } | ||
| 4892 | #define INIT_PTHREAD_SETNAME_NP COMMON_INTERCEPT_FUNCTION(pthread_setname_np); | ||
| 4893 | #elif SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP && SANITIZER_NETBSD | ||
| 4894 | INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name, void *arg) { | ||
| 4895 | void *ctx; | ||
| 4896 | char newname[32]; // PTHREAD_MAX_NAMELEN_NP=32 | ||
| 4897 | COMMON_INTERCEPTOR_ENTER(ctx, pthread_setname_np, thread, name, arg); | ||
| 4898 | COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); | ||
| 4899 | internal_snprintf(newname, sizeof(newname), name, arg); | ||
| 4900 | COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, newname); | ||
| 4901 | return REAL(pthread_setname_np)(thread, name, arg); | ||
| 4902 | } | ||
| 4903 | #define INIT_PTHREAD_SETNAME_NP COMMON_INTERCEPT_FUNCTION(pthread_setname_np); | ||
| 4904 | #else | ||
| 4905 | #define INIT_PTHREAD_SETNAME_NP | ||
| 4906 | #endif | ||
| 4907 | |||
| 4908 | #if SANITIZER_INTERCEPT_PTHREAD_GETNAME_NP | ||
| 4909 | INTERCEPTOR(int, pthread_getname_np, uptr thread, char *name, SIZE_T len) { | ||
| 4910 | void *ctx; | ||
| 4911 | COMMON_INTERCEPTOR_ENTER(ctx, pthread_getname_np, thread, name, len); | ||
| 4912 | int res = REAL(pthread_getname_np)(thread, name, len); | ||
| 4913 | if (!res) | ||
| 4914 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, internal_strnlen(name, len) + 1); | ||
| 4915 | return res; | ||
| 4916 | } | ||
| 4917 | #define INIT_PTHREAD_GETNAME_NP COMMON_INTERCEPT_FUNCTION(pthread_getname_np); | ||
| 4918 | #else | ||
| 4919 | #define INIT_PTHREAD_GETNAME_NP | ||
| 4920 | #endif | ||
| 4921 | |||
| 4922 | #if SANITIZER_INTERCEPT_SINCOS | ||
| 4923 | INTERCEPTOR(void, sincos, double x, double *sin, double *cos) { | ||
| 4924 | void *ctx; | ||
| 4925 | COMMON_INTERCEPTOR_ENTER(ctx, sincos, x, sin, cos); | ||
| 4926 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4927 | // its metadata. See | ||
| 4928 | // https://github.com/google/sanitizers/issues/321. | ||
| 4929 | REAL(sincos)(x, sin, cos); | ||
| 4930 | if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin)); | ||
| 4931 | if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos)); | ||
| 4932 | } | ||
| 4933 | INTERCEPTOR(void, sincosf, float x, float *sin, float *cos) { | ||
| 4934 | void *ctx; | ||
| 4935 | COMMON_INTERCEPTOR_ENTER(ctx, sincosf, x, sin, cos); | ||
| 4936 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4937 | // its metadata. See | ||
| 4938 | // https://github.com/google/sanitizers/issues/321. | ||
| 4939 | REAL(sincosf)(x, sin, cos); | ||
| 4940 | if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin)); | ||
| 4941 | if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos)); | ||
| 4942 | } | ||
| 4943 | INTERCEPTOR(void, sincosl, long double x, long double *sin, long double *cos) { | ||
| 4944 | void *ctx; | ||
| 4945 | COMMON_INTERCEPTOR_ENTER(ctx, sincosl, x, sin, cos); | ||
| 4946 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4947 | // its metadata. See | ||
| 4948 | // https://github.com/google/sanitizers/issues/321. | ||
| 4949 | REAL(sincosl)(x, sin, cos); | ||
| 4950 | if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin)); | ||
| 4951 | if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos)); | ||
| 4952 | } | ||
| 4953 | #define INIT_SINCOS \ | ||
| 4954 | COMMON_INTERCEPT_FUNCTION(sincos); \ | ||
| 4955 | COMMON_INTERCEPT_FUNCTION(sincosf); \ | ||
| 4956 | COMMON_INTERCEPT_FUNCTION_LDBL(sincosl); | ||
| 4957 | #else | ||
| 4958 | #define INIT_SINCOS | ||
| 4959 | #endif | ||
| 4960 | |||
| 4961 | #if SANITIZER_INTERCEPT_REMQUO | ||
| 4962 | INTERCEPTOR(double, remquo, double x, double y, int *quo) { | ||
| 4963 | void *ctx; | ||
| 4964 | COMMON_INTERCEPTOR_ENTER(ctx, remquo, x, y, quo); | ||
| 4965 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4966 | // its metadata. See | ||
| 4967 | // https://github.com/google/sanitizers/issues/321. | ||
| 4968 | double res = REAL(remquo)(x, y, quo); | ||
| 4969 | if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo)); | ||
| 4970 | return res; | ||
| 4971 | } | ||
| 4972 | INTERCEPTOR(float, remquof, float x, float y, int *quo) { | ||
| 4973 | void *ctx; | ||
| 4974 | COMMON_INTERCEPTOR_ENTER(ctx, remquof, x, y, quo); | ||
| 4975 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4976 | // its metadata. See | ||
| 4977 | // https://github.com/google/sanitizers/issues/321. | ||
| 4978 | float res = REAL(remquof)(x, y, quo); | ||
| 4979 | if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo)); | ||
| 4980 | return res; | ||
| 4981 | } | ||
| 4982 | #define INIT_REMQUO \ | ||
| 4983 | COMMON_INTERCEPT_FUNCTION(remquo); \ | ||
| 4984 | COMMON_INTERCEPT_FUNCTION(remquof); | ||
| 4985 | #else | ||
| 4986 | #define INIT_REMQUO | ||
| 4987 | #endif | ||
| 4988 | |||
| 4989 | #if SANITIZER_INTERCEPT_REMQUOL | ||
| 4990 | INTERCEPTOR(long double, remquol, long double x, long double y, int *quo) { | ||
| 4991 | void *ctx; | ||
| 4992 | COMMON_INTERCEPTOR_ENTER(ctx, remquol, x, y, quo); | ||
| 4993 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 4994 | // its metadata. See | ||
| 4995 | // https://github.com/google/sanitizers/issues/321. | ||
| 4996 | long double res = REAL(remquol)(x, y, quo); | ||
| 4997 | if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo)); | ||
| 4998 | return res; | ||
| 4999 | } | ||
| 5000 | #define INIT_REMQUOL \ | ||
| 5001 | COMMON_INTERCEPT_FUNCTION_LDBL(remquol); | ||
| 5002 | #else | ||
| 5003 | #define INIT_REMQUOL | ||
| 5004 | #endif | ||
| 5005 | |||
| 5006 | #if SANITIZER_INTERCEPT_LGAMMA | ||
| 5007 | extern int signgam; | ||
| 5008 | INTERCEPTOR(double, lgamma, double x) { | ||
| 5009 | void *ctx; | ||
| 5010 | COMMON_INTERCEPTOR_ENTER(ctx, lgamma, x); | ||
| 5011 | double res = REAL(lgamma)(x); | ||
| 5012 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam)); | ||
| 5013 | return res; | ||
| 5014 | } | ||
| 5015 | INTERCEPTOR(float, lgammaf, float x) { | ||
| 5016 | void *ctx; | ||
| 5017 | COMMON_INTERCEPTOR_ENTER(ctx, lgammaf, x); | ||
| 5018 | float res = REAL(lgammaf)(x); | ||
| 5019 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam)); | ||
| 5020 | return res; | ||
| 5021 | } | ||
| 5022 | #define INIT_LGAMMA \ | ||
| 5023 | COMMON_INTERCEPT_FUNCTION(lgamma); \ | ||
| 5024 | COMMON_INTERCEPT_FUNCTION(lgammaf); | ||
| 5025 | #else | ||
| 5026 | #define INIT_LGAMMA | ||
| 5027 | #endif | ||
| 5028 | |||
| 5029 | #if SANITIZER_INTERCEPT_LGAMMAL | ||
| 5030 | INTERCEPTOR(long double, lgammal, long double x) { | ||
| 5031 | void *ctx; | ||
| 5032 | COMMON_INTERCEPTOR_ENTER(ctx, lgammal, x); | ||
| 5033 | long double res = REAL(lgammal)(x); | ||
| 5034 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam)); | ||
| 5035 | return res; | ||
| 5036 | } | ||
| 5037 | #define INIT_LGAMMAL \ | ||
| 5038 | COMMON_INTERCEPT_FUNCTION_LDBL(lgammal); | ||
| 5039 | #else | ||
| 5040 | #define INIT_LGAMMAL | ||
| 5041 | #endif | ||
| 5042 | |||
| 5043 | #if SANITIZER_INTERCEPT_LGAMMA_R | ||
| 5044 | INTERCEPTOR(double, lgamma_r, double x, int *signp) { | ||
| 5045 | void *ctx; | ||
| 5046 | COMMON_INTERCEPTOR_ENTER(ctx, lgamma_r, x, signp); | ||
| 5047 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5048 | // its metadata. See | ||
| 5049 | // https://github.com/google/sanitizers/issues/321. | ||
| 5050 | double res = REAL(lgamma_r)(x, signp); | ||
| 5051 | if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp)); | ||
| 5052 | return res; | ||
| 5053 | } | ||
| 5054 | INTERCEPTOR(float, lgammaf_r, float x, int *signp) { | ||
| 5055 | void *ctx; | ||
| 5056 | COMMON_INTERCEPTOR_ENTER(ctx, lgammaf_r, x, signp); | ||
| 5057 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5058 | // its metadata. See | ||
| 5059 | // https://github.com/google/sanitizers/issues/321. | ||
| 5060 | float res = REAL(lgammaf_r)(x, signp); | ||
| 5061 | if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp)); | ||
| 5062 | return res; | ||
| 5063 | } | ||
| 5064 | #define INIT_LGAMMA_R \ | ||
| 5065 | COMMON_INTERCEPT_FUNCTION(lgamma_r); \ | ||
| 5066 | COMMON_INTERCEPT_FUNCTION(lgammaf_r); | ||
| 5067 | #else | ||
| 5068 | #define INIT_LGAMMA_R | ||
| 5069 | #endif | ||
| 5070 | |||
| 5071 | #if SANITIZER_INTERCEPT_LGAMMAL_R | ||
| 5072 | INTERCEPTOR(long double, lgammal_r, long double x, int *signp) { | ||
| 5073 | void *ctx; | ||
| 5074 | COMMON_INTERCEPTOR_ENTER(ctx, lgammal_r, x, signp); | ||
| 5075 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5076 | // its metadata. See | ||
| 5077 | // https://github.com/google/sanitizers/issues/321. | ||
| 5078 | long double res = REAL(lgammal_r)(x, signp); | ||
| 5079 | if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp)); | ||
| 5080 | return res; | ||
| 5081 | } | ||
| 5082 | #define INIT_LGAMMAL_R COMMON_INTERCEPT_FUNCTION_LDBL(lgammal_r); | ||
| 5083 | #else | ||
| 5084 | #define INIT_LGAMMAL_R | ||
| 5085 | #endif | ||
| 5086 | |||
| 5087 | #if SANITIZER_INTERCEPT_DRAND48_R | ||
| 5088 | INTERCEPTOR(int, drand48_r, void *buffer, double *result) { | ||
| 5089 | void *ctx; | ||
| 5090 | COMMON_INTERCEPTOR_ENTER(ctx, drand48_r, buffer, result); | ||
| 5091 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5092 | // its metadata. See | ||
| 5093 | // https://github.com/google/sanitizers/issues/321. | ||
| 5094 | int res = REAL(drand48_r)(buffer, result); | ||
| 5095 | if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); | ||
| 5096 | return res; | ||
| 5097 | } | ||
| 5098 | INTERCEPTOR(int, lrand48_r, void *buffer, long *result) { | ||
| 5099 | void *ctx; | ||
| 5100 | COMMON_INTERCEPTOR_ENTER(ctx, lrand48_r, buffer, result); | ||
| 5101 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5102 | // its metadata. See | ||
| 5103 | // https://github.com/google/sanitizers/issues/321. | ||
| 5104 | int res = REAL(lrand48_r)(buffer, result); | ||
| 5105 | if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); | ||
| 5106 | return res; | ||
| 5107 | } | ||
| 5108 | #define INIT_DRAND48_R \ | ||
| 5109 | COMMON_INTERCEPT_FUNCTION(drand48_r); \ | ||
| 5110 | COMMON_INTERCEPT_FUNCTION(lrand48_r); | ||
| 5111 | #else | ||
| 5112 | #define INIT_DRAND48_R | ||
| 5113 | #endif | ||
| 5114 | |||
| 5115 | #if SANITIZER_INTERCEPT_RAND_R | ||
| 5116 | INTERCEPTOR(int, rand_r, unsigned *seedp) { | ||
| 5117 | void *ctx; | ||
| 5118 | COMMON_INTERCEPTOR_ENTER(ctx, rand_r, seedp); | ||
| 5119 | COMMON_INTERCEPTOR_READ_RANGE(ctx, seedp, sizeof(*seedp)); | ||
| 5120 | return REAL(rand_r)(seedp); | ||
| 5121 | } | ||
| 5122 | #define INIT_RAND_R COMMON_INTERCEPT_FUNCTION(rand_r); | ||
| 5123 | #else | ||
| 5124 | #define INIT_RAND_R | ||
| 5125 | #endif | ||
| 5126 | |||
| 5127 | #if SANITIZER_INTERCEPT_GETLINE | ||
| 5128 | INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) { | ||
| 5129 | void *ctx; | ||
| 5130 | COMMON_INTERCEPTOR_ENTER(ctx, getline, lineptr, n, stream); | ||
| 5131 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5132 | // its metadata. See | ||
| 5133 | // https://github.com/google/sanitizers/issues/321. | ||
| 5134 | SSIZE_T res = REAL(getline)(lineptr, n, stream); | ||
| 5135 | if (res > 0) { | ||
| 5136 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr)); | ||
| 5137 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); | ||
| 5138 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *lineptr, res + 1); | ||
| 5139 | } | ||
| 5140 | return res; | ||
| 5141 | } | ||
| 5142 | |||
| 5143 | // FIXME: under ASan the call below may write to freed memory and corrupt its | ||
| 5144 | // metadata. See | ||
| 5145 | // https://github.com/google/sanitizers/issues/321. | ||
| 5146 | #define GETDELIM_INTERCEPTOR_IMPL(vname) \ | ||
| 5147 | { \ | ||
| 5148 | void *ctx; \ | ||
| 5149 | COMMON_INTERCEPTOR_ENTER(ctx, vname, lineptr, n, delim, stream); \ | ||
| 5150 | SSIZE_T res = REAL(vname)(lineptr, n, delim, stream); \ | ||
| 5151 | if (res > 0) { \ | ||
| 5152 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr)); \ | ||
| 5153 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); \ | ||
| 5154 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *lineptr, res + 1); \ | ||
| 5155 | } \ | ||
| 5156 | return res; \ | ||
| 5157 | } | ||
| 5158 | |||
| 5159 | INTERCEPTOR(SSIZE_T, __getdelim, char **lineptr, SIZE_T *n, int delim, | ||
| 5160 | void *stream) | ||
| 5161 | GETDELIM_INTERCEPTOR_IMPL(__getdelim) | ||
| 5162 | |||
| 5163 | // There's no __getdelim() on FreeBSD so we supply the getdelim() interceptor | ||
| 5164 | // with its own body. | ||
| 5165 | INTERCEPTOR(SSIZE_T, getdelim, char **lineptr, SIZE_T *n, int delim, | ||
| 5166 | void *stream) | ||
| 5167 | GETDELIM_INTERCEPTOR_IMPL(getdelim) | ||
| 5168 | |||
| 5169 | #define INIT_GETLINE \ | ||
| 5170 | COMMON_INTERCEPT_FUNCTION(getline); \ | ||
| 5171 | COMMON_INTERCEPT_FUNCTION(__getdelim); \ | ||
| 5172 | COMMON_INTERCEPT_FUNCTION(getdelim); | ||
| 5173 | #else | ||
| 5174 | #define INIT_GETLINE | ||
| 5175 | #endif | ||
| 5176 | |||
| 5177 | #if SANITIZER_INTERCEPT_ICONV | ||
| 5178 | INTERCEPTOR(SIZE_T, iconv, void *cd, char **inbuf, SIZE_T *inbytesleft, | ||
| 5179 | char **outbuf, SIZE_T *outbytesleft) { | ||
| 5180 | void *ctx; | ||
| 5181 | COMMON_INTERCEPTOR_ENTER(ctx, iconv, cd, inbuf, inbytesleft, outbuf, | ||
| 5182 | outbytesleft); | ||
| 5183 | if (inbytesleft) | ||
| 5184 | COMMON_INTERCEPTOR_READ_RANGE(ctx, inbytesleft, sizeof(*inbytesleft)); | ||
| 5185 | if (inbuf && inbytesleft) | ||
| 5186 | COMMON_INTERCEPTOR_READ_RANGE(ctx, *inbuf, *inbytesleft); | ||
| 5187 | if (outbytesleft) | ||
| 5188 | COMMON_INTERCEPTOR_READ_RANGE(ctx, outbytesleft, sizeof(*outbytesleft)); | ||
| 5189 | void *outbuf_orig = outbuf ? *outbuf : nullptr; | ||
| 5190 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5191 | // its metadata. See | ||
| 5192 | // https://github.com/google/sanitizers/issues/321. | ||
| 5193 | SIZE_T res = REAL(iconv)(cd, inbuf, inbytesleft, outbuf, outbytesleft); | ||
| 5194 | if (outbuf && *outbuf > outbuf_orig) { | ||
| 5195 | SIZE_T sz = (char *)*outbuf - (char *)outbuf_orig; | ||
| 5196 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, outbuf_orig, sz); | ||
| 5197 | } | ||
| 5198 | return res; | ||
| 5199 | } | ||
| 5200 | #define INIT_ICONV COMMON_INTERCEPT_FUNCTION(iconv); | ||
| 5201 | #else | ||
| 5202 | #define INIT_ICONV | ||
| 5203 | #endif | ||
| 5204 | |||
| 5205 | #if SANITIZER_INTERCEPT_TIMES | ||
| 5206 | INTERCEPTOR(__sanitizer_clock_t, times, void *tms) { | ||
| 5207 | void *ctx; | ||
| 5208 | COMMON_INTERCEPTOR_ENTER(ctx, times, tms); | ||
| 5209 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5210 | // its metadata. See | ||
| 5211 | // https://github.com/google/sanitizers/issues/321. | ||
| 5212 | __sanitizer_clock_t res = REAL(times)(tms); | ||
| 5213 | if (res != (__sanitizer_clock_t)-1 && tms) | ||
| 5214 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tms, struct_tms_sz); | ||
| 5215 | return res; | ||
| 5216 | } | ||
| 5217 | #define INIT_TIMES COMMON_INTERCEPT_FUNCTION(times); | ||
| 5218 | #else | ||
| 5219 | #define INIT_TIMES | ||
| 5220 | #endif | ||
| 5221 | |||
| 5222 | #if SANITIZER_INTERCEPT_TLS_GET_ADDR | ||
| 5223 | #if !SANITIZER_S390 | ||
| 5224 | #define INIT_TLS_GET_ADDR COMMON_INTERCEPT_FUNCTION(__tls_get_addr) | ||
| 5225 | // If you see any crashes around this functions, there are 2 known issues with | ||
| 5226 | // it: 1. __tls_get_addr can be called with mis-aligned stack due to: | ||
| 5227 | // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066 | ||
| 5228 | // 2. It can be called recursively if sanitizer code uses __tls_get_addr | ||
| 5229 | // to access thread local variables (it should not happen normally, | ||
| 5230 | // because sanitizers use initial-exec tls model). | ||
| 5231 | INTERCEPTOR(void *, __tls_get_addr, void *arg) { | ||
| 5232 | void *ctx; | ||
| 5233 | COMMON_INTERCEPTOR_ENTER(ctx, __tls_get_addr, arg); | ||
| 5234 | void *res = REAL(__tls_get_addr)(arg); | ||
| 5235 | uptr tls_begin, tls_end; | ||
| 5236 | COMMON_INTERCEPTOR_GET_TLS_RANGE(&tls_begin, &tls_end); | ||
| 5237 | DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, tls_begin, tls_end); | ||
| 5238 | if (dtv) { | ||
| 5239 | // New DTLS block has been allocated. | ||
| 5240 | COMMON_INTERCEPTOR_INITIALIZE_RANGE((void *)dtv->beg, dtv->size); | ||
| 5241 | } | ||
| 5242 | return res; | ||
| 5243 | } | ||
| 5244 | #if SANITIZER_PPC | ||
| 5245 | // On PowerPC, we also need to intercept __tls_get_addr_opt, which has | ||
| 5246 | // mostly the same semantics as __tls_get_addr, but its presence enables | ||
| 5247 | // some optimizations in linker (which are safe to ignore here). | ||
| 5248 | extern "C" __attribute__((alias("__interceptor___tls_get_addr"), | ||
| 5249 | visibility("default"))) | ||
| 5250 | void *__tls_get_addr_opt(void *arg); | ||
| 5251 | #endif | ||
| 5252 | #else // SANITIZER_S390 | ||
| 5253 | // On s390, we have to intercept two functions here: | ||
| 5254 | // - __tls_get_addr_internal, which is a glibc-internal function that is like | ||
| 5255 | // the usual __tls_get_addr, but returns a TP-relative offset instead of | ||
| 5256 | // a proper pointer. It is used by dlsym for TLS symbols. | ||
| 5257 | // - __tls_get_offset, which is like the above, but also takes a GOT-relative | ||
| 5258 | // descriptor offset as an argument instead of a pointer. GOT address | ||
| 5259 | // is passed in r12, so it's necessary to write it in assembly. This is | ||
| 5260 | // the function used by the compiler. | ||
| 5261 | extern "C" uptr __tls_get_offset_wrapper(void *arg, uptr (*fn)(void *arg)); | ||
| 5262 | #define INIT_TLS_GET_ADDR COMMON_INTERCEPT_FUNCTION(__tls_get_offset) | ||
| 5263 | DEFINE_REAL(uptr, __tls_get_offset, void *arg) | ||
| 5264 | extern "C" uptr __tls_get_offset(void *arg); | ||
| 5265 | extern "C" uptr __interceptor___tls_get_offset(void *arg); | ||
| 5266 | INTERCEPTOR(uptr, __tls_get_addr_internal, void *arg) { | ||
| 5267 | void *ctx; | ||
| 5268 | COMMON_INTERCEPTOR_ENTER(ctx, __tls_get_addr_internal, arg); | ||
| 5269 | uptr res = __tls_get_offset_wrapper(arg, REAL(__tls_get_offset)); | ||
| 5270 | uptr tp = reinterpret_cast<uptr>(__builtin_thread_pointer()); | ||
| 5271 | void *ptr = reinterpret_cast<void *>(res + tp); | ||
| 5272 | uptr tls_begin, tls_end; | ||
| 5273 | COMMON_INTERCEPTOR_GET_TLS_RANGE(&tls_begin, &tls_end); | ||
| 5274 | DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, ptr, tls_begin, tls_end); | ||
| 5275 | if (dtv) { | ||
| 5276 | // New DTLS block has been allocated. | ||
| 5277 | COMMON_INTERCEPTOR_INITIALIZE_RANGE((void *)dtv->beg, dtv->size); | ||
| 5278 | } | ||
| 5279 | return res; | ||
| 5280 | } | ||
| 5281 | // We need a hidden symbol aliasing the above, so that we can jump | ||
| 5282 | // directly to it from the assembly below. | ||
| 5283 | extern "C" __attribute__((alias("__interceptor___tls_get_addr_internal"), | ||
| 5284 | visibility("hidden"))) | ||
| 5285 | uptr __tls_get_addr_hidden(void *arg); | ||
| 5286 | // Now carefully intercept __tls_get_offset. | ||
| 5287 | asm( | ||
| 5288 | ".text\n" | ||
| 5289 | // The __intercept_ version has to exist, so that gen_dynamic_list.py | ||
| 5290 | // exports our symbol. | ||
| 5291 | ".weak __tls_get_offset\n" | ||
| 5292 | ".type __tls_get_offset, @function\n" | ||
| 5293 | "__tls_get_offset:\n" | ||
| 5294 | ".global __interceptor___tls_get_offset\n" | ||
| 5295 | ".type __interceptor___tls_get_offset, @function\n" | ||
| 5296 | "__interceptor___tls_get_offset:\n" | ||
| 5297 | #ifdef __s390x__ | ||
| 5298 | "la %r2, 0(%r2,%r12)\n" | ||
| 5299 | "jg __tls_get_addr_hidden\n" | ||
| 5300 | #else | ||
| 5301 | "basr %r3,0\n" | ||
| 5302 | "0: la %r2,0(%r2,%r12)\n" | ||
| 5303 | "l %r4,1f-0b(%r3)\n" | ||
| 5304 | "b 0(%r4,%r3)\n" | ||
| 5305 | "1: .long __tls_get_addr_hidden - 0b\n" | ||
| 5306 | #endif | ||
| 5307 | ".size __interceptor___tls_get_offset, .-__interceptor___tls_get_offset\n" | ||
| 5308 | // Assembly wrapper to call REAL(__tls_get_offset)(arg) | ||
| 5309 | ".type __tls_get_offset_wrapper, @function\n" | ||
| 5310 | "__tls_get_offset_wrapper:\n" | ||
| 5311 | #ifdef __s390x__ | ||
| 5312 | "sgr %r2,%r12\n" | ||
| 5313 | #else | ||
| 5314 | "sr %r2,%r12\n" | ||
| 5315 | #endif | ||
| 5316 | "br %r3\n" | ||
| 5317 | ".size __tls_get_offset_wrapper, .-__tls_get_offset_wrapper\n" | ||
| 5318 | ); | ||
| 5319 | #endif // SANITIZER_S390 | ||
| 5320 | #else | ||
| 5321 | #define INIT_TLS_GET_ADDR | ||
| 5322 | #endif | ||
| 5323 | |||
| 5324 | #if SANITIZER_INTERCEPT_LISTXATTR | ||
| 5325 | INTERCEPTOR(SSIZE_T, listxattr, const char *path, char *list, SIZE_T size) { | ||
| 5326 | void *ctx; | ||
| 5327 | COMMON_INTERCEPTOR_ENTER(ctx, listxattr, path, list, size); | ||
| 5328 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 5329 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5330 | // its metadata. See | ||
| 5331 | // https://github.com/google/sanitizers/issues/321. | ||
| 5332 | SSIZE_T res = REAL(listxattr)(path, list, size); | ||
| 5333 | // Here and below, size == 0 is a special case where nothing is written to the | ||
| 5334 | // buffer, and res contains the desired buffer size. | ||
| 5335 | if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res); | ||
| 5336 | return res; | ||
| 5337 | } | ||
| 5338 | INTERCEPTOR(SSIZE_T, llistxattr, const char *path, char *list, SIZE_T size) { | ||
| 5339 | void *ctx; | ||
| 5340 | COMMON_INTERCEPTOR_ENTER(ctx, llistxattr, path, list, size); | ||
| 5341 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 5342 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5343 | // its metadata. See | ||
| 5344 | // https://github.com/google/sanitizers/issues/321. | ||
| 5345 | SSIZE_T res = REAL(llistxattr)(path, list, size); | ||
| 5346 | if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res); | ||
| 5347 | return res; | ||
| 5348 | } | ||
| 5349 | INTERCEPTOR(SSIZE_T, flistxattr, int fd, char *list, SIZE_T size) { | ||
| 5350 | void *ctx; | ||
| 5351 | COMMON_INTERCEPTOR_ENTER(ctx, flistxattr, fd, list, size); | ||
| 5352 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5353 | // its metadata. See | ||
| 5354 | // https://github.com/google/sanitizers/issues/321. | ||
| 5355 | SSIZE_T res = REAL(flistxattr)(fd, list, size); | ||
| 5356 | if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res); | ||
| 5357 | return res; | ||
| 5358 | } | ||
| 5359 | #define INIT_LISTXATTR \ | ||
| 5360 | COMMON_INTERCEPT_FUNCTION(listxattr); \ | ||
| 5361 | COMMON_INTERCEPT_FUNCTION(llistxattr); \ | ||
| 5362 | COMMON_INTERCEPT_FUNCTION(flistxattr); | ||
| 5363 | #else | ||
| 5364 | #define INIT_LISTXATTR | ||
| 5365 | #endif | ||
| 5366 | |||
| 5367 | #if SANITIZER_INTERCEPT_GETXATTR | ||
| 5368 | INTERCEPTOR(SSIZE_T, getxattr, const char *path, const char *name, char *value, | ||
| 5369 | SIZE_T size) { | ||
| 5370 | void *ctx; | ||
| 5371 | COMMON_INTERCEPTOR_ENTER(ctx, getxattr, path, name, value, size); | ||
| 5372 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 5373 | if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 5374 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5375 | // its metadata. See | ||
| 5376 | // https://github.com/google/sanitizers/issues/321. | ||
| 5377 | SSIZE_T res = REAL(getxattr)(path, name, value, size); | ||
| 5378 | if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res); | ||
| 5379 | return res; | ||
| 5380 | } | ||
| 5381 | INTERCEPTOR(SSIZE_T, lgetxattr, const char *path, const char *name, char *value, | ||
| 5382 | SIZE_T size) { | ||
| 5383 | void *ctx; | ||
| 5384 | COMMON_INTERCEPTOR_ENTER(ctx, lgetxattr, path, name, value, size); | ||
| 5385 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 5386 | if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 5387 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5388 | // its metadata. See | ||
| 5389 | // https://github.com/google/sanitizers/issues/321. | ||
| 5390 | SSIZE_T res = REAL(lgetxattr)(path, name, value, size); | ||
| 5391 | if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res); | ||
| 5392 | return res; | ||
| 5393 | } | ||
| 5394 | INTERCEPTOR(SSIZE_T, fgetxattr, int fd, const char *name, char *value, | ||
| 5395 | SIZE_T size) { | ||
| 5396 | void *ctx; | ||
| 5397 | COMMON_INTERCEPTOR_ENTER(ctx, fgetxattr, fd, name, value, size); | ||
| 5398 | if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 5399 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5400 | // its metadata. See | ||
| 5401 | // https://github.com/google/sanitizers/issues/321. | ||
| 5402 | SSIZE_T res = REAL(fgetxattr)(fd, name, value, size); | ||
| 5403 | if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res); | ||
| 5404 | return res; | ||
| 5405 | } | ||
| 5406 | #define INIT_GETXATTR \ | ||
| 5407 | COMMON_INTERCEPT_FUNCTION(getxattr); \ | ||
| 5408 | COMMON_INTERCEPT_FUNCTION(lgetxattr); \ | ||
| 5409 | COMMON_INTERCEPT_FUNCTION(fgetxattr); | ||
| 5410 | #else | ||
| 5411 | #define INIT_GETXATTR | ||
| 5412 | #endif | ||
| 5413 | |||
| 5414 | #if SANITIZER_INTERCEPT_GETRESID | ||
| 5415 | INTERCEPTOR(int, getresuid, void *ruid, void *euid, void *suid) { | ||
| 5416 | void *ctx; | ||
| 5417 | COMMON_INTERCEPTOR_ENTER(ctx, getresuid, ruid, euid, suid); | ||
| 5418 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5419 | // its metadata. See | ||
| 5420 | // https://github.com/google/sanitizers/issues/321. | ||
| 5421 | int res = REAL(getresuid)(ruid, euid, suid); | ||
| 5422 | if (res >= 0) { | ||
| 5423 | if (ruid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ruid, uid_t_sz); | ||
| 5424 | if (euid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, euid, uid_t_sz); | ||
| 5425 | if (suid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, suid, uid_t_sz); | ||
| 5426 | } | ||
| 5427 | return res; | ||
| 5428 | } | ||
| 5429 | INTERCEPTOR(int, getresgid, void *rgid, void *egid, void *sgid) { | ||
| 5430 | void *ctx; | ||
| 5431 | COMMON_INTERCEPTOR_ENTER(ctx, getresgid, rgid, egid, sgid); | ||
| 5432 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5433 | // its metadata. See | ||
| 5434 | // https://github.com/google/sanitizers/issues/321. | ||
| 5435 | int res = REAL(getresgid)(rgid, egid, sgid); | ||
| 5436 | if (res >= 0) { | ||
| 5437 | if (rgid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rgid, gid_t_sz); | ||
| 5438 | if (egid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, egid, gid_t_sz); | ||
| 5439 | if (sgid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sgid, gid_t_sz); | ||
| 5440 | } | ||
| 5441 | return res; | ||
| 5442 | } | ||
| 5443 | #define INIT_GETRESID \ | ||
| 5444 | COMMON_INTERCEPT_FUNCTION(getresuid); \ | ||
| 5445 | COMMON_INTERCEPT_FUNCTION(getresgid); | ||
| 5446 | #else | ||
| 5447 | #define INIT_GETRESID | ||
| 5448 | #endif | ||
| 5449 | |||
| 5450 | #if SANITIZER_INTERCEPT_GETIFADDRS | ||
| 5451 | // As long as getifaddrs()/freeifaddrs() use calloc()/free(), we don't need to | ||
| 5452 | // intercept freeifaddrs(). If that ceases to be the case, we might need to | ||
| 5453 | // intercept it to poison the memory again. | ||
| 5454 | INTERCEPTOR(int, getifaddrs, __sanitizer_ifaddrs **ifap) { | ||
| 5455 | void *ctx; | ||
| 5456 | COMMON_INTERCEPTOR_ENTER(ctx, getifaddrs, ifap); | ||
| 5457 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5458 | // its metadata. See | ||
| 5459 | // https://github.com/google/sanitizers/issues/321. | ||
| 5460 | int res = REAL(getifaddrs)(ifap); | ||
| 5461 | if (res == 0 && ifap) { | ||
| 5462 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifap, sizeof(void *)); | ||
| 5463 | __sanitizer_ifaddrs *p = *ifap; | ||
| 5464 | while (p) { | ||
| 5465 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(__sanitizer_ifaddrs)); | ||
| 5466 | if (p->ifa_name) | ||
| 5467 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_name, | ||
| 5468 | REAL(strlen)(p->ifa_name) + 1); | ||
| 5469 | if (p->ifa_addr) | ||
| 5470 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_addr, struct_sockaddr_sz); | ||
| 5471 | if (p->ifa_netmask) | ||
| 5472 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_netmask, struct_sockaddr_sz); | ||
| 5473 | // On Linux this is a union, but the other member also points to a | ||
| 5474 | // struct sockaddr, so the following is sufficient. | ||
| 5475 | if (p->ifa_dstaddr) | ||
| 5476 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_dstaddr, struct_sockaddr_sz); | ||
| 5477 | // FIXME(smatveev): Unpoison p->ifa_data as well. | ||
| 5478 | p = p->ifa_next; | ||
| 5479 | } | ||
| 5480 | } | ||
| 5481 | return res; | ||
| 5482 | } | ||
| 5483 | #define INIT_GETIFADDRS \ | ||
| 5484 | COMMON_INTERCEPT_FUNCTION(getifaddrs); | ||
| 5485 | #else | ||
| 5486 | #define INIT_GETIFADDRS | ||
| 5487 | #endif | ||
| 5488 | |||
| 5489 | #if SANITIZER_INTERCEPT_IF_INDEXTONAME | ||
| 5490 | INTERCEPTOR(char *, if_indextoname, unsigned int ifindex, char* ifname) { | ||
| 5491 | void *ctx; | ||
| 5492 | COMMON_INTERCEPTOR_ENTER(ctx, if_indextoname, ifindex, ifname); | ||
| 5493 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5494 | // its metadata. See | ||
| 5495 | // https://github.com/google/sanitizers/issues/321. | ||
| 5496 | char *res = REAL(if_indextoname)(ifindex, ifname); | ||
| 5497 | if (res && ifname) | ||
| 5498 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifname, REAL(strlen)(ifname) + 1); | ||
| 5499 | return res; | ||
| 5500 | } | ||
| 5501 | INTERCEPTOR(unsigned int, if_nametoindex, const char* ifname) { | ||
| 5502 | void *ctx; | ||
| 5503 | COMMON_INTERCEPTOR_ENTER(ctx, if_nametoindex, ifname); | ||
| 5504 | if (ifname) | ||
| 5505 | COMMON_INTERCEPTOR_READ_RANGE(ctx, ifname, REAL(strlen)(ifname) + 1); | ||
| 5506 | return REAL(if_nametoindex)(ifname); | ||
| 5507 | } | ||
| 5508 | #define INIT_IF_INDEXTONAME \ | ||
| 5509 | COMMON_INTERCEPT_FUNCTION(if_indextoname); \ | ||
| 5510 | COMMON_INTERCEPT_FUNCTION(if_nametoindex); | ||
| 5511 | #else | ||
| 5512 | #define INIT_IF_INDEXTONAME | ||
| 5513 | #endif | ||
| 5514 | |||
| 5515 | #if SANITIZER_INTERCEPT_CAPGET | ||
| 5516 | INTERCEPTOR(int, capget, void *hdrp, void *datap) { | ||
| 5517 | void *ctx; | ||
| 5518 | COMMON_INTERCEPTOR_ENTER(ctx, capget, hdrp, datap); | ||
| 5519 | if (hdrp) | ||
| 5520 | COMMON_INTERCEPTOR_READ_RANGE(ctx, hdrp, __user_cap_header_struct_sz); | ||
| 5521 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5522 | // its metadata. See | ||
| 5523 | // https://github.com/google/sanitizers/issues/321. | ||
| 5524 | int res = REAL(capget)(hdrp, datap); | ||
| 5525 | if (res == 0 && datap) | ||
| 5526 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datap, __user_cap_data_struct_sz); | ||
| 5527 | // We can also return -1 and write to hdrp->version if the version passed in | ||
| 5528 | // hdrp->version is unsupported. But that's not a trivial condition to check, | ||
| 5529 | // and anyway COMMON_INTERCEPTOR_READ_RANGE protects us to some extent. | ||
| 5530 | return res; | ||
| 5531 | } | ||
| 5532 | INTERCEPTOR(int, capset, void *hdrp, const void *datap) { | ||
| 5533 | void *ctx; | ||
| 5534 | COMMON_INTERCEPTOR_ENTER(ctx, capset, hdrp, datap); | ||
| 5535 | if (hdrp) | ||
| 5536 | COMMON_INTERCEPTOR_READ_RANGE(ctx, hdrp, __user_cap_header_struct_sz); | ||
| 5537 | if (datap) | ||
| 5538 | COMMON_INTERCEPTOR_READ_RANGE(ctx, datap, __user_cap_data_struct_sz); | ||
| 5539 | return REAL(capset)(hdrp, datap); | ||
| 5540 | } | ||
| 5541 | #define INIT_CAPGET \ | ||
| 5542 | COMMON_INTERCEPT_FUNCTION(capget); \ | ||
| 5543 | COMMON_INTERCEPT_FUNCTION(capset); | ||
| 5544 | #else | ||
| 5545 | #define INIT_CAPGET | ||
| 5546 | #endif | ||
| 5547 | |||
| 5548 | #if SANITIZER_INTERCEPT_AEABI_MEM | ||
| 5549 | INTERCEPTOR(void *, __aeabi_memmove, void *to, const void *from, uptr size) { | ||
| 5550 | void *ctx; | ||
| 5551 | COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size); | ||
| 5552 | } | ||
| 5553 | |||
| 5554 | INTERCEPTOR(void *, __aeabi_memmove4, void *to, const void *from, uptr size) { | ||
| 5555 | void *ctx; | ||
| 5556 | COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size); | ||
| 5557 | } | ||
| 5558 | |||
| 5559 | INTERCEPTOR(void *, __aeabi_memmove8, void *to, const void *from, uptr size) { | ||
| 5560 | void *ctx; | ||
| 5561 | COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size); | ||
| 5562 | } | ||
| 5563 | |||
| 5564 | INTERCEPTOR(void *, __aeabi_memcpy, void *to, const void *from, uptr size) { | ||
| 5565 | void *ctx; | ||
| 5566 | COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size); | ||
| 5567 | } | ||
| 5568 | |||
| 5569 | INTERCEPTOR(void *, __aeabi_memcpy4, void *to, const void *from, uptr size) { | ||
| 5570 | void *ctx; | ||
| 5571 | COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size); | ||
| 5572 | } | ||
| 5573 | |||
| 5574 | INTERCEPTOR(void *, __aeabi_memcpy8, void *to, const void *from, uptr size) { | ||
| 5575 | void *ctx; | ||
| 5576 | COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size); | ||
| 5577 | } | ||
| 5578 | |||
| 5579 | // Note the argument order. | ||
| 5580 | INTERCEPTOR(void *, __aeabi_memset, void *block, uptr size, int c) { | ||
| 5581 | void *ctx; | ||
| 5582 | COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size); | ||
| 5583 | } | ||
| 5584 | |||
| 5585 | INTERCEPTOR(void *, __aeabi_memset4, void *block, uptr size, int c) { | ||
| 5586 | void *ctx; | ||
| 5587 | COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size); | ||
| 5588 | } | ||
| 5589 | |||
| 5590 | INTERCEPTOR(void *, __aeabi_memset8, void *block, uptr size, int c) { | ||
| 5591 | void *ctx; | ||
| 5592 | COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size); | ||
| 5593 | } | ||
| 5594 | |||
| 5595 | INTERCEPTOR(void *, __aeabi_memclr, void *block, uptr size) { | ||
| 5596 | void *ctx; | ||
| 5597 | COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size); | ||
| 5598 | } | ||
| 5599 | |||
| 5600 | INTERCEPTOR(void *, __aeabi_memclr4, void *block, uptr size) { | ||
| 5601 | void *ctx; | ||
| 5602 | COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size); | ||
| 5603 | } | ||
| 5604 | |||
| 5605 | INTERCEPTOR(void *, __aeabi_memclr8, void *block, uptr size) { | ||
| 5606 | void *ctx; | ||
| 5607 | COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size); | ||
| 5608 | } | ||
| 5609 | |||
| 5610 | #define INIT_AEABI_MEM \ | ||
| 5611 | COMMON_INTERCEPT_FUNCTION(__aeabi_memmove); \ | ||
| 5612 | COMMON_INTERCEPT_FUNCTION(__aeabi_memmove4); \ | ||
| 5613 | COMMON_INTERCEPT_FUNCTION(__aeabi_memmove8); \ | ||
| 5614 | COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy); \ | ||
| 5615 | COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy4); \ | ||
| 5616 | COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy8); \ | ||
| 5617 | COMMON_INTERCEPT_FUNCTION(__aeabi_memset); \ | ||
| 5618 | COMMON_INTERCEPT_FUNCTION(__aeabi_memset4); \ | ||
| 5619 | COMMON_INTERCEPT_FUNCTION(__aeabi_memset8); \ | ||
| 5620 | COMMON_INTERCEPT_FUNCTION(__aeabi_memclr); \ | ||
| 5621 | COMMON_INTERCEPT_FUNCTION(__aeabi_memclr4); \ | ||
| 5622 | COMMON_INTERCEPT_FUNCTION(__aeabi_memclr8); | ||
| 5623 | #else | ||
| 5624 | #define INIT_AEABI_MEM | ||
| 5625 | #endif // SANITIZER_INTERCEPT_AEABI_MEM | ||
| 5626 | |||
| 5627 | #if SANITIZER_INTERCEPT___BZERO | ||
| 5628 | INTERCEPTOR(void *, __bzero, void *block, uptr size) { | ||
| 5629 | void *ctx; | ||
| 5630 | COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size); | ||
| 5631 | } | ||
| 5632 | #define INIT___BZERO COMMON_INTERCEPT_FUNCTION(__bzero); | ||
| 5633 | #else | ||
| 5634 | #define INIT___BZERO | ||
| 5635 | #endif // SANITIZER_INTERCEPT___BZERO | ||
| 5636 | |||
| 5637 | #if SANITIZER_INTERCEPT_BZERO | ||
| 5638 | INTERCEPTOR(void *, bzero, void *block, uptr size) { | ||
| 5639 | void *ctx; | ||
| 5640 | COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size); | ||
| 5641 | } | ||
| 5642 | #define INIT_BZERO COMMON_INTERCEPT_FUNCTION(bzero); | ||
| 5643 | #else | ||
| 5644 | #define INIT_BZERO | ||
| 5645 | #endif // SANITIZER_INTERCEPT_BZERO | ||
| 5646 | |||
| 5647 | #if SANITIZER_INTERCEPT_FTIME | ||
| 5648 | INTERCEPTOR(int, ftime, __sanitizer_timeb *tp) { | ||
| 5649 | void *ctx; | ||
| 5650 | COMMON_INTERCEPTOR_ENTER(ctx, ftime, tp); | ||
| 5651 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5652 | // its metadata. See | ||
| 5653 | // https://github.com/google/sanitizers/issues/321. | ||
| 5654 | int res = REAL(ftime)(tp); | ||
| 5655 | if (tp) | ||
| 5656 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, sizeof(*tp)); | ||
| 5657 | return res; | ||
| 5658 | } | ||
| 5659 | #define INIT_FTIME COMMON_INTERCEPT_FUNCTION(ftime); | ||
| 5660 | #else | ||
| 5661 | #define INIT_FTIME | ||
| 5662 | #endif // SANITIZER_INTERCEPT_FTIME | ||
| 5663 | |||
| 5664 | #if SANITIZER_INTERCEPT_XDR | ||
| 5665 | INTERCEPTOR(void, xdrmem_create, __sanitizer_XDR *xdrs, uptr addr, | ||
| 5666 | unsigned size, int op) { | ||
| 5667 | void *ctx; | ||
| 5668 | COMMON_INTERCEPTOR_ENTER(ctx, xdrmem_create, xdrs, addr, size, op); | ||
| 5669 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5670 | // its metadata. See | ||
| 5671 | // https://github.com/google/sanitizers/issues/321. | ||
| 5672 | REAL(xdrmem_create)(xdrs, addr, size, op); | ||
| 5673 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs)); | ||
| 5674 | if (op == __sanitizer_XDR_ENCODE) { | ||
| 5675 | // It's not obvious how much data individual xdr_ routines write. | ||
| 5676 | // Simply unpoison the entire target buffer in advance. | ||
| 5677 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (void *)addr, size); | ||
| 5678 | } | ||
| 5679 | } | ||
| 5680 | |||
| 5681 | INTERCEPTOR(void, xdrstdio_create, __sanitizer_XDR *xdrs, void *file, int op) { | ||
| 5682 | void *ctx; | ||
| 5683 | COMMON_INTERCEPTOR_ENTER(ctx, xdrstdio_create, xdrs, file, op); | ||
| 5684 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5685 | // its metadata. See | ||
| 5686 | // https://github.com/google/sanitizers/issues/321. | ||
| 5687 | REAL(xdrstdio_create)(xdrs, file, op); | ||
| 5688 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs)); | ||
| 5689 | } | ||
| 5690 | |||
| 5691 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5692 | // its metadata. See | ||
| 5693 | // https://github.com/google/sanitizers/issues/321. | ||
| 5694 | #define XDR_INTERCEPTOR(F, T) \ | ||
| 5695 | INTERCEPTOR(int, F, __sanitizer_XDR *xdrs, T *p) { \ | ||
| 5696 | void *ctx; \ | ||
| 5697 | COMMON_INTERCEPTOR_ENTER(ctx, F, xdrs, p); \ | ||
| 5698 | if (p && xdrs->x_op == __sanitizer_XDR_ENCODE) \ | ||
| 5699 | COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p)); \ | ||
| 5700 | int res = REAL(F)(xdrs, p); \ | ||
| 5701 | if (res && p && xdrs->x_op == __sanitizer_XDR_DECODE) \ | ||
| 5702 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); \ | ||
| 5703 | return res; \ | ||
| 5704 | } | ||
| 5705 | |||
| 5706 | XDR_INTERCEPTOR(xdr_short, short) | ||
| 5707 | XDR_INTERCEPTOR(xdr_u_short, unsigned short) | ||
| 5708 | XDR_INTERCEPTOR(xdr_int, int) | ||
| 5709 | XDR_INTERCEPTOR(xdr_u_int, unsigned) | ||
| 5710 | XDR_INTERCEPTOR(xdr_long, long) | ||
| 5711 | XDR_INTERCEPTOR(xdr_u_long, unsigned long) | ||
| 5712 | XDR_INTERCEPTOR(xdr_hyper, long long) | ||
| 5713 | XDR_INTERCEPTOR(xdr_u_hyper, unsigned long long) | ||
| 5714 | XDR_INTERCEPTOR(xdr_longlong_t, long long) | ||
| 5715 | XDR_INTERCEPTOR(xdr_u_longlong_t, unsigned long long) | ||
| 5716 | XDR_INTERCEPTOR(xdr_int8_t, u8) | ||
| 5717 | XDR_INTERCEPTOR(xdr_uint8_t, u8) | ||
| 5718 | XDR_INTERCEPTOR(xdr_int16_t, u16) | ||
| 5719 | XDR_INTERCEPTOR(xdr_uint16_t, u16) | ||
| 5720 | XDR_INTERCEPTOR(xdr_int32_t, u32) | ||
| 5721 | XDR_INTERCEPTOR(xdr_uint32_t, u32) | ||
| 5722 | XDR_INTERCEPTOR(xdr_int64_t, u64) | ||
| 5723 | XDR_INTERCEPTOR(xdr_uint64_t, u64) | ||
| 5724 | XDR_INTERCEPTOR(xdr_quad_t, long long) | ||
| 5725 | XDR_INTERCEPTOR(xdr_u_quad_t, unsigned long long) | ||
| 5726 | XDR_INTERCEPTOR(xdr_bool, bool) | ||
| 5727 | XDR_INTERCEPTOR(xdr_enum, int) | ||
| 5728 | XDR_INTERCEPTOR(xdr_char, char) | ||
| 5729 | XDR_INTERCEPTOR(xdr_u_char, unsigned char) | ||
| 5730 | XDR_INTERCEPTOR(xdr_float, float) | ||
| 5731 | XDR_INTERCEPTOR(xdr_double, double) | ||
| 5732 | |||
| 5733 | // FIXME: intercept xdr_array, opaque, union, vector, reference, pointer, | ||
| 5734 | // wrapstring, sizeof | ||
| 5735 | |||
| 5736 | INTERCEPTOR(int, xdr_bytes, __sanitizer_XDR *xdrs, char **p, unsigned *sizep, | ||
| 5737 | unsigned maxsize) { | ||
| 5738 | void *ctx; | ||
| 5739 | COMMON_INTERCEPTOR_ENTER(ctx, xdr_bytes, xdrs, p, sizep, maxsize); | ||
| 5740 | if (p && sizep && xdrs->x_op == __sanitizer_XDR_ENCODE) { | ||
| 5741 | COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p)); | ||
| 5742 | COMMON_INTERCEPTOR_READ_RANGE(ctx, sizep, sizeof(*sizep)); | ||
| 5743 | COMMON_INTERCEPTOR_READ_RANGE(ctx, *p, *sizep); | ||
| 5744 | } | ||
| 5745 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5746 | // its metadata. See | ||
| 5747 | // https://github.com/google/sanitizers/issues/321. | ||
| 5748 | int res = REAL(xdr_bytes)(xdrs, p, sizep, maxsize); | ||
| 5749 | if (p && sizep && xdrs->x_op == __sanitizer_XDR_DECODE) { | ||
| 5750 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); | ||
| 5751 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizep, sizeof(*sizep)); | ||
| 5752 | if (res && *p && *sizep) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, *sizep); | ||
| 5753 | } | ||
| 5754 | return res; | ||
| 5755 | } | ||
| 5756 | |||
| 5757 | INTERCEPTOR(int, xdr_string, __sanitizer_XDR *xdrs, char **p, | ||
| 5758 | unsigned maxsize) { | ||
| 5759 | void *ctx; | ||
| 5760 | COMMON_INTERCEPTOR_ENTER(ctx, xdr_string, xdrs, p, maxsize); | ||
| 5761 | if (p && xdrs->x_op == __sanitizer_XDR_ENCODE) { | ||
| 5762 | COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p)); | ||
| 5763 | COMMON_INTERCEPTOR_READ_RANGE(ctx, *p, REAL(strlen)(*p) + 1); | ||
| 5764 | } | ||
| 5765 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5766 | // its metadata. See | ||
| 5767 | // https://github.com/google/sanitizers/issues/321. | ||
| 5768 | int res = REAL(xdr_string)(xdrs, p, maxsize); | ||
| 5769 | if (p && xdrs->x_op == __sanitizer_XDR_DECODE) { | ||
| 5770 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); | ||
| 5771 | if (res && *p) | ||
| 5772 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, REAL(strlen)(*p) + 1); | ||
| 5773 | } | ||
| 5774 | return res; | ||
| 5775 | } | ||
| 5776 | |||
| 5777 | #define INIT_XDR \ | ||
| 5778 | COMMON_INTERCEPT_FUNCTION(xdrmem_create); \ | ||
| 5779 | COMMON_INTERCEPT_FUNCTION(xdrstdio_create); \ | ||
| 5780 | COMMON_INTERCEPT_FUNCTION(xdr_short); \ | ||
| 5781 | COMMON_INTERCEPT_FUNCTION(xdr_u_short); \ | ||
| 5782 | COMMON_INTERCEPT_FUNCTION(xdr_int); \ | ||
| 5783 | COMMON_INTERCEPT_FUNCTION(xdr_u_int); \ | ||
| 5784 | COMMON_INTERCEPT_FUNCTION(xdr_long); \ | ||
| 5785 | COMMON_INTERCEPT_FUNCTION(xdr_u_long); \ | ||
| 5786 | COMMON_INTERCEPT_FUNCTION(xdr_hyper); \ | ||
| 5787 | COMMON_INTERCEPT_FUNCTION(xdr_u_hyper); \ | ||
| 5788 | COMMON_INTERCEPT_FUNCTION(xdr_longlong_t); \ | ||
| 5789 | COMMON_INTERCEPT_FUNCTION(xdr_u_longlong_t); \ | ||
| 5790 | COMMON_INTERCEPT_FUNCTION(xdr_int8_t); \ | ||
| 5791 | COMMON_INTERCEPT_FUNCTION(xdr_uint8_t); \ | ||
| 5792 | COMMON_INTERCEPT_FUNCTION(xdr_int16_t); \ | ||
| 5793 | COMMON_INTERCEPT_FUNCTION(xdr_uint16_t); \ | ||
| 5794 | COMMON_INTERCEPT_FUNCTION(xdr_int32_t); \ | ||
| 5795 | COMMON_INTERCEPT_FUNCTION(xdr_uint32_t); \ | ||
| 5796 | COMMON_INTERCEPT_FUNCTION(xdr_int64_t); \ | ||
| 5797 | COMMON_INTERCEPT_FUNCTION(xdr_uint64_t); \ | ||
| 5798 | COMMON_INTERCEPT_FUNCTION(xdr_quad_t); \ | ||
| 5799 | COMMON_INTERCEPT_FUNCTION(xdr_u_quad_t); \ | ||
| 5800 | COMMON_INTERCEPT_FUNCTION(xdr_bool); \ | ||
| 5801 | COMMON_INTERCEPT_FUNCTION(xdr_enum); \ | ||
| 5802 | COMMON_INTERCEPT_FUNCTION(xdr_char); \ | ||
| 5803 | COMMON_INTERCEPT_FUNCTION(xdr_u_char); \ | ||
| 5804 | COMMON_INTERCEPT_FUNCTION(xdr_float); \ | ||
| 5805 | COMMON_INTERCEPT_FUNCTION(xdr_double); \ | ||
| 5806 | COMMON_INTERCEPT_FUNCTION(xdr_bytes); \ | ||
| 5807 | COMMON_INTERCEPT_FUNCTION(xdr_string); | ||
| 5808 | #else | ||
| 5809 | #define INIT_XDR | ||
| 5810 | #endif // SANITIZER_INTERCEPT_XDR | ||
| 5811 | |||
| 5812 | #if SANITIZER_INTERCEPT_TSEARCH | ||
| 5813 | INTERCEPTOR(void *, tsearch, void *key, void **rootp, | ||
| 5814 | int (*compar)(const void *, const void *)) { | ||
| 5815 | void *ctx; | ||
| 5816 | COMMON_INTERCEPTOR_ENTER(ctx, tsearch, key, rootp, compar); | ||
| 5817 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5818 | // its metadata. See | ||
| 5819 | // https://github.com/google/sanitizers/issues/321. | ||
| 5820 | void *res = REAL(tsearch)(key, rootp, compar); | ||
| 5821 | if (res && *(void **)res == key) | ||
| 5822 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(void *)); | ||
| 5823 | return res; | ||
| 5824 | } | ||
| 5825 | #define INIT_TSEARCH COMMON_INTERCEPT_FUNCTION(tsearch); | ||
| 5826 | #else | ||
| 5827 | #define INIT_TSEARCH | ||
| 5828 | #endif | ||
| 5829 | |||
| 5830 | #if SANITIZER_INTERCEPT_LIBIO_INTERNALS || SANITIZER_INTERCEPT_FOPEN || \ | ||
| 5831 | SANITIZER_INTERCEPT_OPEN_MEMSTREAM | ||
| 5832 | void unpoison_file(__sanitizer_FILE *fp) { | ||
| 5833 | #if SANITIZER_HAS_STRUCT_FILE | ||
| 5834 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp, sizeof(*fp)); | ||
| 5835 | #if SANITIZER_NETBSD | ||
| 5836 | if (fp->_bf._base && fp->_bf._size > 0) | ||
| 5837 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_bf._base, | ||
| 5838 | fp->_bf._size); | ||
| 5839 | #else | ||
| 5840 | if (fp->_IO_read_base && fp->_IO_read_base < fp->_IO_read_end) | ||
| 5841 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_read_base, | ||
| 5842 | fp->_IO_read_end - fp->_IO_read_base); | ||
| 5843 | #endif | ||
| 5844 | #endif // SANITIZER_HAS_STRUCT_FILE | ||
| 5845 | } | ||
| 5846 | #endif | ||
| 5847 | |||
| 5848 | #if SANITIZER_INTERCEPT_LIBIO_INTERNALS | ||
| 5849 | // These guys are called when a .c source is built with -O2. | ||
| 5850 | INTERCEPTOR(int, __uflow, __sanitizer_FILE *fp) { | ||
| 5851 | void *ctx; | ||
| 5852 | COMMON_INTERCEPTOR_ENTER(ctx, __uflow, fp); | ||
| 5853 | int res = REAL(__uflow)(fp); | ||
| 5854 | unpoison_file(fp); | ||
| 5855 | return res; | ||
| 5856 | } | ||
| 5857 | INTERCEPTOR(int, __underflow, __sanitizer_FILE *fp) { | ||
| 5858 | void *ctx; | ||
| 5859 | COMMON_INTERCEPTOR_ENTER(ctx, __underflow, fp); | ||
| 5860 | int res = REAL(__underflow)(fp); | ||
| 5861 | unpoison_file(fp); | ||
| 5862 | return res; | ||
| 5863 | } | ||
| 5864 | INTERCEPTOR(int, __overflow, __sanitizer_FILE *fp, int ch) { | ||
| 5865 | void *ctx; | ||
| 5866 | COMMON_INTERCEPTOR_ENTER(ctx, __overflow, fp, ch); | ||
| 5867 | int res = REAL(__overflow)(fp, ch); | ||
| 5868 | unpoison_file(fp); | ||
| 5869 | return res; | ||
| 5870 | } | ||
| 5871 | INTERCEPTOR(int, __wuflow, __sanitizer_FILE *fp) { | ||
| 5872 | void *ctx; | ||
| 5873 | COMMON_INTERCEPTOR_ENTER(ctx, __wuflow, fp); | ||
| 5874 | int res = REAL(__wuflow)(fp); | ||
| 5875 | unpoison_file(fp); | ||
| 5876 | return res; | ||
| 5877 | } | ||
| 5878 | INTERCEPTOR(int, __wunderflow, __sanitizer_FILE *fp) { | ||
| 5879 | void *ctx; | ||
| 5880 | COMMON_INTERCEPTOR_ENTER(ctx, __wunderflow, fp); | ||
| 5881 | int res = REAL(__wunderflow)(fp); | ||
| 5882 | unpoison_file(fp); | ||
| 5883 | return res; | ||
| 5884 | } | ||
| 5885 | INTERCEPTOR(int, __woverflow, __sanitizer_FILE *fp, int ch) { | ||
| 5886 | void *ctx; | ||
| 5887 | COMMON_INTERCEPTOR_ENTER(ctx, __woverflow, fp, ch); | ||
| 5888 | int res = REAL(__woverflow)(fp, ch); | ||
| 5889 | unpoison_file(fp); | ||
| 5890 | return res; | ||
| 5891 | } | ||
| 5892 | #define INIT_LIBIO_INTERNALS \ | ||
| 5893 | COMMON_INTERCEPT_FUNCTION(__uflow); \ | ||
| 5894 | COMMON_INTERCEPT_FUNCTION(__underflow); \ | ||
| 5895 | COMMON_INTERCEPT_FUNCTION(__overflow); \ | ||
| 5896 | COMMON_INTERCEPT_FUNCTION(__wuflow); \ | ||
| 5897 | COMMON_INTERCEPT_FUNCTION(__wunderflow); \ | ||
| 5898 | COMMON_INTERCEPT_FUNCTION(__woverflow); | ||
| 5899 | #else | ||
| 5900 | #define INIT_LIBIO_INTERNALS | ||
| 5901 | #endif | ||
| 5902 | |||
| 5903 | #if SANITIZER_INTERCEPT_FOPEN | ||
| 5904 | INTERCEPTOR(__sanitizer_FILE *, fopen, const char *path, const char *mode) { | ||
| 5905 | void *ctx; | ||
| 5906 | COMMON_INTERCEPTOR_ENTER(ctx, fopen, path, mode); | ||
| 5907 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 5908 | COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1); | ||
| 5909 | __sanitizer_FILE *res = REAL(fopen)(path, mode); | ||
| 5910 | COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path); | ||
| 5911 | if (res) unpoison_file(res); | ||
| 5912 | return res; | ||
| 5913 | } | ||
| 5914 | INTERCEPTOR(__sanitizer_FILE *, fdopen, int fd, const char *mode) { | ||
| 5915 | void *ctx; | ||
| 5916 | COMMON_INTERCEPTOR_ENTER(ctx, fdopen, fd, mode); | ||
| 5917 | COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1); | ||
| 5918 | __sanitizer_FILE *res = REAL(fdopen)(fd, mode); | ||
| 5919 | if (res) unpoison_file(res); | ||
| 5920 | return res; | ||
| 5921 | } | ||
| 5922 | INTERCEPTOR(__sanitizer_FILE *, freopen, const char *path, const char *mode, | ||
| 5923 | __sanitizer_FILE *fp) { | ||
| 5924 | void *ctx; | ||
| 5925 | COMMON_INTERCEPTOR_ENTER(ctx, freopen, path, mode, fp); | ||
| 5926 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 5927 | COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1); | ||
| 5928 | COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); | ||
| 5929 | __sanitizer_FILE *res = REAL(freopen)(path, mode, fp); | ||
| 5930 | COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path); | ||
| 5931 | if (res) unpoison_file(res); | ||
| 5932 | return res; | ||
| 5933 | } | ||
| 5934 | #define INIT_FOPEN \ | ||
| 5935 | COMMON_INTERCEPT_FUNCTION(fopen); \ | ||
| 5936 | COMMON_INTERCEPT_FUNCTION(fdopen); \ | ||
| 5937 | COMMON_INTERCEPT_FUNCTION(freopen); | ||
| 5938 | #else | ||
| 5939 | #define INIT_FOPEN | ||
| 5940 | #endif | ||
| 5941 | |||
| 5942 | #if SANITIZER_INTERCEPT_FOPEN64 | ||
| 5943 | INTERCEPTOR(__sanitizer_FILE *, fopen64, const char *path, const char *mode) { | ||
| 5944 | void *ctx; | ||
| 5945 | COMMON_INTERCEPTOR_ENTER(ctx, fopen64, path, mode); | ||
| 5946 | COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 5947 | COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1); | ||
| 5948 | __sanitizer_FILE *res = REAL(fopen64)(path, mode); | ||
| 5949 | COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path); | ||
| 5950 | if (res) unpoison_file(res); | ||
| 5951 | return res; | ||
| 5952 | } | ||
| 5953 | INTERCEPTOR(__sanitizer_FILE *, freopen64, const char *path, const char *mode, | ||
| 5954 | __sanitizer_FILE *fp) { | ||
| 5955 | void *ctx; | ||
| 5956 | COMMON_INTERCEPTOR_ENTER(ctx, freopen64, path, mode, fp); | ||
| 5957 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 5958 | COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1); | ||
| 5959 | COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); | ||
| 5960 | __sanitizer_FILE *res = REAL(freopen64)(path, mode, fp); | ||
| 5961 | COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path); | ||
| 5962 | if (res) unpoison_file(res); | ||
| 5963 | return res; | ||
| 5964 | } | ||
| 5965 | #define INIT_FOPEN64 \ | ||
| 5966 | COMMON_INTERCEPT_FUNCTION(fopen64); \ | ||
| 5967 | COMMON_INTERCEPT_FUNCTION(freopen64); | ||
| 5968 | #else | ||
| 5969 | #define INIT_FOPEN64 | ||
| 5970 | #endif | ||
| 5971 | |||
| 5972 | #if SANITIZER_INTERCEPT_OPEN_MEMSTREAM | ||
| 5973 | INTERCEPTOR(__sanitizer_FILE *, open_memstream, char **ptr, SIZE_T *sizeloc) { | ||
| 5974 | void *ctx; | ||
| 5975 | COMMON_INTERCEPTOR_ENTER(ctx, open_memstream, ptr, sizeloc); | ||
| 5976 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 5977 | // its metadata. See | ||
| 5978 | // https://github.com/google/sanitizers/issues/321. | ||
| 5979 | __sanitizer_FILE *res = REAL(open_memstream)(ptr, sizeloc); | ||
| 5980 | if (res) { | ||
| 5981 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr)); | ||
| 5982 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizeloc, sizeof(*sizeloc)); | ||
| 5983 | unpoison_file(res); | ||
| 5984 | FileMetadata file = {ptr, sizeloc}; | ||
| 5985 | SetInterceptorMetadata(res, file); | ||
| 5986 | } | ||
| 5987 | return res; | ||
| 5988 | } | ||
| 5989 | INTERCEPTOR(__sanitizer_FILE *, open_wmemstream, wchar_t **ptr, | ||
| 5990 | SIZE_T *sizeloc) { | ||
| 5991 | void *ctx; | ||
| 5992 | COMMON_INTERCEPTOR_ENTER(ctx, open_wmemstream, ptr, sizeloc); | ||
| 5993 | __sanitizer_FILE *res = REAL(open_wmemstream)(ptr, sizeloc); | ||
| 5994 | if (res) { | ||
| 5995 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr)); | ||
| 5996 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizeloc, sizeof(*sizeloc)); | ||
| 5997 | unpoison_file(res); | ||
| 5998 | FileMetadata file = {(char **)ptr, sizeloc}; | ||
| 5999 | SetInterceptorMetadata(res, file); | ||
| 6000 | } | ||
| 6001 | return res; | ||
| 6002 | } | ||
| 6003 | INTERCEPTOR(__sanitizer_FILE *, fmemopen, void *buf, SIZE_T size, | ||
| 6004 | const char *mode) { | ||
| 6005 | void *ctx; | ||
| 6006 | COMMON_INTERCEPTOR_ENTER(ctx, fmemopen, buf, size, mode); | ||
| 6007 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 6008 | // its metadata. See | ||
| 6009 | // https://github.com/google/sanitizers/issues/321. | ||
| 6010 | __sanitizer_FILE *res = REAL(fmemopen)(buf, size, mode); | ||
| 6011 | if (res) unpoison_file(res); | ||
| 6012 | return res; | ||
| 6013 | } | ||
| 6014 | #define INIT_OPEN_MEMSTREAM \ | ||
| 6015 | COMMON_INTERCEPT_FUNCTION(open_memstream); \ | ||
| 6016 | COMMON_INTERCEPT_FUNCTION(open_wmemstream); \ | ||
| 6017 | COMMON_INTERCEPT_FUNCTION(fmemopen); | ||
| 6018 | #else | ||
| 6019 | #define INIT_OPEN_MEMSTREAM | ||
| 6020 | #endif | ||
| 6021 | |||
| 6022 | #if SANITIZER_INTERCEPT_OBSTACK | ||
| 6023 | static void initialize_obstack(__sanitizer_obstack *obstack) { | ||
| 6024 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(obstack, sizeof(*obstack)); | ||
| 6025 | if (obstack->chunk) | ||
| 6026 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(obstack->chunk, | ||
| 6027 | sizeof(*obstack->chunk)); | ||
| 6028 | } | ||
| 6029 | |||
| 6030 | INTERCEPTOR(int, _obstack_begin_1, __sanitizer_obstack *obstack, int sz, | ||
| 6031 | int align, void *(*alloc_fn)(uptr arg, uptr sz), | ||
| 6032 | void (*free_fn)(uptr arg, void *p)) { | ||
| 6033 | void *ctx; | ||
| 6034 | COMMON_INTERCEPTOR_ENTER(ctx, _obstack_begin_1, obstack, sz, align, alloc_fn, | ||
| 6035 | free_fn); | ||
| 6036 | int res = REAL(_obstack_begin_1)(obstack, sz, align, alloc_fn, free_fn); | ||
| 6037 | if (res) initialize_obstack(obstack); | ||
| 6038 | return res; | ||
| 6039 | } | ||
| 6040 | INTERCEPTOR(int, _obstack_begin, __sanitizer_obstack *obstack, int sz, | ||
| 6041 | int align, void *(*alloc_fn)(uptr sz), void (*free_fn)(void *p)) { | ||
| 6042 | void *ctx; | ||
| 6043 | COMMON_INTERCEPTOR_ENTER(ctx, _obstack_begin, obstack, sz, align, alloc_fn, | ||
| 6044 | free_fn); | ||
| 6045 | int res = REAL(_obstack_begin)(obstack, sz, align, alloc_fn, free_fn); | ||
| 6046 | if (res) initialize_obstack(obstack); | ||
| 6047 | return res; | ||
| 6048 | } | ||
| 6049 | INTERCEPTOR(void, _obstack_newchunk, __sanitizer_obstack *obstack, int length) { | ||
| 6050 | void *ctx; | ||
| 6051 | COMMON_INTERCEPTOR_ENTER(ctx, _obstack_newchunk, obstack, length); | ||
| 6052 | REAL(_obstack_newchunk)(obstack, length); | ||
| 6053 | if (obstack->chunk) | ||
| 6054 | COMMON_INTERCEPTOR_INITIALIZE_RANGE( | ||
| 6055 | obstack->chunk, obstack->next_free - (char *)obstack->chunk); | ||
| 6056 | } | ||
| 6057 | #define INIT_OBSTACK \ | ||
| 6058 | COMMON_INTERCEPT_FUNCTION(_obstack_begin_1); \ | ||
| 6059 | COMMON_INTERCEPT_FUNCTION(_obstack_begin); \ | ||
| 6060 | COMMON_INTERCEPT_FUNCTION(_obstack_newchunk); | ||
| 6061 | #else | ||
| 6062 | #define INIT_OBSTACK | ||
| 6063 | #endif | ||
| 6064 | |||
| 6065 | #if SANITIZER_INTERCEPT_FFLUSH | ||
| 6066 | INTERCEPTOR(int, fflush, __sanitizer_FILE *fp) { | ||
| 6067 | void *ctx; | ||
| 6068 | COMMON_INTERCEPTOR_ENTER(ctx, fflush, fp); | ||
| 6069 | int res = REAL(fflush)(fp); | ||
| 6070 | // FIXME: handle fp == NULL | ||
| 6071 | if (fp) { | ||
| 6072 | const FileMetadata *m = GetInterceptorMetadata(fp); | ||
| 6073 | if (m) COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size); | ||
| 6074 | } | ||
| 6075 | return res; | ||
| 6076 | } | ||
| 6077 | #define INIT_FFLUSH COMMON_INTERCEPT_FUNCTION(fflush); | ||
| 6078 | #else | ||
| 6079 | #define INIT_FFLUSH | ||
| 6080 | #endif | ||
| 6081 | |||
| 6082 | #if SANITIZER_INTERCEPT_FCLOSE | ||
| 6083 | INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) { | ||
| 6084 | void *ctx; | ||
| 6085 | COMMON_INTERCEPTOR_ENTER(ctx, fclose, fp); | ||
| 6086 | COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); | ||
| 6087 | const FileMetadata *m = GetInterceptorMetadata(fp); | ||
| 6088 | int res = REAL(fclose)(fp); | ||
| 6089 | if (m) { | ||
| 6090 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size); | ||
| 6091 | DeleteInterceptorMetadata(fp); | ||
| 6092 | } | ||
| 6093 | return res; | ||
| 6094 | } | ||
| 6095 | #define INIT_FCLOSE COMMON_INTERCEPT_FUNCTION(fclose); | ||
| 6096 | #else | ||
| 6097 | #define INIT_FCLOSE | ||
| 6098 | #endif | ||
| 6099 | |||
| 6100 | #if SANITIZER_INTERCEPT_DLOPEN_DLCLOSE | ||
| 6101 | INTERCEPTOR(void*, dlopen, const char *filename, int flag) { | ||
| 6102 | void *ctx; | ||
| 6103 | COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlopen, filename, flag); | ||
| 6104 | if (filename) COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0); | ||
| 6105 | COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag); | ||
| 6106 | void *res = REAL(dlopen)(filename, flag); | ||
| 6107 | Symbolizer::GetOrInit()->InvalidateModuleList(); | ||
| 6108 | COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res); | ||
| 6109 | return res; | ||
| 6110 | } | ||
| 6111 | |||
| 6112 | INTERCEPTOR(int, dlclose, void *handle) { | ||
| 6113 | void *ctx; | ||
| 6114 | COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlclose, handle); | ||
| 6115 | int res = REAL(dlclose)(handle); | ||
| 6116 | Symbolizer::GetOrInit()->InvalidateModuleList(); | ||
| 6117 | COMMON_INTERCEPTOR_LIBRARY_UNLOADED(); | ||
| 6118 | return res; | ||
| 6119 | } | ||
| 6120 | #define INIT_DLOPEN_DLCLOSE \ | ||
| 6121 | COMMON_INTERCEPT_FUNCTION(dlopen); \ | ||
| 6122 | COMMON_INTERCEPT_FUNCTION(dlclose); | ||
| 6123 | #else | ||
| 6124 | #define INIT_DLOPEN_DLCLOSE | ||
| 6125 | #endif | ||
| 6126 | |||
| 6127 | #if SANITIZER_INTERCEPT_GETPASS | ||
| 6128 | INTERCEPTOR(char *, getpass, const char *prompt) { | ||
| 6129 | void *ctx; | ||
| 6130 | COMMON_INTERCEPTOR_ENTER(ctx, getpass, prompt); | ||
| 6131 | if (prompt) | ||
| 6132 | COMMON_INTERCEPTOR_READ_RANGE(ctx, prompt, REAL(strlen)(prompt)+1); | ||
| 6133 | char *res = REAL(getpass)(prompt); | ||
| 6134 | if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res)+1); | ||
| 6135 | return res; | ||
| 6136 | } | ||
| 6137 | |||
| 6138 | #define INIT_GETPASS COMMON_INTERCEPT_FUNCTION(getpass); | ||
| 6139 | #else | ||
| 6140 | #define INIT_GETPASS | ||
| 6141 | #endif | ||
| 6142 | |||
| 6143 | #if SANITIZER_INTERCEPT_TIMERFD | ||
| 6144 | INTERCEPTOR(int, timerfd_settime, int fd, int flags, void *new_value, | ||
| 6145 | void *old_value) { | ||
| 6146 | void *ctx; | ||
| 6147 | COMMON_INTERCEPTOR_ENTER(ctx, timerfd_settime, fd, flags, new_value, | ||
| 6148 | old_value); | ||
| 6149 | COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerspec_sz); | ||
| 6150 | int res = REAL(timerfd_settime)(fd, flags, new_value, old_value); | ||
| 6151 | if (res != -1 && old_value) | ||
| 6152 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerspec_sz); | ||
| 6153 | return res; | ||
| 6154 | } | ||
| 6155 | |||
| 6156 | INTERCEPTOR(int, timerfd_gettime, int fd, void *curr_value) { | ||
| 6157 | void *ctx; | ||
| 6158 | COMMON_INTERCEPTOR_ENTER(ctx, timerfd_gettime, fd, curr_value); | ||
| 6159 | int res = REAL(timerfd_gettime)(fd, curr_value); | ||
| 6160 | if (res != -1 && curr_value) | ||
| 6161 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerspec_sz); | ||
| 6162 | return res; | ||
| 6163 | } | ||
| 6164 | #define INIT_TIMERFD \ | ||
| 6165 | COMMON_INTERCEPT_FUNCTION(timerfd_settime); \ | ||
| 6166 | COMMON_INTERCEPT_FUNCTION(timerfd_gettime); | ||
| 6167 | #else | ||
| 6168 | #define INIT_TIMERFD | ||
| 6169 | #endif | ||
| 6170 | |||
| 6171 | #if SANITIZER_INTERCEPT_MLOCKX | ||
| 6172 | // Linux kernel has a bug that leads to kernel deadlock if a process | ||
| 6173 | // maps TBs of memory and then calls mlock(). | ||
| 6174 | static void MlockIsUnsupported() { | ||
| 6175 | static atomic_uint8_t printed; | ||
| 6176 | if (atomic_exchange(&printed, 1, memory_order_relaxed)) | ||
| 6177 | return; | ||
| 6178 | VPrintf(1, "%s ignores mlock/mlockall/munlock/munlockall\n", | ||
| 6179 | SanitizerToolName); | ||
| 6180 | } | ||
| 6181 | |||
| 6182 | INTERCEPTOR(int, mlock, const void *addr, uptr len) { | ||
| 6183 | MlockIsUnsupported(); | ||
| 6184 | return 0; | ||
| 6185 | } | ||
| 6186 | |||
| 6187 | INTERCEPTOR(int, munlock, const void *addr, uptr len) { | ||
| 6188 | MlockIsUnsupported(); | ||
| 6189 | return 0; | ||
| 6190 | } | ||
| 6191 | |||
| 6192 | INTERCEPTOR(int, mlockall, int flags) { | ||
| 6193 | MlockIsUnsupported(); | ||
| 6194 | return 0; | ||
| 6195 | } | ||
| 6196 | |||
| 6197 | INTERCEPTOR(int, munlockall, void) { | ||
| 6198 | MlockIsUnsupported(); | ||
| 6199 | return 0; | ||
| 6200 | } | ||
| 6201 | |||
| 6202 | #define INIT_MLOCKX \ | ||
| 6203 | COMMON_INTERCEPT_FUNCTION(mlock); \ | ||
| 6204 | COMMON_INTERCEPT_FUNCTION(munlock); \ | ||
| 6205 | COMMON_INTERCEPT_FUNCTION(mlockall); \ | ||
| 6206 | COMMON_INTERCEPT_FUNCTION(munlockall); | ||
| 6207 | |||
| 6208 | #else | ||
| 6209 | #define INIT_MLOCKX | ||
| 6210 | #endif // SANITIZER_INTERCEPT_MLOCKX | ||
| 6211 | |||
| 6212 | #if SANITIZER_INTERCEPT_FOPENCOOKIE | ||
| 6213 | struct WrappedCookie { | ||
| 6214 | void *real_cookie; | ||
| 6215 | __sanitizer_cookie_io_functions_t real_io_funcs; | ||
| 6216 | }; | ||
| 6217 | |||
| 6218 | static uptr wrapped_read(void *cookie, char *buf, uptr size) { | ||
| 6219 | COMMON_INTERCEPTOR_UNPOISON_PARAM(3); | ||
| 6220 | WrappedCookie *wrapped_cookie = (WrappedCookie *)cookie; | ||
| 6221 | __sanitizer_cookie_io_read real_read = wrapped_cookie->real_io_funcs.read; | ||
| 6222 | return real_read ? real_read(wrapped_cookie->real_cookie, buf, size) : 0; | ||
| 6223 | } | ||
| 6224 | |||
| 6225 | static uptr wrapped_write(void *cookie, const char *buf, uptr size) { | ||
| 6226 | COMMON_INTERCEPTOR_UNPOISON_PARAM(3); | ||
| 6227 | WrappedCookie *wrapped_cookie = (WrappedCookie *)cookie; | ||
| 6228 | __sanitizer_cookie_io_write real_write = wrapped_cookie->real_io_funcs.write; | ||
| 6229 | return real_write ? real_write(wrapped_cookie->real_cookie, buf, size) : size; | ||
| 6230 | } | ||
| 6231 | |||
| 6232 | static int wrapped_seek(void *cookie, u64 *offset, int whence) { | ||
| 6233 | COMMON_INTERCEPTOR_UNPOISON_PARAM(3); | ||
| 6234 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(offset, sizeof(*offset)); | ||
| 6235 | WrappedCookie *wrapped_cookie = (WrappedCookie *)cookie; | ||
| 6236 | __sanitizer_cookie_io_seek real_seek = wrapped_cookie->real_io_funcs.seek; | ||
| 6237 | return real_seek ? real_seek(wrapped_cookie->real_cookie, offset, whence) | ||
| 6238 | : -1; | ||
| 6239 | } | ||
| 6240 | |||
| 6241 | static int wrapped_close(void *cookie) { | ||
| 6242 | COMMON_INTERCEPTOR_UNPOISON_PARAM(1); | ||
| 6243 | WrappedCookie *wrapped_cookie = (WrappedCookie *)cookie; | ||
| 6244 | __sanitizer_cookie_io_close real_close = wrapped_cookie->real_io_funcs.close; | ||
| 6245 | int res = real_close ? real_close(wrapped_cookie->real_cookie) : 0; | ||
| 6246 | InternalFree(wrapped_cookie); | ||
| 6247 | return res; | ||
| 6248 | } | ||
| 6249 | |||
| 6250 | INTERCEPTOR(__sanitizer_FILE *, fopencookie, void *cookie, const char *mode, | ||
| 6251 | __sanitizer_cookie_io_functions_t io_funcs) { | ||
| 6252 | void *ctx; | ||
| 6253 | COMMON_INTERCEPTOR_ENTER(ctx, fopencookie, cookie, mode, io_funcs); | ||
| 6254 | WrappedCookie *wrapped_cookie = | ||
| 6255 | (WrappedCookie *)InternalAlloc(sizeof(WrappedCookie)); | ||
| 6256 | wrapped_cookie->real_cookie = cookie; | ||
| 6257 | wrapped_cookie->real_io_funcs = io_funcs; | ||
| 6258 | __sanitizer_FILE *res = | ||
| 6259 | REAL(fopencookie)(wrapped_cookie, mode, {wrapped_read, wrapped_write, | ||
| 6260 | wrapped_seek, wrapped_close}); | ||
| 6261 | return res; | ||
| 6262 | } | ||
| 6263 | |||
| 6264 | #define INIT_FOPENCOOKIE COMMON_INTERCEPT_FUNCTION(fopencookie); | ||
| 6265 | #else | ||
| 6266 | #define INIT_FOPENCOOKIE | ||
| 6267 | #endif // SANITIZER_INTERCEPT_FOPENCOOKIE | ||
| 6268 | |||
| 6269 | #if SANITIZER_INTERCEPT_SEM | ||
| 6270 | INTERCEPTOR(int, sem_init, __sanitizer_sem_t *s, int pshared, unsigned value) { | ||
| 6271 | void *ctx; | ||
| 6272 | COMMON_INTERCEPTOR_ENTER(ctx, sem_init, s, pshared, value); | ||
| 6273 | // Workaround a bug in glibc's "old" semaphore implementation by | ||
| 6274 | // zero-initializing the sem_t contents. This has to be done here because | ||
| 6275 | // interceptors bind to the lowest symbols version by default, hitting the | ||
| 6276 | // buggy code path while the non-sanitized build of the same code works fine. | ||
| 6277 | REAL(memset)(s, 0, sizeof(*s)); | ||
| 6278 | int res = REAL(sem_init)(s, pshared, value); | ||
| 6279 | return res; | ||
| 6280 | } | ||
| 6281 | |||
| 6282 | INTERCEPTOR(int, sem_destroy, __sanitizer_sem_t *s) { | ||
| 6283 | void *ctx; | ||
| 6284 | COMMON_INTERCEPTOR_ENTER(ctx, sem_destroy, s); | ||
| 6285 | int res = REAL(sem_destroy)(s); | ||
| 6286 | return res; | ||
| 6287 | } | ||
| 6288 | |||
| 6289 | INTERCEPTOR(int, sem_wait, __sanitizer_sem_t *s) { | ||
| 6290 | void *ctx; | ||
| 6291 | COMMON_INTERCEPTOR_ENTER(ctx, sem_wait, s); | ||
| 6292 | int res = COMMON_INTERCEPTOR_BLOCK_REAL(sem_wait)(s); | ||
| 6293 | if (res == 0) { | ||
| 6294 | COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s); | ||
| 6295 | } | ||
| 6296 | return res; | ||
| 6297 | } | ||
| 6298 | |||
| 6299 | INTERCEPTOR(int, sem_trywait, __sanitizer_sem_t *s) { | ||
| 6300 | void *ctx; | ||
| 6301 | COMMON_INTERCEPTOR_ENTER(ctx, sem_trywait, s); | ||
| 6302 | int res = COMMON_INTERCEPTOR_BLOCK_REAL(sem_trywait)(s); | ||
| 6303 | if (res == 0) { | ||
| 6304 | COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s); | ||
| 6305 | } | ||
| 6306 | return res; | ||
| 6307 | } | ||
| 6308 | |||
| 6309 | INTERCEPTOR(int, sem_timedwait, __sanitizer_sem_t *s, void *abstime) { | ||
| 6310 | void *ctx; | ||
| 6311 | COMMON_INTERCEPTOR_ENTER(ctx, sem_timedwait, s, abstime); | ||
| 6312 | COMMON_INTERCEPTOR_READ_RANGE(ctx, abstime, struct_timespec_sz); | ||
| 6313 | int res = COMMON_INTERCEPTOR_BLOCK_REAL(sem_timedwait)(s, abstime); | ||
| 6314 | if (res == 0) { | ||
| 6315 | COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s); | ||
| 6316 | } | ||
| 6317 | return res; | ||
| 6318 | } | ||
| 6319 | |||
| 6320 | INTERCEPTOR(int, sem_post, __sanitizer_sem_t *s) { | ||
| 6321 | void *ctx; | ||
| 6322 | COMMON_INTERCEPTOR_ENTER(ctx, sem_post, s); | ||
| 6323 | COMMON_INTERCEPTOR_RELEASE(ctx, (uptr)s); | ||
| 6324 | int res = REAL(sem_post)(s); | ||
| 6325 | return res; | ||
| 6326 | } | ||
| 6327 | |||
| 6328 | INTERCEPTOR(int, sem_getvalue, __sanitizer_sem_t *s, int *sval) { | ||
| 6329 | void *ctx; | ||
| 6330 | COMMON_INTERCEPTOR_ENTER(ctx, sem_getvalue, s, sval); | ||
| 6331 | int res = REAL(sem_getvalue)(s, sval); | ||
| 6332 | if (res == 0) { | ||
| 6333 | COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s); | ||
| 6334 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sval, sizeof(*sval)); | ||
| 6335 | } | ||
| 6336 | return res; | ||
| 6337 | } | ||
| 6338 | #define INIT_SEM \ | ||
| 6339 | COMMON_INTERCEPT_FUNCTION(sem_init); \ | ||
| 6340 | COMMON_INTERCEPT_FUNCTION(sem_destroy); \ | ||
| 6341 | COMMON_INTERCEPT_FUNCTION(sem_wait); \ | ||
| 6342 | COMMON_INTERCEPT_FUNCTION(sem_trywait); \ | ||
| 6343 | COMMON_INTERCEPT_FUNCTION(sem_timedwait); \ | ||
| 6344 | COMMON_INTERCEPT_FUNCTION(sem_post); \ | ||
| 6345 | COMMON_INTERCEPT_FUNCTION(sem_getvalue); | ||
| 6346 | #else | ||
| 6347 | #define INIT_SEM | ||
| 6348 | #endif // SANITIZER_INTERCEPT_SEM | ||
| 6349 | |||
| 6350 | #if SANITIZER_INTERCEPT_PTHREAD_SETCANCEL | ||
| 6351 | INTERCEPTOR(int, pthread_setcancelstate, int state, int *oldstate) { | ||
| 6352 | void *ctx; | ||
| 6353 | COMMON_INTERCEPTOR_ENTER(ctx, pthread_setcancelstate, state, oldstate); | ||
| 6354 | int res = REAL(pthread_setcancelstate)(state, oldstate); | ||
| 6355 | if (res == 0 && oldstate != nullptr) | ||
| 6356 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldstate, sizeof(*oldstate)); | ||
| 6357 | return res; | ||
| 6358 | } | ||
| 6359 | |||
| 6360 | INTERCEPTOR(int, pthread_setcanceltype, int type, int *oldtype) { | ||
| 6361 | void *ctx; | ||
| 6362 | COMMON_INTERCEPTOR_ENTER(ctx, pthread_setcanceltype, type, oldtype); | ||
| 6363 | int res = REAL(pthread_setcanceltype)(type, oldtype); | ||
| 6364 | if (res == 0 && oldtype != nullptr) | ||
| 6365 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldtype, sizeof(*oldtype)); | ||
| 6366 | return res; | ||
| 6367 | } | ||
| 6368 | #define INIT_PTHREAD_SETCANCEL \ | ||
| 6369 | COMMON_INTERCEPT_FUNCTION(pthread_setcancelstate); \ | ||
| 6370 | COMMON_INTERCEPT_FUNCTION(pthread_setcanceltype); | ||
| 6371 | #else | ||
| 6372 | #define INIT_PTHREAD_SETCANCEL | ||
| 6373 | #endif | ||
| 6374 | |||
| 6375 | #if SANITIZER_INTERCEPT_MINCORE | ||
| 6376 | INTERCEPTOR(int, mincore, void *addr, uptr length, unsigned char *vec) { | ||
| 6377 | void *ctx; | ||
| 6378 | COMMON_INTERCEPTOR_ENTER(ctx, mincore, addr, length, vec); | ||
| 6379 | int res = REAL(mincore)(addr, length, vec); | ||
| 6380 | if (res == 0) { | ||
| 6381 | uptr page_size = GetPageSizeCached(); | ||
| 6382 | uptr vec_size = ((length + page_size - 1) & (~(page_size - 1))) / page_size; | ||
| 6383 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, vec, vec_size); | ||
| 6384 | } | ||
| 6385 | return res; | ||
| 6386 | } | ||
| 6387 | #define INIT_MINCORE COMMON_INTERCEPT_FUNCTION(mincore); | ||
| 6388 | #else | ||
| 6389 | #define INIT_MINCORE | ||
| 6390 | #endif | ||
| 6391 | |||
| 6392 | #if SANITIZER_INTERCEPT_PROCESS_VM_READV | ||
| 6393 | INTERCEPTOR(SSIZE_T, process_vm_readv, int pid, __sanitizer_iovec *local_iov, | ||
| 6394 | uptr liovcnt, __sanitizer_iovec *remote_iov, uptr riovcnt, | ||
| 6395 | uptr flags) { | ||
| 6396 | void *ctx; | ||
| 6397 | COMMON_INTERCEPTOR_ENTER(ctx, process_vm_readv, pid, local_iov, liovcnt, | ||
| 6398 | remote_iov, riovcnt, flags); | ||
| 6399 | SSIZE_T res = REAL(process_vm_readv)(pid, local_iov, liovcnt, remote_iov, | ||
| 6400 | riovcnt, flags); | ||
| 6401 | if (res > 0) | ||
| 6402 | write_iovec(ctx, local_iov, liovcnt, res); | ||
| 6403 | return res; | ||
| 6404 | } | ||
| 6405 | |||
| 6406 | INTERCEPTOR(SSIZE_T, process_vm_writev, int pid, __sanitizer_iovec *local_iov, | ||
| 6407 | uptr liovcnt, __sanitizer_iovec *remote_iov, uptr riovcnt, | ||
| 6408 | uptr flags) { | ||
| 6409 | void *ctx; | ||
| 6410 | COMMON_INTERCEPTOR_ENTER(ctx, process_vm_writev, pid, local_iov, liovcnt, | ||
| 6411 | remote_iov, riovcnt, flags); | ||
| 6412 | SSIZE_T res = REAL(process_vm_writev)(pid, local_iov, liovcnt, remote_iov, | ||
| 6413 | riovcnt, flags); | ||
| 6414 | if (res > 0) | ||
| 6415 | read_iovec(ctx, local_iov, liovcnt, res); | ||
| 6416 | return res; | ||
| 6417 | } | ||
| 6418 | #define INIT_PROCESS_VM_READV \ | ||
| 6419 | COMMON_INTERCEPT_FUNCTION(process_vm_readv); \ | ||
| 6420 | COMMON_INTERCEPT_FUNCTION(process_vm_writev); | ||
| 6421 | #else | ||
| 6422 | #define INIT_PROCESS_VM_READV | ||
| 6423 | #endif | ||
| 6424 | |||
| 6425 | #if SANITIZER_INTERCEPT_CTERMID | ||
| 6426 | INTERCEPTOR(char *, ctermid, char *s) { | ||
| 6427 | void *ctx; | ||
| 6428 | COMMON_INTERCEPTOR_ENTER(ctx, ctermid, s); | ||
| 6429 | char *res = REAL(ctermid)(s); | ||
| 6430 | if (res) { | ||
| 6431 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); | ||
| 6432 | } | ||
| 6433 | return res; | ||
| 6434 | } | ||
| 6435 | #define INIT_CTERMID COMMON_INTERCEPT_FUNCTION(ctermid); | ||
| 6436 | #else | ||
| 6437 | #define INIT_CTERMID | ||
| 6438 | #endif | ||
| 6439 | |||
| 6440 | #if SANITIZER_INTERCEPT_CTERMID_R | ||
| 6441 | INTERCEPTOR(char *, ctermid_r, char *s) { | ||
| 6442 | void *ctx; | ||
| 6443 | COMMON_INTERCEPTOR_ENTER(ctx, ctermid_r, s); | ||
| 6444 | char *res = REAL(ctermid_r)(s); | ||
| 6445 | if (res) { | ||
| 6446 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); | ||
| 6447 | } | ||
| 6448 | return res; | ||
| 6449 | } | ||
| 6450 | #define INIT_CTERMID_R COMMON_INTERCEPT_FUNCTION(ctermid_r); | ||
| 6451 | #else | ||
| 6452 | #define INIT_CTERMID_R | ||
| 6453 | #endif | ||
| 6454 | |||
| 6455 | #if SANITIZER_INTERCEPT_RECV_RECVFROM | ||
| 6456 | INTERCEPTOR(SSIZE_T, recv, int fd, void *buf, SIZE_T len, int flags) { | ||
| 6457 | void *ctx; | ||
| 6458 | COMMON_INTERCEPTOR_ENTER(ctx, recv, fd, buf, len, flags); | ||
| 6459 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 6460 | SSIZE_T res = REAL(recv)(fd, buf, len, flags); | ||
| 6461 | if (res > 0) { | ||
| 6462 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len)); | ||
| 6463 | } | ||
| 6464 | if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 6465 | return res; | ||
| 6466 | } | ||
| 6467 | |||
| 6468 | INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags, | ||
| 6469 | void *srcaddr, int *addrlen) { | ||
| 6470 | void *ctx; | ||
| 6471 | COMMON_INTERCEPTOR_ENTER(ctx, recvfrom, fd, buf, len, flags, srcaddr, | ||
| 6472 | addrlen); | ||
| 6473 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 6474 | SIZE_T srcaddr_sz; | ||
| 6475 | if (srcaddr) srcaddr_sz = *addrlen; | ||
| 6476 | (void)srcaddr_sz; // prevent "set but not used" warning | ||
| 6477 | SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen); | ||
| 6478 | if (res > 0) | ||
| 6479 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len)); | ||
| 6480 | if (res >= 0 && srcaddr) | ||
| 6481 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr, | ||
| 6482 | Min((SIZE_T)*addrlen, srcaddr_sz)); | ||
| 6483 | return res; | ||
| 6484 | } | ||
| 6485 | #define INIT_RECV_RECVFROM \ | ||
| 6486 | COMMON_INTERCEPT_FUNCTION(recv); \ | ||
| 6487 | COMMON_INTERCEPT_FUNCTION(recvfrom); | ||
| 6488 | #else | ||
| 6489 | #define INIT_RECV_RECVFROM | ||
| 6490 | #endif | ||
| 6491 | |||
| 6492 | #if SANITIZER_INTERCEPT_SEND_SENDTO | ||
| 6493 | INTERCEPTOR(SSIZE_T, send, int fd, void *buf, SIZE_T len, int flags) { | ||
| 6494 | void *ctx; | ||
| 6495 | COMMON_INTERCEPTOR_ENTER(ctx, send, fd, buf, len, flags); | ||
| 6496 | if (fd >= 0) { | ||
| 6497 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 6498 | COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); | ||
| 6499 | } | ||
| 6500 | SSIZE_T res = REAL(send)(fd, buf, len, flags); | ||
| 6501 | if (common_flags()->intercept_send && res > 0) | ||
| 6502 | COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, Min((SIZE_T)res, len)); | ||
| 6503 | return res; | ||
| 6504 | } | ||
| 6505 | |||
| 6506 | INTERCEPTOR(SSIZE_T, sendto, int fd, void *buf, SIZE_T len, int flags, | ||
| 6507 | void *dstaddr, int addrlen) { | ||
| 6508 | void *ctx; | ||
| 6509 | COMMON_INTERCEPTOR_ENTER(ctx, sendto, fd, buf, len, flags, dstaddr, addrlen); | ||
| 6510 | if (fd >= 0) { | ||
| 6511 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 6512 | COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); | ||
| 6513 | } | ||
| 6514 | // Can't check dstaddr as it may have uninitialized padding at the end. | ||
| 6515 | SSIZE_T res = REAL(sendto)(fd, buf, len, flags, dstaddr, addrlen); | ||
| 6516 | if (common_flags()->intercept_send && res > 0) | ||
| 6517 | COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, Min((SIZE_T)res, len)); | ||
| 6518 | return res; | ||
| 6519 | } | ||
| 6520 | #define INIT_SEND_SENDTO \ | ||
| 6521 | COMMON_INTERCEPT_FUNCTION(send); \ | ||
| 6522 | COMMON_INTERCEPT_FUNCTION(sendto); | ||
| 6523 | #else | ||
| 6524 | #define INIT_SEND_SENDTO | ||
| 6525 | #endif | ||
| 6526 | |||
| 6527 | #if SANITIZER_INTERCEPT_EVENTFD_READ_WRITE | ||
| 6528 | INTERCEPTOR(int, eventfd_read, int fd, u64 *value) { | ||
| 6529 | void *ctx; | ||
| 6530 | COMMON_INTERCEPTOR_ENTER(ctx, eventfd_read, fd, value); | ||
| 6531 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 6532 | int res = REAL(eventfd_read)(fd, value); | ||
| 6533 | if (res == 0) { | ||
| 6534 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, sizeof(*value)); | ||
| 6535 | if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 6536 | } | ||
| 6537 | return res; | ||
| 6538 | } | ||
| 6539 | INTERCEPTOR(int, eventfd_write, int fd, u64 value) { | ||
| 6540 | void *ctx; | ||
| 6541 | COMMON_INTERCEPTOR_ENTER(ctx, eventfd_write, fd, value); | ||
| 6542 | if (fd >= 0) { | ||
| 6543 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 6544 | COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd); | ||
| 6545 | } | ||
| 6546 | int res = REAL(eventfd_write)(fd, value); | ||
| 6547 | return res; | ||
| 6548 | } | ||
| 6549 | #define INIT_EVENTFD_READ_WRITE \ | ||
| 6550 | COMMON_INTERCEPT_FUNCTION(eventfd_read); \ | ||
| 6551 | COMMON_INTERCEPT_FUNCTION(eventfd_write) | ||
| 6552 | #else | ||
| 6553 | #define INIT_EVENTFD_READ_WRITE | ||
| 6554 | #endif | ||
| 6555 | |||
| 6556 | #if SANITIZER_INTERCEPT_STAT | ||
| 6557 | INTERCEPTOR(int, stat, const char *path, void *buf) { | ||
| 6558 | void *ctx; | ||
| 6559 | COMMON_INTERCEPTOR_ENTER(ctx, stat, path, buf); | ||
| 6560 | if (common_flags()->intercept_stat) | ||
| 6561 | COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); | ||
| 6562 | int res = REAL(stat)(path, buf); | ||
| 6563 | if (!res) | ||
| 6564 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat_sz); | ||
| 6565 | return res; | ||
| 6566 | } | ||
| 6567 | #define INIT_STAT COMMON_INTERCEPT_FUNCTION(stat) | ||
| 6568 | #else | ||
| 6569 | #define INIT_STAT | ||
| 6570 | #endif | ||
| 6571 | |||
| 6572 | #if SANITIZER_INTERCEPT_LSTAT | ||
| 6573 | INTERCEPTOR(int, lstat, const char *path, void *buf) { | ||
| 6574 | void *ctx; | ||
| 6575 | COMMON_INTERCEPTOR_ENTER(ctx, lstat, path, buf); | ||
| 6576 | if (common_flags()->intercept_stat) | ||
| 6577 | COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); | ||
| 6578 | int res = REAL(lstat)(path, buf); | ||
| 6579 | if (!res) | ||
| 6580 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat_sz); | ||
| 6581 | return res; | ||
| 6582 | } | ||
| 6583 | #define INIT_LSTAT COMMON_INTERCEPT_FUNCTION(lstat) | ||
| 6584 | #else | ||
| 6585 | #define INIT_LSTAT | ||
| 6586 | #endif | ||
| 6587 | |||
| 6588 | #if SANITIZER_INTERCEPT___XSTAT | ||
| 6589 | INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) { | ||
| 6590 | void *ctx; | ||
| 6591 | COMMON_INTERCEPTOR_ENTER(ctx, __xstat, version, path, buf); | ||
| 6592 | if (common_flags()->intercept_stat) | ||
| 6593 | COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); | ||
| 6594 | int res = REAL(__xstat)(version, path, buf); | ||
| 6595 | if (!res) | ||
| 6596 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat_sz); | ||
| 6597 | return res; | ||
| 6598 | } | ||
| 6599 | #define INIT___XSTAT COMMON_INTERCEPT_FUNCTION(__xstat) | ||
| 6600 | #else | ||
| 6601 | #define INIT___XSTAT | ||
| 6602 | #endif | ||
| 6603 | |||
| 6604 | #if SANITIZER_INTERCEPT___XSTAT64 | ||
| 6605 | INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) { | ||
| 6606 | void *ctx; | ||
| 6607 | COMMON_INTERCEPTOR_ENTER(ctx, __xstat64, version, path, buf); | ||
| 6608 | if (common_flags()->intercept_stat) | ||
| 6609 | COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); | ||
| 6610 | int res = REAL(__xstat64)(version, path, buf); | ||
| 6611 | if (!res) | ||
| 6612 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat64_sz); | ||
| 6613 | return res; | ||
| 6614 | } | ||
| 6615 | #define INIT___XSTAT64 COMMON_INTERCEPT_FUNCTION(__xstat64) | ||
| 6616 | #else | ||
| 6617 | #define INIT___XSTAT64 | ||
| 6618 | #endif | ||
| 6619 | |||
| 6620 | #if SANITIZER_INTERCEPT___LXSTAT | ||
| 6621 | INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) { | ||
| 6622 | void *ctx; | ||
| 6623 | COMMON_INTERCEPTOR_ENTER(ctx, __lxstat, version, path, buf); | ||
| 6624 | if (common_flags()->intercept_stat) | ||
| 6625 | COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); | ||
| 6626 | int res = REAL(__lxstat)(version, path, buf); | ||
| 6627 | if (!res) | ||
| 6628 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat_sz); | ||
| 6629 | return res; | ||
| 6630 | } | ||
| 6631 | #define INIT___LXSTAT COMMON_INTERCEPT_FUNCTION(__lxstat) | ||
| 6632 | #else | ||
| 6633 | #define INIT___LXSTAT | ||
| 6634 | #endif | ||
| 6635 | |||
| 6636 | #if SANITIZER_INTERCEPT___LXSTAT64 | ||
| 6637 | INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) { | ||
| 6638 | void *ctx; | ||
| 6639 | COMMON_INTERCEPTOR_ENTER(ctx, __lxstat64, version, path, buf); | ||
| 6640 | if (common_flags()->intercept_stat) | ||
| 6641 | COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); | ||
| 6642 | int res = REAL(__lxstat64)(version, path, buf); | ||
| 6643 | if (!res) | ||
| 6644 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat64_sz); | ||
| 6645 | return res; | ||
| 6646 | } | ||
| 6647 | #define INIT___LXSTAT64 COMMON_INTERCEPT_FUNCTION(__lxstat64) | ||
| 6648 | #else | ||
| 6649 | #define INIT___LXSTAT64 | ||
| 6650 | #endif | ||
| 6651 | |||
| 6652 | // FIXME: add other *stat interceptor | ||
| 6653 | |||
| 6654 | #if SANITIZER_INTERCEPT_UTMP | ||
| 6655 | INTERCEPTOR(void *, getutent, int dummy) { | ||
| 6656 | void *ctx; | ||
| 6657 | COMMON_INTERCEPTOR_ENTER(ctx, getutent, dummy); | ||
| 6658 | void *res = REAL(getutent)(dummy); | ||
| 6659 | if (res) | ||
| 6660 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmp_sz); | ||
| 6661 | return res; | ||
| 6662 | } | ||
| 6663 | INTERCEPTOR(void *, getutid, void *ut) { | ||
| 6664 | void *ctx; | ||
| 6665 | COMMON_INTERCEPTOR_ENTER(ctx, getutid, ut); | ||
| 6666 | void *res = REAL(getutid)(ut); | ||
| 6667 | if (res) | ||
| 6668 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmp_sz); | ||
| 6669 | return res; | ||
| 6670 | } | ||
| 6671 | INTERCEPTOR(void *, getutline, void *ut) { | ||
| 6672 | void *ctx; | ||
| 6673 | COMMON_INTERCEPTOR_ENTER(ctx, getutline, ut); | ||
| 6674 | void *res = REAL(getutline)(ut); | ||
| 6675 | if (res) | ||
| 6676 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmp_sz); | ||
| 6677 | return res; | ||
| 6678 | } | ||
| 6679 | #define INIT_UTMP \ | ||
| 6680 | COMMON_INTERCEPT_FUNCTION(getutent); \ | ||
| 6681 | COMMON_INTERCEPT_FUNCTION(getutid); \ | ||
| 6682 | COMMON_INTERCEPT_FUNCTION(getutline); | ||
| 6683 | #else | ||
| 6684 | #define INIT_UTMP | ||
| 6685 | #endif | ||
| 6686 | |||
| 6687 | #if SANITIZER_INTERCEPT_UTMPX | ||
| 6688 | INTERCEPTOR(void *, getutxent, int dummy) { | ||
| 6689 | void *ctx; | ||
| 6690 | COMMON_INTERCEPTOR_ENTER(ctx, getutxent, dummy); | ||
| 6691 | void *res = REAL(getutxent)(dummy); | ||
| 6692 | if (res) | ||
| 6693 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmpx_sz); | ||
| 6694 | return res; | ||
| 6695 | } | ||
| 6696 | INTERCEPTOR(void *, getutxid, void *ut) { | ||
| 6697 | void *ctx; | ||
| 6698 | COMMON_INTERCEPTOR_ENTER(ctx, getutxid, ut); | ||
| 6699 | void *res = REAL(getutxid)(ut); | ||
| 6700 | if (res) | ||
| 6701 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmpx_sz); | ||
| 6702 | return res; | ||
| 6703 | } | ||
| 6704 | INTERCEPTOR(void *, getutxline, void *ut) { | ||
| 6705 | void *ctx; | ||
| 6706 | COMMON_INTERCEPTOR_ENTER(ctx, getutxline, ut); | ||
| 6707 | void *res = REAL(getutxline)(ut); | ||
| 6708 | if (res) | ||
| 6709 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmpx_sz); | ||
| 6710 | return res; | ||
| 6711 | } | ||
| 6712 | INTERCEPTOR(void *, pututxline, const void *ut) { | ||
| 6713 | void *ctx; | ||
| 6714 | COMMON_INTERCEPTOR_ENTER(ctx, pututxline, ut); | ||
| 6715 | if (ut) | ||
| 6716 | COMMON_INTERCEPTOR_READ_RANGE(ctx, ut, __sanitizer::struct_utmpx_sz); | ||
| 6717 | void *res = REAL(pututxline)(ut); | ||
| 6718 | if (res) | ||
| 6719 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, __sanitizer::struct_utmpx_sz); | ||
| 6720 | return res; | ||
| 6721 | } | ||
| 6722 | #define INIT_UTMPX \ | ||
| 6723 | COMMON_INTERCEPT_FUNCTION(getutxent); \ | ||
| 6724 | COMMON_INTERCEPT_FUNCTION(getutxid); \ | ||
| 6725 | COMMON_INTERCEPT_FUNCTION(getutxline); \ | ||
| 6726 | COMMON_INTERCEPT_FUNCTION(pututxline); | ||
| 6727 | #else | ||
| 6728 | #define INIT_UTMPX | ||
| 6729 | #endif | ||
| 6730 | |||
| 6731 | #if SANITIZER_INTERCEPT_GETLOADAVG | ||
| 6732 | INTERCEPTOR(int, getloadavg, double *loadavg, int nelem) { | ||
| 6733 | void *ctx; | ||
| 6734 | COMMON_INTERCEPTOR_ENTER(ctx, getloadavg, loadavg, nelem); | ||
| 6735 | int res = REAL(getloadavg)(loadavg, nelem); | ||
| 6736 | if (res > 0) | ||
| 6737 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, loadavg, res * sizeof(*loadavg)); | ||
| 6738 | return res; | ||
| 6739 | } | ||
| 6740 | #define INIT_GETLOADAVG \ | ||
| 6741 | COMMON_INTERCEPT_FUNCTION(getloadavg); | ||
| 6742 | #else | ||
| 6743 | #define INIT_GETLOADAVG | ||
| 6744 | #endif | ||
| 6745 | |||
| 6746 | #if SANITIZER_INTERCEPT_MCHECK_MPROBE | ||
| 6747 | INTERCEPTOR(int, mcheck, void (*abortfunc)(int mstatus)) { | ||
| 6748 | return 0; | ||
| 6749 | } | ||
| 6750 | |||
| 6751 | INTERCEPTOR(int, mcheck_pedantic, void (*abortfunc)(int mstatus)) { | ||
| 6752 | return 0; | ||
| 6753 | } | ||
| 6754 | |||
| 6755 | INTERCEPTOR(int, mprobe, void *ptr) { | ||
| 6756 | return 0; | ||
| 6757 | } | ||
| 6758 | #endif | ||
| 6759 | |||
| 6760 | INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) { | ||
| 6761 | void *ctx; | ||
| 6762 | COMMON_INTERCEPTOR_ENTER(ctx, wcslen, s); | ||
| 6763 | SIZE_T res = REAL(wcslen)(s); | ||
| 6764 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s, sizeof(wchar_t) * (res + 1)); | ||
| 6765 | return res; | ||
| 6766 | } | ||
| 6767 | |||
| 6768 | INTERCEPTOR(SIZE_T, wcsnlen, const wchar_t *s, SIZE_T n) { | ||
| 6769 | void *ctx; | ||
| 6770 | COMMON_INTERCEPTOR_ENTER(ctx, wcsnlen, s, n); | ||
| 6771 | SIZE_T res = REAL(wcsnlen)(s, n); | ||
| 6772 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s, sizeof(wchar_t) * Min(res + 1, n)); | ||
| 6773 | return res; | ||
| 6774 | } | ||
| 6775 | #define INIT_WCSLEN \ | ||
| 6776 | COMMON_INTERCEPT_FUNCTION(wcslen); \ | ||
| 6777 | COMMON_INTERCEPT_FUNCTION(wcsnlen); | ||
| 6778 | |||
| 6779 | #if SANITIZER_INTERCEPT_WCSCAT | ||
| 6780 | INTERCEPTOR(wchar_t *, wcscat, wchar_t *dst, const wchar_t *src) { | ||
| 6781 | void *ctx; | ||
| 6782 | COMMON_INTERCEPTOR_ENTER(ctx, wcscat, dst, src); | ||
| 6783 | SIZE_T src_size = REAL(wcslen)(src); | ||
| 6784 | SIZE_T dst_size = REAL(wcslen)(dst); | ||
| 6785 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, (src_size + 1) * sizeof(wchar_t)); | ||
| 6786 | COMMON_INTERCEPTOR_READ_RANGE(ctx, dst, (dst_size + 1) * sizeof(wchar_t)); | ||
| 6787 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst + dst_size, | ||
| 6788 | (src_size + 1) * sizeof(wchar_t)); | ||
| 6789 | return REAL(wcscat)(dst, src); | ||
| 6790 | } | ||
| 6791 | |||
| 6792 | INTERCEPTOR(wchar_t *, wcsncat, wchar_t *dst, const wchar_t *src, SIZE_T n) { | ||
| 6793 | void *ctx; | ||
| 6794 | COMMON_INTERCEPTOR_ENTER(ctx, wcsncat, dst, src, n); | ||
| 6795 | SIZE_T src_size = REAL(wcsnlen)(src, n); | ||
| 6796 | SIZE_T dst_size = REAL(wcslen)(dst); | ||
| 6797 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, | ||
| 6798 | Min(src_size + 1, n) * sizeof(wchar_t)); | ||
| 6799 | COMMON_INTERCEPTOR_READ_RANGE(ctx, dst, (dst_size + 1) * sizeof(wchar_t)); | ||
| 6800 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst + dst_size, | ||
| 6801 | (src_size + 1) * sizeof(wchar_t)); | ||
| 6802 | return REAL(wcsncat)(dst, src, n); | ||
| 6803 | } | ||
| 6804 | #define INIT_WCSCAT \ | ||
| 6805 | COMMON_INTERCEPT_FUNCTION(wcscat); \ | ||
| 6806 | COMMON_INTERCEPT_FUNCTION(wcsncat); | ||
| 6807 | #else | ||
| 6808 | #define INIT_WCSCAT | ||
| 6809 | #endif | ||
| 6810 | |||
| 6811 | #if SANITIZER_INTERCEPT_WCSDUP | ||
| 6812 | INTERCEPTOR(wchar_t *, wcsdup, wchar_t *s) { | ||
| 6813 | void *ctx; | ||
| 6814 | COMMON_INTERCEPTOR_ENTER(ctx, wcsdup, s); | ||
| 6815 | SIZE_T len = REAL(wcslen)(s); | ||
| 6816 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s, sizeof(wchar_t) * (len + 1)); | ||
| 6817 | wchar_t *result = REAL(wcsdup)(s); | ||
| 6818 | if (result) | ||
| 6819 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(wchar_t) * (len + 1)); | ||
| 6820 | return result; | ||
| 6821 | } | ||
| 6822 | |||
| 6823 | #define INIT_WCSDUP COMMON_INTERCEPT_FUNCTION(wcsdup); | ||
| 6824 | #else | ||
| 6825 | #define INIT_WCSDUP | ||
| 6826 | #endif | ||
| 6827 | |||
| 6828 | #if SANITIZER_INTERCEPT_STRXFRM | ||
| 6829 | static SIZE_T RealStrLen(const char *str) { return REAL(strlen)(str); } | ||
| 6830 | |||
| 6831 | static SIZE_T RealStrLen(const wchar_t *str) { return REAL(wcslen)(str); } | ||
| 6832 | |||
| 6833 | #define STRXFRM_INTERCEPTOR_IMPL(strxfrm, dest, src, len, ...) \ | ||
| 6834 | { \ | ||
| 6835 | void *ctx; \ | ||
| 6836 | COMMON_INTERCEPTOR_ENTER(ctx, strxfrm, dest, src, len, ##__VA_ARGS__); \ | ||
| 6837 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, \ | ||
| 6838 | sizeof(*src) * (RealStrLen(src) + 1)); \ | ||
| 6839 | SIZE_T res = REAL(strxfrm)(dest, src, len, ##__VA_ARGS__); \ | ||
| 6840 | if (res < len) \ | ||
| 6841 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, sizeof(*src) * (res + 1)); \ | ||
| 6842 | return res; \ | ||
| 6843 | } | ||
| 6844 | |||
| 6845 | INTERCEPTOR(SIZE_T, strxfrm, char *dest, const char *src, SIZE_T len) { | ||
| 6846 | STRXFRM_INTERCEPTOR_IMPL(strxfrm, dest, src, len); | ||
| 6847 | } | ||
| 6848 | |||
| 6849 | INTERCEPTOR(SIZE_T, strxfrm_l, char *dest, const char *src, SIZE_T len, | ||
| 6850 | void *locale) { | ||
| 6851 | STRXFRM_INTERCEPTOR_IMPL(strxfrm_l, dest, src, len, locale); | ||
| 6852 | } | ||
| 6853 | |||
| 6854 | #define INIT_STRXFRM \ | ||
| 6855 | COMMON_INTERCEPT_FUNCTION(strxfrm); \ | ||
| 6856 | COMMON_INTERCEPT_FUNCTION(strxfrm_l); | ||
| 6857 | #else | ||
| 6858 | #define INIT_STRXFRM | ||
| 6859 | #endif | ||
| 6860 | |||
| 6861 | #if SANITIZER_INTERCEPT___STRXFRM_L | ||
| 6862 | INTERCEPTOR(SIZE_T, __strxfrm_l, char *dest, const char *src, SIZE_T len, | ||
| 6863 | void *locale) { | ||
| 6864 | STRXFRM_INTERCEPTOR_IMPL(__strxfrm_l, dest, src, len, locale); | ||
| 6865 | } | ||
| 6866 | |||
| 6867 | #define INIT___STRXFRM_L COMMON_INTERCEPT_FUNCTION(__strxfrm_l); | ||
| 6868 | #else | ||
| 6869 | #define INIT___STRXFRM_L | ||
| 6870 | #endif | ||
| 6871 | |||
| 6872 | #if SANITIZER_INTERCEPT_WCSXFRM | ||
| 6873 | INTERCEPTOR(SIZE_T, wcsxfrm, wchar_t *dest, const wchar_t *src, SIZE_T len) { | ||
| 6874 | STRXFRM_INTERCEPTOR_IMPL(wcsxfrm, dest, src, len); | ||
| 6875 | } | ||
| 6876 | |||
| 6877 | INTERCEPTOR(SIZE_T, wcsxfrm_l, wchar_t *dest, const wchar_t *src, SIZE_T len, | ||
| 6878 | void *locale) { | ||
| 6879 | STRXFRM_INTERCEPTOR_IMPL(wcsxfrm_l, dest, src, len, locale); | ||
| 6880 | } | ||
| 6881 | |||
| 6882 | #define INIT_WCSXFRM \ | ||
| 6883 | COMMON_INTERCEPT_FUNCTION(wcsxfrm); \ | ||
| 6884 | COMMON_INTERCEPT_FUNCTION(wcsxfrm_l); | ||
| 6885 | #else | ||
| 6886 | #define INIT_WCSXFRM | ||
| 6887 | #endif | ||
| 6888 | |||
| 6889 | #if SANITIZER_INTERCEPT___WCSXFRM_L | ||
| 6890 | INTERCEPTOR(SIZE_T, __wcsxfrm_l, wchar_t *dest, const wchar_t *src, SIZE_T len, | ||
| 6891 | void *locale) { | ||
| 6892 | STRXFRM_INTERCEPTOR_IMPL(__wcsxfrm_l, dest, src, len, locale); | ||
| 6893 | } | ||
| 6894 | |||
| 6895 | #define INIT___WCSXFRM_L COMMON_INTERCEPT_FUNCTION(__wcsxfrm_l); | ||
| 6896 | #else | ||
| 6897 | #define INIT___WCSXFRM_L | ||
| 6898 | #endif | ||
| 6899 | |||
| 6900 | #if SANITIZER_INTERCEPT_ACCT | ||
| 6901 | INTERCEPTOR(int, acct, const char *file) { | ||
| 6902 | void *ctx; | ||
| 6903 | COMMON_INTERCEPTOR_ENTER(ctx, acct, file); | ||
| 6904 | if (file) | ||
| 6905 | COMMON_INTERCEPTOR_READ_RANGE(ctx, file, REAL(strlen)(file) + 1); | ||
| 6906 | return REAL(acct)(file); | ||
| 6907 | } | ||
| 6908 | #define INIT_ACCT COMMON_INTERCEPT_FUNCTION(acct) | ||
| 6909 | #else | ||
| 6910 | #define INIT_ACCT | ||
| 6911 | #endif | ||
| 6912 | |||
| 6913 | #if SANITIZER_INTERCEPT_USER_FROM_UID | ||
| 6914 | INTERCEPTOR(const char *, user_from_uid, u32 uid, int nouser) { | ||
| 6915 | void *ctx; | ||
| 6916 | const char *user; | ||
| 6917 | COMMON_INTERCEPTOR_ENTER(ctx, user_from_uid, uid, nouser); | ||
| 6918 | user = REAL(user_from_uid)(uid, nouser); | ||
| 6919 | if (user) | ||
| 6920 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, user, REAL(strlen)(user) + 1); | ||
| 6921 | return user; | ||
| 6922 | } | ||
| 6923 | #define INIT_USER_FROM_UID COMMON_INTERCEPT_FUNCTION(user_from_uid) | ||
| 6924 | #else | ||
| 6925 | #define INIT_USER_FROM_UID | ||
| 6926 | #endif | ||
| 6927 | |||
| 6928 | #if SANITIZER_INTERCEPT_UID_FROM_USER | ||
| 6929 | INTERCEPTOR(int, uid_from_user, const char *name, u32 *uid) { | ||
| 6930 | void *ctx; | ||
| 6931 | int res; | ||
| 6932 | COMMON_INTERCEPTOR_ENTER(ctx, uid_from_user, name, uid); | ||
| 6933 | if (name) | ||
| 6934 | COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 6935 | res = REAL(uid_from_user)(name, uid); | ||
| 6936 | if (uid) | ||
| 6937 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, uid, sizeof(*uid)); | ||
| 6938 | return res; | ||
| 6939 | } | ||
| 6940 | #define INIT_UID_FROM_USER COMMON_INTERCEPT_FUNCTION(uid_from_user) | ||
| 6941 | #else | ||
| 6942 | #define INIT_UID_FROM_USER | ||
| 6943 | #endif | ||
| 6944 | |||
| 6945 | #if SANITIZER_INTERCEPT_GROUP_FROM_GID | ||
| 6946 | INTERCEPTOR(const char *, group_from_gid, u32 gid, int nogroup) { | ||
| 6947 | void *ctx; | ||
| 6948 | const char *group; | ||
| 6949 | COMMON_INTERCEPTOR_ENTER(ctx, group_from_gid, gid, nogroup); | ||
| 6950 | group = REAL(group_from_gid)(gid, nogroup); | ||
| 6951 | if (group) | ||
| 6952 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, group, REAL(strlen)(group) + 1); | ||
| 6953 | return group; | ||
| 6954 | } | ||
| 6955 | #define INIT_GROUP_FROM_GID COMMON_INTERCEPT_FUNCTION(group_from_gid) | ||
| 6956 | #else | ||
| 6957 | #define INIT_GROUP_FROM_GID | ||
| 6958 | #endif | ||
| 6959 | |||
| 6960 | #if SANITIZER_INTERCEPT_GID_FROM_GROUP | ||
| 6961 | INTERCEPTOR(int, gid_from_group, const char *group, u32 *gid) { | ||
| 6962 | void *ctx; | ||
| 6963 | int res; | ||
| 6964 | COMMON_INTERCEPTOR_ENTER(ctx, gid_from_group, group, gid); | ||
| 6965 | if (group) | ||
| 6966 | COMMON_INTERCEPTOR_READ_RANGE(ctx, group, REAL(strlen)(group) + 1); | ||
| 6967 | res = REAL(gid_from_group)(group, gid); | ||
| 6968 | if (gid) | ||
| 6969 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, gid, sizeof(*gid)); | ||
| 6970 | return res; | ||
| 6971 | } | ||
| 6972 | #define INIT_GID_FROM_GROUP COMMON_INTERCEPT_FUNCTION(gid_from_group) | ||
| 6973 | #else | ||
| 6974 | #define INIT_GID_FROM_GROUP | ||
| 6975 | #endif | ||
| 6976 | |||
| 6977 | #if SANITIZER_INTERCEPT_ACCESS | ||
| 6978 | INTERCEPTOR(int, access, const char *path, int mode) { | ||
| 6979 | void *ctx; | ||
| 6980 | COMMON_INTERCEPTOR_ENTER(ctx, access, path, mode); | ||
| 6981 | if (path) | ||
| 6982 | COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 6983 | return REAL(access)(path, mode); | ||
| 6984 | } | ||
| 6985 | #define INIT_ACCESS COMMON_INTERCEPT_FUNCTION(access) | ||
| 6986 | #else | ||
| 6987 | #define INIT_ACCESS | ||
| 6988 | #endif | ||
| 6989 | |||
| 6990 | #if SANITIZER_INTERCEPT_FACCESSAT | ||
| 6991 | INTERCEPTOR(int, faccessat, int fd, const char *path, int mode, int flags) { | ||
| 6992 | void *ctx; | ||
| 6993 | COMMON_INTERCEPTOR_ENTER(ctx, faccessat, fd, path, mode, flags); | ||
| 6994 | if (path) | ||
| 6995 | COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 6996 | return REAL(faccessat)(fd, path, mode, flags); | ||
| 6997 | } | ||
| 6998 | #define INIT_FACCESSAT COMMON_INTERCEPT_FUNCTION(faccessat) | ||
| 6999 | #else | ||
| 7000 | #define INIT_FACCESSAT | ||
| 7001 | #endif | ||
| 7002 | |||
| 7003 | #if SANITIZER_INTERCEPT_GETGROUPLIST | ||
| 7004 | INTERCEPTOR(int, getgrouplist, const char *name, u32 basegid, u32 *groups, | ||
| 7005 | int *ngroups) { | ||
| 7006 | void *ctx; | ||
| 7007 | int res; | ||
| 7008 | COMMON_INTERCEPTOR_ENTER(ctx, getgrouplist, name, basegid, groups, ngroups); | ||
| 7009 | if (name) | ||
| 7010 | COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 7011 | if (ngroups) | ||
| 7012 | COMMON_INTERCEPTOR_READ_RANGE(ctx, ngroups, sizeof(*ngroups)); | ||
| 7013 | res = REAL(getgrouplist)(name, basegid, groups, ngroups); | ||
| 7014 | if (!res && groups && ngroups) { | ||
| 7015 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, groups, sizeof(*groups) * (*ngroups)); | ||
| 7016 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ngroups, sizeof(*ngroups)); | ||
| 7017 | } | ||
| 7018 | return res; | ||
| 7019 | } | ||
| 7020 | |||
| 7021 | #define INIT_GETGROUPLIST COMMON_INTERCEPT_FUNCTION(getgrouplist); | ||
| 7022 | #else | ||
| 7023 | #define INIT_GETGROUPLIST | ||
| 7024 | #endif | ||
| 7025 | |||
| 7026 | #if SANITIZER_INTERCEPT_GETGROUPMEMBERSHIP | ||
| 7027 | INTERCEPTOR(int, getgroupmembership, const char *name, u32 basegid, u32 *groups, | ||
| 7028 | int maxgrp, int *ngroups) { | ||
| 7029 | void *ctx; | ||
| 7030 | int res; | ||
| 7031 | COMMON_INTERCEPTOR_ENTER(ctx, getgroupmembership, name, basegid, groups, | ||
| 7032 | maxgrp, ngroups); | ||
| 7033 | if (name) | ||
| 7034 | COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 7035 | res = REAL(getgroupmembership)(name, basegid, groups, maxgrp, ngroups); | ||
| 7036 | if (!res && groups && ngroups) { | ||
| 7037 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, groups, sizeof(*groups) * (*ngroups)); | ||
| 7038 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ngroups, sizeof(*ngroups)); | ||
| 7039 | } | ||
| 7040 | return res; | ||
| 7041 | } | ||
| 7042 | |||
| 7043 | #define INIT_GETGROUPMEMBERSHIP COMMON_INTERCEPT_FUNCTION(getgroupmembership); | ||
| 7044 | #else | ||
| 7045 | #define INIT_GETGROUPMEMBERSHIP | ||
| 7046 | #endif | ||
| 7047 | |||
| 7048 | #if SANITIZER_INTERCEPT_READLINK | ||
| 7049 | INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) { | ||
| 7050 | void* ctx; | ||
| 7051 | COMMON_INTERCEPTOR_ENTER(ctx, readlink, path, buf, bufsiz); | ||
| 7052 | COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 7053 | SSIZE_T res = REAL(readlink)(path, buf, bufsiz); | ||
| 7054 | if (res > 0) | ||
| 7055 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res); | ||
| 7056 | return res; | ||
| 7057 | } | ||
| 7058 | |||
| 7059 | #define INIT_READLINK COMMON_INTERCEPT_FUNCTION(readlink) | ||
| 7060 | #else | ||
| 7061 | #define INIT_READLINK | ||
| 7062 | #endif | ||
| 7063 | |||
| 7064 | #if SANITIZER_INTERCEPT_READLINKAT | ||
| 7065 | INTERCEPTOR(SSIZE_T, readlinkat, int dirfd, const char *path, char *buf, | ||
| 7066 | SIZE_T bufsiz) { | ||
| 7067 | void* ctx; | ||
| 7068 | COMMON_INTERCEPTOR_ENTER(ctx, readlinkat, dirfd, path, buf, bufsiz); | ||
| 7069 | COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 7070 | SSIZE_T res = REAL(readlinkat)(dirfd, path, buf, bufsiz); | ||
| 7071 | if (res > 0) | ||
| 7072 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res); | ||
| 7073 | return res; | ||
| 7074 | } | ||
| 7075 | |||
| 7076 | #define INIT_READLINKAT COMMON_INTERCEPT_FUNCTION(readlinkat) | ||
| 7077 | #else | ||
| 7078 | #define INIT_READLINKAT | ||
| 7079 | #endif | ||
| 7080 | |||
| 7081 | #if SANITIZER_INTERCEPT_NAME_TO_HANDLE_AT | ||
| 7082 | INTERCEPTOR(int, name_to_handle_at, int dirfd, const char *pathname, | ||
| 7083 | struct file_handle *handle, int *mount_id, int flags) { | ||
| 7084 | void* ctx; | ||
| 7085 | COMMON_INTERCEPTOR_ENTER(ctx, name_to_handle_at, dirfd, pathname, handle, | ||
| 7086 | mount_id, flags); | ||
| 7087 | COMMON_INTERCEPTOR_READ_RANGE(ctx, pathname, REAL(strlen)(pathname) + 1); | ||
| 7088 | |||
| 7089 | __sanitizer_file_handle *sanitizer_handle = | ||
| 7090 | reinterpret_cast<__sanitizer_file_handle*>(handle); | ||
| 7091 | COMMON_INTERCEPTOR_READ_RANGE( | ||
| 7092 | ctx, &sanitizer_handle->handle_bytes, | ||
| 7093 | sizeof(sanitizer_handle->handle_bytes)); | ||
| 7094 | |||
| 7095 | int res = REAL(name_to_handle_at)(dirfd, pathname, handle, mount_id, flags); | ||
| 7096 | if (!res) { | ||
| 7097 | COMMON_INTERCEPTOR_WRITE_RANGE( | ||
| 7098 | ctx, &sanitizer_handle->handle_bytes, | ||
| 7099 | sizeof(sanitizer_handle->handle_bytes)); | ||
| 7100 | COMMON_INTERCEPTOR_WRITE_RANGE( | ||
| 7101 | ctx, &sanitizer_handle->handle_type, | ||
| 7102 | sizeof(sanitizer_handle->handle_type)); | ||
| 7103 | COMMON_INTERCEPTOR_WRITE_RANGE( | ||
| 7104 | ctx, &sanitizer_handle->f_handle, sanitizer_handle->handle_bytes); | ||
| 7105 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mount_id, sizeof(*mount_id)); | ||
| 7106 | } | ||
| 7107 | return res; | ||
| 7108 | } | ||
| 7109 | |||
| 7110 | #define INIT_NAME_TO_HANDLE_AT COMMON_INTERCEPT_FUNCTION(name_to_handle_at) | ||
| 7111 | #else | ||
| 7112 | #define INIT_NAME_TO_HANDLE_AT | ||
| 7113 | #endif | ||
| 7114 | |||
| 7115 | #if SANITIZER_INTERCEPT_OPEN_BY_HANDLE_AT | ||
| 7116 | INTERCEPTOR(int, open_by_handle_at, int mount_fd, struct file_handle* handle, | ||
| 7117 | int flags) { | ||
| 7118 | void* ctx; | ||
| 7119 | COMMON_INTERCEPTOR_ENTER(ctx, open_by_handle_at, mount_fd, handle, flags); | ||
| 7120 | |||
| 7121 | __sanitizer_file_handle *sanitizer_handle = | ||
| 7122 | reinterpret_cast<__sanitizer_file_handle*>(handle); | ||
| 7123 | COMMON_INTERCEPTOR_READ_RANGE( | ||
| 7124 | ctx, &sanitizer_handle->handle_bytes, | ||
| 7125 | sizeof(sanitizer_handle->handle_bytes)); | ||
| 7126 | COMMON_INTERCEPTOR_READ_RANGE( | ||
| 7127 | ctx, &sanitizer_handle->handle_type, | ||
| 7128 | sizeof(sanitizer_handle->handle_type)); | ||
| 7129 | COMMON_INTERCEPTOR_READ_RANGE( | ||
| 7130 | ctx, &sanitizer_handle->f_handle, sanitizer_handle->handle_bytes); | ||
| 7131 | |||
| 7132 | return REAL(open_by_handle_at)(mount_fd, handle, flags); | ||
| 7133 | } | ||
| 7134 | |||
| 7135 | #define INIT_OPEN_BY_HANDLE_AT COMMON_INTERCEPT_FUNCTION(open_by_handle_at) | ||
| 7136 | #else | ||
| 7137 | #define INIT_OPEN_BY_HANDLE_AT | ||
| 7138 | #endif | ||
| 7139 | |||
| 7140 | #if SANITIZER_INTERCEPT_STRLCPY | ||
| 7141 | INTERCEPTOR(SIZE_T, strlcpy, char *dst, char *src, SIZE_T size) { | ||
| 7142 | void *ctx; | ||
| 7143 | SIZE_T res; | ||
| 7144 | COMMON_INTERCEPTOR_ENTER(ctx, strlcpy, dst, src, size); | ||
| 7145 | if (src) { | ||
| 7146 | // Keep strnlen as macro argument, as macro may ignore it. | ||
| 7147 | COMMON_INTERCEPTOR_READ_STRING( | ||
| 7148 | ctx, src, Min(internal_strnlen(src, size), size - 1) + 1); | ||
| 7149 | } | ||
| 7150 | res = REAL(strlcpy)(dst, src, size); | ||
| 7151 | COMMON_INTERCEPTOR_COPY_STRING(ctx, dst, src, REAL(strlen)(dst) + 1); | ||
| 7152 | return res; | ||
| 7153 | } | ||
| 7154 | |||
| 7155 | INTERCEPTOR(SIZE_T, strlcat, char *dst, char *src, SIZE_T size) { | ||
| 7156 | void *ctx; | ||
| 7157 | SIZE_T len = 0; | ||
| 7158 | COMMON_INTERCEPTOR_ENTER(ctx, strlcat, dst, src, size); | ||
| 7159 | // src is checked in the strlcpy() interceptor | ||
| 7160 | if (dst) { | ||
| 7161 | len = internal_strnlen(dst, size); | ||
| 7162 | COMMON_INTERCEPTOR_READ_STRING(ctx, dst, Min(len, size - 1) + 1); | ||
| 7163 | } | ||
| 7164 | // Reuse the rest of the code in the strlcpy() interceptor | ||
| 7165 | return WRAP(strlcpy)(dst + len, src, size - len) + len; | ||
| 7166 | } | ||
| 7167 | #define INIT_STRLCPY \ | ||
| 7168 | COMMON_INTERCEPT_FUNCTION(strlcpy); \ | ||
| 7169 | COMMON_INTERCEPT_FUNCTION(strlcat); | ||
| 7170 | #else | ||
| 7171 | #define INIT_STRLCPY | ||
| 7172 | #endif | ||
| 7173 | |||
| 7174 | #if SANITIZER_INTERCEPT_MMAP | ||
| 7175 | INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags, int fd, | ||
| 7176 | OFF_T off) { | ||
| 7177 | void *ctx; | ||
| 7178 | if (common_flags()->detect_write_exec) | ||
| 7179 | ReportMmapWriteExec(prot); | ||
| 7180 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) | ||
| 7181 | return (void *)internal_mmap(addr, sz, prot, flags, fd, off); | ||
| 7182 | COMMON_INTERCEPTOR_ENTER(ctx, mmap, addr, sz, prot, flags, fd, off); | ||
| 7183 | COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd, off); | ||
| 7184 | } | ||
| 7185 | |||
| 7186 | INTERCEPTOR(int, mprotect, void *addr, SIZE_T sz, int prot) { | ||
| 7187 | void *ctx; | ||
| 7188 | if (common_flags()->detect_write_exec) | ||
| 7189 | ReportMmapWriteExec(prot); | ||
| 7190 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) | ||
| 7191 | return (int)internal_mprotect(addr, sz, prot); | ||
| 7192 | COMMON_INTERCEPTOR_ENTER(ctx, mprotect, addr, sz, prot); | ||
| 7193 | MprotectMallocZones(addr, prot); | ||
| 7194 | return REAL(mprotect)(addr, sz, prot); | ||
| 7195 | } | ||
| 7196 | #define INIT_MMAP \ | ||
| 7197 | COMMON_INTERCEPT_FUNCTION(mmap); \ | ||
| 7198 | COMMON_INTERCEPT_FUNCTION(mprotect); | ||
| 7199 | #else | ||
| 7200 | #define INIT_MMAP | ||
| 7201 | #endif | ||
| 7202 | |||
| 7203 | #if SANITIZER_INTERCEPT_MMAP64 | ||
| 7204 | INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags, int fd, | ||
| 7205 | OFF64_T off) { | ||
| 7206 | void *ctx; | ||
| 7207 | if (common_flags()->detect_write_exec) | ||
| 7208 | ReportMmapWriteExec(prot); | ||
| 7209 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) | ||
| 7210 | return (void *)internal_mmap(addr, sz, prot, flags, fd, off); | ||
| 7211 | COMMON_INTERCEPTOR_ENTER(ctx, mmap64, addr, sz, prot, flags, fd, off); | ||
| 7212 | COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap64, addr, sz, prot, flags, fd, off); | ||
| 7213 | } | ||
| 7214 | #define INIT_MMAP64 COMMON_INTERCEPT_FUNCTION(mmap64); | ||
| 7215 | #else | ||
| 7216 | #define INIT_MMAP64 | ||
| 7217 | #endif | ||
| 7218 | |||
| 7219 | #if SANITIZER_INTERCEPT_DEVNAME | ||
| 7220 | INTERCEPTOR(char *, devname, u64 dev, u32 type) { | ||
| 7221 | void *ctx; | ||
| 7222 | char *name; | ||
| 7223 | COMMON_INTERCEPTOR_ENTER(ctx, devname, dev, type); | ||
| 7224 | name = REAL(devname)(dev, type); | ||
| 7225 | if (name) | ||
| 7226 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 7227 | return name; | ||
| 7228 | } | ||
| 7229 | #define INIT_DEVNAME COMMON_INTERCEPT_FUNCTION(devname); | ||
| 7230 | #else | ||
| 7231 | #define INIT_DEVNAME | ||
| 7232 | #endif | ||
| 7233 | |||
| 7234 | #if SANITIZER_INTERCEPT_DEVNAME_R | ||
| 7235 | #if SANITIZER_NETBSD | ||
| 7236 | #define DEVNAME_R_RETTYPE int | ||
| 7237 | #define DEVNAME_R_SUCCESS(x) (!(x)) | ||
| 7238 | #else | ||
| 7239 | #define DEVNAME_R_RETTYPE char* | ||
| 7240 | #define DEVNAME_R_SUCCESS(x) (x) | ||
| 7241 | #endif | ||
| 7242 | INTERCEPTOR(DEVNAME_R_RETTYPE, devname_r, u64 dev, u32 type, char *path, | ||
| 7243 | uptr len) { | ||
| 7244 | void *ctx; | ||
| 7245 | COMMON_INTERCEPTOR_ENTER(ctx, devname_r, dev, type, path, len); | ||
| 7246 | DEVNAME_R_RETTYPE res = REAL(devname_r)(dev, type, path, len); | ||
| 7247 | if (DEVNAME_R_SUCCESS(res)) | ||
| 7248 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 7249 | return res; | ||
| 7250 | } | ||
| 7251 | #define INIT_DEVNAME_R COMMON_INTERCEPT_FUNCTION(devname_r); | ||
| 7252 | #else | ||
| 7253 | #define INIT_DEVNAME_R | ||
| 7254 | #endif | ||
| 7255 | |||
| 7256 | #if SANITIZER_INTERCEPT_FGETLN | ||
| 7257 | INTERCEPTOR(char *, fgetln, __sanitizer_FILE *stream, SIZE_T *len) { | ||
| 7258 | void *ctx; | ||
| 7259 | COMMON_INTERCEPTOR_ENTER(ctx, fgetln, stream, len); | ||
| 7260 | char *str = REAL(fgetln)(stream, len); | ||
| 7261 | if (str && len) { | ||
| 7262 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, len, sizeof(*len)); | ||
| 7263 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, *len); | ||
| 7264 | } | ||
| 7265 | return str; | ||
| 7266 | } | ||
| 7267 | #define INIT_FGETLN COMMON_INTERCEPT_FUNCTION(fgetln) | ||
| 7268 | #else | ||
| 7269 | #define INIT_FGETLN | ||
| 7270 | #endif | ||
| 7271 | |||
| 7272 | #if SANITIZER_INTERCEPT_STRMODE | ||
| 7273 | INTERCEPTOR(void, strmode, u32 mode, char *bp) { | ||
| 7274 | void *ctx; | ||
| 7275 | COMMON_INTERCEPTOR_ENTER(ctx, strmode, mode, bp); | ||
| 7276 | REAL(strmode)(mode, bp); | ||
| 7277 | if (bp) | ||
| 7278 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, bp, REAL(strlen)(bp) + 1); | ||
| 7279 | } | ||
| 7280 | #define INIT_STRMODE COMMON_INTERCEPT_FUNCTION(strmode) | ||
| 7281 | #else | ||
| 7282 | #define INIT_STRMODE | ||
| 7283 | #endif | ||
| 7284 | |||
| 7285 | #if SANITIZER_INTERCEPT_TTYENT | ||
| 7286 | INTERCEPTOR(struct __sanitizer_ttyent *, getttyent, void) { | ||
| 7287 | void *ctx; | ||
| 7288 | COMMON_INTERCEPTOR_ENTER(ctx, getttyent); | ||
| 7289 | struct __sanitizer_ttyent *ttyent = REAL(getttyent)(); | ||
| 7290 | if (ttyent) | ||
| 7291 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ttyent, struct_ttyent_sz); | ||
| 7292 | return ttyent; | ||
| 7293 | } | ||
| 7294 | INTERCEPTOR(struct __sanitizer_ttyent *, getttynam, char *name) { | ||
| 7295 | void *ctx; | ||
| 7296 | COMMON_INTERCEPTOR_ENTER(ctx, getttynam, name); | ||
| 7297 | if (name) | ||
| 7298 | COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 7299 | struct __sanitizer_ttyent *ttyent = REAL(getttynam)(name); | ||
| 7300 | if (ttyent) | ||
| 7301 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ttyent, struct_ttyent_sz); | ||
| 7302 | return ttyent; | ||
| 7303 | } | ||
| 7304 | INTERCEPTOR(int, setttyentpath, char *path) { | ||
| 7305 | void *ctx; | ||
| 7306 | COMMON_INTERCEPTOR_ENTER(ctx, setttyentpath, path); | ||
| 7307 | if (path) | ||
| 7308 | COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 7309 | return REAL(setttyentpath)(path); | ||
| 7310 | } | ||
| 7311 | #define INIT_TTYENT \ | ||
| 7312 | COMMON_INTERCEPT_FUNCTION(getttyent); \ | ||
| 7313 | COMMON_INTERCEPT_FUNCTION(getttynam); \ | ||
| 7314 | COMMON_INTERCEPT_FUNCTION(setttyentpath) | ||
| 7315 | #else | ||
| 7316 | #define INIT_TTYENT | ||
| 7317 | #endif | ||
| 7318 | |||
| 7319 | #if SANITIZER_INTERCEPT_PROTOENT | ||
| 7320 | static void write_protoent(void *ctx, struct __sanitizer_protoent *p) { | ||
| 7321 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); | ||
| 7322 | |||
| 7323 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1); | ||
| 7324 | |||
| 7325 | SIZE_T pp_size = 1; // One handles the trailing \0 | ||
| 7326 | |||
| 7327 | for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size) | ||
| 7328 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1); | ||
| 7329 | |||
| 7330 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases, | ||
| 7331 | pp_size * sizeof(char **)); | ||
| 7332 | } | ||
| 7333 | |||
| 7334 | INTERCEPTOR(struct __sanitizer_protoent *, getprotoent) { | ||
| 7335 | void *ctx; | ||
| 7336 | COMMON_INTERCEPTOR_ENTER(ctx, getprotoent); | ||
| 7337 | struct __sanitizer_protoent *p = REAL(getprotoent)(); | ||
| 7338 | if (p) | ||
| 7339 | write_protoent(ctx, p); | ||
| 7340 | return p; | ||
| 7341 | } | ||
| 7342 | |||
| 7343 | INTERCEPTOR(struct __sanitizer_protoent *, getprotobyname, const char *name) { | ||
| 7344 | void *ctx; | ||
| 7345 | COMMON_INTERCEPTOR_ENTER(ctx, getprotobyname, name); | ||
| 7346 | if (name) | ||
| 7347 | COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 7348 | struct __sanitizer_protoent *p = REAL(getprotobyname)(name); | ||
| 7349 | if (p) | ||
| 7350 | write_protoent(ctx, p); | ||
| 7351 | return p; | ||
| 7352 | } | ||
| 7353 | |||
| 7354 | INTERCEPTOR(struct __sanitizer_protoent *, getprotobynumber, int proto) { | ||
| 7355 | void *ctx; | ||
| 7356 | COMMON_INTERCEPTOR_ENTER(ctx, getprotobynumber, proto); | ||
| 7357 | struct __sanitizer_protoent *p = REAL(getprotobynumber)(proto); | ||
| 7358 | if (p) | ||
| 7359 | write_protoent(ctx, p); | ||
| 7360 | return p; | ||
| 7361 | } | ||
| 7362 | #define INIT_PROTOENT \ | ||
| 7363 | COMMON_INTERCEPT_FUNCTION(getprotoent); \ | ||
| 7364 | COMMON_INTERCEPT_FUNCTION(getprotobyname); \ | ||
| 7365 | COMMON_INTERCEPT_FUNCTION(getprotobynumber) | ||
| 7366 | #else | ||
| 7367 | #define INIT_PROTOENT | ||
| 7368 | #endif | ||
| 7369 | |||
| 7370 | #if SANITIZER_INTERCEPT_PROTOENT_R | ||
| 7371 | INTERCEPTOR(int, getprotoent_r, struct __sanitizer_protoent *result_buf, | ||
| 7372 | char *buf, SIZE_T buflen, struct __sanitizer_protoent **result) { | ||
| 7373 | void *ctx; | ||
| 7374 | COMMON_INTERCEPTOR_ENTER(ctx, getprotoent_r, result_buf, buf, buflen, | ||
| 7375 | result); | ||
| 7376 | int res = REAL(getprotoent_r)(result_buf, buf, buflen, result); | ||
| 7377 | |||
| 7378 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof *result); | ||
| 7379 | if (!res && *result) | ||
| 7380 | write_protoent(ctx, *result); | ||
| 7381 | return res; | ||
| 7382 | } | ||
| 7383 | |||
| 7384 | INTERCEPTOR(int, getprotobyname_r, const char *name, | ||
| 7385 | struct __sanitizer_protoent *result_buf, char *buf, SIZE_T buflen, | ||
| 7386 | struct __sanitizer_protoent **result) { | ||
| 7387 | void *ctx; | ||
| 7388 | COMMON_INTERCEPTOR_ENTER(ctx, getprotobyname_r, name, result_buf, buf, | ||
| 7389 | buflen, result); | ||
| 7390 | if (name) | ||
| 7391 | COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 7392 | int res = REAL(getprotobyname_r)(name, result_buf, buf, buflen, result); | ||
| 7393 | |||
| 7394 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof *result); | ||
| 7395 | if (!res && *result) | ||
| 7396 | write_protoent(ctx, *result); | ||
| 7397 | return res; | ||
| 7398 | } | ||
| 7399 | |||
| 7400 | INTERCEPTOR(int, getprotobynumber_r, int num, | ||
| 7401 | struct __sanitizer_protoent *result_buf, char *buf, | ||
| 7402 | SIZE_T buflen, struct __sanitizer_protoent **result) { | ||
| 7403 | void *ctx; | ||
| 7404 | COMMON_INTERCEPTOR_ENTER(ctx, getprotobynumber_r, num, result_buf, buf, | ||
| 7405 | buflen, result); | ||
| 7406 | int res = REAL(getprotobynumber_r)(num, result_buf, buf, buflen, result); | ||
| 7407 | |||
| 7408 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof *result); | ||
| 7409 | if (!res && *result) | ||
| 7410 | write_protoent(ctx, *result); | ||
| 7411 | return res; | ||
| 7412 | } | ||
| 7413 | |||
| 7414 | #define INIT_PROTOENT_R \ | ||
| 7415 | COMMON_INTERCEPT_FUNCTION(getprotoent_r); \ | ||
| 7416 | COMMON_INTERCEPT_FUNCTION(getprotobyname_r); \ | ||
| 7417 | COMMON_INTERCEPT_FUNCTION(getprotobynumber_r); | ||
| 7418 | #else | ||
| 7419 | #define INIT_PROTOENT_R | ||
| 7420 | #endif | ||
| 7421 | |||
| 7422 | #if SANITIZER_INTERCEPT_NETENT | ||
| 7423 | INTERCEPTOR(struct __sanitizer_netent *, getnetent) { | ||
| 7424 | void *ctx; | ||
| 7425 | COMMON_INTERCEPTOR_ENTER(ctx, getnetent); | ||
| 7426 | struct __sanitizer_netent *n = REAL(getnetent)(); | ||
| 7427 | if (n) { | ||
| 7428 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); | ||
| 7429 | |||
| 7430 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_name, REAL(strlen)(n->n_name) + 1); | ||
| 7431 | |||
| 7432 | SIZE_T nn_size = 1; // One handles the trailing \0 | ||
| 7433 | |||
| 7434 | for (char **nn = n->n_aliases; *nn; ++nn, ++nn_size) | ||
| 7435 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *nn, REAL(strlen)(*nn) + 1); | ||
| 7436 | |||
| 7437 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_aliases, | ||
| 7438 | nn_size * sizeof(char **)); | ||
| 7439 | } | ||
| 7440 | return n; | ||
| 7441 | } | ||
| 7442 | |||
| 7443 | INTERCEPTOR(struct __sanitizer_netent *, getnetbyname, const char *name) { | ||
| 7444 | void *ctx; | ||
| 7445 | COMMON_INTERCEPTOR_ENTER(ctx, getnetbyname, name); | ||
| 7446 | if (name) | ||
| 7447 | COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 7448 | struct __sanitizer_netent *n = REAL(getnetbyname)(name); | ||
| 7449 | if (n) { | ||
| 7450 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); | ||
| 7451 | |||
| 7452 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_name, REAL(strlen)(n->n_name) + 1); | ||
| 7453 | |||
| 7454 | SIZE_T nn_size = 1; // One handles the trailing \0 | ||
| 7455 | |||
| 7456 | for (char **nn = n->n_aliases; *nn; ++nn, ++nn_size) | ||
| 7457 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *nn, REAL(strlen)(*nn) + 1); | ||
| 7458 | |||
| 7459 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_aliases, | ||
| 7460 | nn_size * sizeof(char **)); | ||
| 7461 | } | ||
| 7462 | return n; | ||
| 7463 | } | ||
| 7464 | |||
| 7465 | INTERCEPTOR(struct __sanitizer_netent *, getnetbyaddr, u32 net, int type) { | ||
| 7466 | void *ctx; | ||
| 7467 | COMMON_INTERCEPTOR_ENTER(ctx, getnetbyaddr, net, type); | ||
| 7468 | struct __sanitizer_netent *n = REAL(getnetbyaddr)(net, type); | ||
| 7469 | if (n) { | ||
| 7470 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); | ||
| 7471 | |||
| 7472 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_name, REAL(strlen)(n->n_name) + 1); | ||
| 7473 | |||
| 7474 | SIZE_T nn_size = 1; // One handles the trailing \0 | ||
| 7475 | |||
| 7476 | for (char **nn = n->n_aliases; *nn; ++nn, ++nn_size) | ||
| 7477 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *nn, REAL(strlen)(*nn) + 1); | ||
| 7478 | |||
| 7479 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n->n_aliases, | ||
| 7480 | nn_size * sizeof(char **)); | ||
| 7481 | } | ||
| 7482 | return n; | ||
| 7483 | } | ||
| 7484 | #define INIT_NETENT \ | ||
| 7485 | COMMON_INTERCEPT_FUNCTION(getnetent); \ | ||
| 7486 | COMMON_INTERCEPT_FUNCTION(getnetbyname); \ | ||
| 7487 | COMMON_INTERCEPT_FUNCTION(getnetbyaddr) | ||
| 7488 | #else | ||
| 7489 | #define INIT_NETENT | ||
| 7490 | #endif | ||
| 7491 | |||
| 7492 | #if SANITIZER_INTERCEPT_GETMNTINFO | ||
| 7493 | INTERCEPTOR(int, getmntinfo, void **mntbufp, int flags) { | ||
| 7494 | void *ctx; | ||
| 7495 | COMMON_INTERCEPTOR_ENTER(ctx, getmntinfo, mntbufp, flags); | ||
| 7496 | int cnt = REAL(getmntinfo)(mntbufp, flags); | ||
| 7497 | if (cnt > 0 && mntbufp) { | ||
| 7498 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mntbufp, sizeof(void *)); | ||
| 7499 | if (*mntbufp) | ||
| 7500 | #if SANITIZER_NETBSD | ||
| 7501 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *mntbufp, cnt * struct_statvfs_sz); | ||
| 7502 | #else | ||
| 7503 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *mntbufp, cnt * struct_statfs_sz); | ||
| 7504 | #endif | ||
| 7505 | } | ||
| 7506 | return cnt; | ||
| 7507 | } | ||
| 7508 | #define INIT_GETMNTINFO COMMON_INTERCEPT_FUNCTION(getmntinfo) | ||
| 7509 | #else | ||
| 7510 | #define INIT_GETMNTINFO | ||
| 7511 | #endif | ||
| 7512 | |||
| 7513 | #if SANITIZER_INTERCEPT_MI_VECTOR_HASH | ||
| 7514 | INTERCEPTOR(void, mi_vector_hash, const void *key, SIZE_T len, u32 seed, | ||
| 7515 | u32 hashes[3]) { | ||
| 7516 | void *ctx; | ||
| 7517 | COMMON_INTERCEPTOR_ENTER(ctx, mi_vector_hash, key, len, seed, hashes); | ||
| 7518 | if (key) | ||
| 7519 | COMMON_INTERCEPTOR_READ_RANGE(ctx, key, len); | ||
| 7520 | REAL(mi_vector_hash)(key, len, seed, hashes); | ||
| 7521 | if (hashes) | ||
| 7522 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hashes, sizeof(hashes[0]) * 3); | ||
| 7523 | } | ||
| 7524 | #define INIT_MI_VECTOR_HASH COMMON_INTERCEPT_FUNCTION(mi_vector_hash) | ||
| 7525 | #else | ||
| 7526 | #define INIT_MI_VECTOR_HASH | ||
| 7527 | #endif | ||
| 7528 | |||
| 7529 | #if SANITIZER_INTERCEPT_SETVBUF | ||
| 7530 | INTERCEPTOR(int, setvbuf, __sanitizer_FILE *stream, char *buf, int mode, | ||
| 7531 | SIZE_T size) { | ||
| 7532 | void *ctx; | ||
| 7533 | COMMON_INTERCEPTOR_ENTER(ctx, setvbuf, stream, buf, mode, size); | ||
| 7534 | int ret = REAL(setvbuf)(stream, buf, mode, size); | ||
| 7535 | if (buf) | ||
| 7536 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, size); | ||
| 7537 | if (stream) | ||
| 7538 | unpoison_file(stream); | ||
| 7539 | return ret; | ||
| 7540 | } | ||
| 7541 | |||
| 7542 | INTERCEPTOR(void, setbuf, __sanitizer_FILE *stream, char *buf) { | ||
| 7543 | void *ctx; | ||
| 7544 | COMMON_INTERCEPTOR_ENTER(ctx, setbuf, stream, buf); | ||
| 7545 | REAL(setbuf)(stream, buf); | ||
| 7546 | if (buf) { | ||
| 7547 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer_bufsiz); | ||
| 7548 | } | ||
| 7549 | if (stream) | ||
| 7550 | unpoison_file(stream); | ||
| 7551 | } | ||
| 7552 | |||
| 7553 | INTERCEPTOR(void, setbuffer, __sanitizer_FILE *stream, char *buf, int mode) { | ||
| 7554 | void *ctx; | ||
| 7555 | COMMON_INTERCEPTOR_ENTER(ctx, setbuffer, stream, buf, mode); | ||
| 7556 | REAL(setbuffer)(stream, buf, mode); | ||
| 7557 | if (buf) { | ||
| 7558 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer_bufsiz); | ||
| 7559 | } | ||
| 7560 | if (stream) | ||
| 7561 | unpoison_file(stream); | ||
| 7562 | } | ||
| 7563 | |||
| 7564 | INTERCEPTOR(void, setlinebuf, __sanitizer_FILE *stream) { | ||
| 7565 | void *ctx; | ||
| 7566 | COMMON_INTERCEPTOR_ENTER(ctx, setlinebuf, stream); | ||
| 7567 | REAL(setlinebuf)(stream); | ||
| 7568 | if (stream) | ||
| 7569 | unpoison_file(stream); | ||
| 7570 | } | ||
| 7571 | #define INIT_SETVBUF COMMON_INTERCEPT_FUNCTION(setvbuf); \ | ||
| 7572 | COMMON_INTERCEPT_FUNCTION(setbuf); \ | ||
| 7573 | COMMON_INTERCEPT_FUNCTION(setbuffer); \ | ||
| 7574 | COMMON_INTERCEPT_FUNCTION(setlinebuf) | ||
| 7575 | #else | ||
| 7576 | #define INIT_SETVBUF | ||
| 7577 | #endif | ||
| 7578 | |||
| 7579 | #if SANITIZER_INTERCEPT_GETVFSSTAT | ||
| 7580 | INTERCEPTOR(int, getvfsstat, void *buf, SIZE_T bufsize, int flags) { | ||
| 7581 | void *ctx; | ||
| 7582 | COMMON_INTERCEPTOR_ENTER(ctx, getvfsstat, buf, bufsize, flags); | ||
| 7583 | int ret = REAL(getvfsstat)(buf, bufsize, flags); | ||
| 7584 | if (buf && ret > 0) | ||
| 7585 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, ret * struct_statvfs_sz); | ||
| 7586 | return ret; | ||
| 7587 | } | ||
| 7588 | #define INIT_GETVFSSTAT COMMON_INTERCEPT_FUNCTION(getvfsstat) | ||
| 7589 | #else | ||
| 7590 | #define INIT_GETVFSSTAT | ||
| 7591 | #endif | ||
| 7592 | |||
| 7593 | #if SANITIZER_INTERCEPT_REGEX | ||
| 7594 | INTERCEPTOR(int, regcomp, void *preg, const char *pattern, int cflags) { | ||
| 7595 | void *ctx; | ||
| 7596 | COMMON_INTERCEPTOR_ENTER(ctx, regcomp, preg, pattern, cflags); | ||
| 7597 | if (pattern) | ||
| 7598 | COMMON_INTERCEPTOR_READ_RANGE(ctx, pattern, REAL(strlen)(pattern) + 1); | ||
| 7599 | int res = REAL(regcomp)(preg, pattern, cflags); | ||
| 7600 | if (!res) | ||
| 7601 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, preg, struct_regex_sz); | ||
| 7602 | return res; | ||
| 7603 | } | ||
| 7604 | INTERCEPTOR(int, regexec, const void *preg, const char *string, SIZE_T nmatch, | ||
| 7605 | struct __sanitizer_regmatch *pmatch[], int eflags) { | ||
| 7606 | void *ctx; | ||
| 7607 | COMMON_INTERCEPTOR_ENTER(ctx, regexec, preg, string, nmatch, pmatch, eflags); | ||
| 7608 | if (preg) | ||
| 7609 | COMMON_INTERCEPTOR_READ_RANGE(ctx, preg, struct_regex_sz); | ||
| 7610 | if (string) | ||
| 7611 | COMMON_INTERCEPTOR_READ_RANGE(ctx, string, REAL(strlen)(string) + 1); | ||
| 7612 | int res = REAL(regexec)(preg, string, nmatch, pmatch, eflags); | ||
| 7613 | if (!res && pmatch) | ||
| 7614 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pmatch, nmatch * struct_regmatch_sz); | ||
| 7615 | return res; | ||
| 7616 | } | ||
| 7617 | INTERCEPTOR(SIZE_T, regerror, int errcode, const void *preg, char *errbuf, | ||
| 7618 | SIZE_T errbuf_size) { | ||
| 7619 | void *ctx; | ||
| 7620 | COMMON_INTERCEPTOR_ENTER(ctx, regerror, errcode, preg, errbuf, errbuf_size); | ||
| 7621 | if (preg) | ||
| 7622 | COMMON_INTERCEPTOR_READ_RANGE(ctx, preg, struct_regex_sz); | ||
| 7623 | SIZE_T res = REAL(regerror)(errcode, preg, errbuf, errbuf_size); | ||
| 7624 | if (errbuf) | ||
| 7625 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, errbuf, REAL(strlen)(errbuf) + 1); | ||
| 7626 | return res; | ||
| 7627 | } | ||
| 7628 | INTERCEPTOR(void, regfree, const void *preg) { | ||
| 7629 | void *ctx; | ||
| 7630 | COMMON_INTERCEPTOR_ENTER(ctx, regfree, preg); | ||
| 7631 | if (preg) | ||
| 7632 | COMMON_INTERCEPTOR_READ_RANGE(ctx, preg, struct_regex_sz); | ||
| 7633 | REAL(regfree)(preg); | ||
| 7634 | } | ||
| 7635 | #define INIT_REGEX \ | ||
| 7636 | COMMON_INTERCEPT_FUNCTION(regcomp); \ | ||
| 7637 | COMMON_INTERCEPT_FUNCTION(regexec); \ | ||
| 7638 | COMMON_INTERCEPT_FUNCTION(regerror); \ | ||
| 7639 | COMMON_INTERCEPT_FUNCTION(regfree); | ||
| 7640 | #else | ||
| 7641 | #define INIT_REGEX | ||
| 7642 | #endif | ||
| 7643 | |||
| 7644 | #if SANITIZER_INTERCEPT_REGEXSUB | ||
| 7645 | INTERCEPTOR(SSIZE_T, regnsub, char *buf, SIZE_T bufsiz, const char *sub, | ||
| 7646 | const struct __sanitizer_regmatch *rm, const char *str) { | ||
| 7647 | void *ctx; | ||
| 7648 | COMMON_INTERCEPTOR_ENTER(ctx, regnsub, buf, bufsiz, sub, rm, str); | ||
| 7649 | if (sub) | ||
| 7650 | COMMON_INTERCEPTOR_READ_RANGE(ctx, sub, REAL(strlen)(sub) + 1); | ||
| 7651 | // The implementation demands and hardcodes 10 elements | ||
| 7652 | if (rm) | ||
| 7653 | COMMON_INTERCEPTOR_READ_RANGE(ctx, rm, 10 * struct_regmatch_sz); | ||
| 7654 | if (str) | ||
| 7655 | COMMON_INTERCEPTOR_READ_RANGE(ctx, str, REAL(strlen)(str) + 1); | ||
| 7656 | SSIZE_T res = REAL(regnsub)(buf, bufsiz, sub, rm, str); | ||
| 7657 | if (res > 0 && buf) | ||
| 7658 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, REAL(strlen)(buf) + 1); | ||
| 7659 | return res; | ||
| 7660 | } | ||
| 7661 | INTERCEPTOR(SSIZE_T, regasub, char **buf, const char *sub, | ||
| 7662 | const struct __sanitizer_regmatch *rm, const char *sstr) { | ||
| 7663 | void *ctx; | ||
| 7664 | COMMON_INTERCEPTOR_ENTER(ctx, regasub, buf, sub, rm, sstr); | ||
| 7665 | if (sub) | ||
| 7666 | COMMON_INTERCEPTOR_READ_RANGE(ctx, sub, REAL(strlen)(sub) + 1); | ||
| 7667 | // Hardcode 10 elements as this is hardcoded size | ||
| 7668 | if (rm) | ||
| 7669 | COMMON_INTERCEPTOR_READ_RANGE(ctx, rm, 10 * struct_regmatch_sz); | ||
| 7670 | if (sstr) | ||
| 7671 | COMMON_INTERCEPTOR_READ_RANGE(ctx, sstr, REAL(strlen)(sstr) + 1); | ||
| 7672 | SSIZE_T res = REAL(regasub)(buf, sub, rm, sstr); | ||
| 7673 | if (res > 0 && buf) { | ||
| 7674 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sizeof(char *)); | ||
| 7675 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *buf, REAL(strlen)(*buf) + 1); | ||
| 7676 | } | ||
| 7677 | return res; | ||
| 7678 | } | ||
| 7679 | |||
| 7680 | #define INIT_REGEXSUB \ | ||
| 7681 | COMMON_INTERCEPT_FUNCTION(regnsub); \ | ||
| 7682 | COMMON_INTERCEPT_FUNCTION(regasub); | ||
| 7683 | #else | ||
| 7684 | #define INIT_REGEXSUB | ||
| 7685 | #endif | ||
| 7686 | |||
| 7687 | #if SANITIZER_INTERCEPT_FTS | ||
| 7688 | INTERCEPTOR(void *, fts_open, char *const *path_argv, int options, | ||
| 7689 | int (*compar)(void **, void **)) { | ||
| 7690 | void *ctx; | ||
| 7691 | COMMON_INTERCEPTOR_ENTER(ctx, fts_open, path_argv, options, compar); | ||
| 7692 | if (path_argv) { | ||
| 7693 | for (char *const *pa = path_argv; ; ++pa) { | ||
| 7694 | COMMON_INTERCEPTOR_READ_RANGE(ctx, pa, sizeof(char **)); | ||
| 7695 | if (!*pa) | ||
| 7696 | break; | ||
| 7697 | COMMON_INTERCEPTOR_READ_RANGE(ctx, *pa, REAL(strlen)(*pa) + 1); | ||
| 7698 | } | ||
| 7699 | } | ||
| 7700 | // TODO(kamil): handle compar callback | ||
| 7701 | void *fts = REAL(fts_open)(path_argv, options, compar); | ||
| 7702 | if (fts) | ||
| 7703 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, fts, struct_FTS_sz); | ||
| 7704 | return fts; | ||
| 7705 | } | ||
| 7706 | |||
| 7707 | INTERCEPTOR(void *, fts_read, void *ftsp) { | ||
| 7708 | void *ctx; | ||
| 7709 | COMMON_INTERCEPTOR_ENTER(ctx, fts_read, ftsp); | ||
| 7710 | if (ftsp) | ||
| 7711 | COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz); | ||
| 7712 | void *ftsent = REAL(fts_read)(ftsp); | ||
| 7713 | if (ftsent) | ||
| 7714 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ftsent, struct_FTSENT_sz); | ||
| 7715 | return ftsent; | ||
| 7716 | } | ||
| 7717 | |||
| 7718 | INTERCEPTOR(void *, fts_children, void *ftsp, int options) { | ||
| 7719 | void *ctx; | ||
| 7720 | COMMON_INTERCEPTOR_ENTER(ctx, fts_children, ftsp, options); | ||
| 7721 | if (ftsp) | ||
| 7722 | COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz); | ||
| 7723 | void *ftsent = REAL(fts_children)(ftsp, options); | ||
| 7724 | if (ftsent) | ||
| 7725 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ftsent, struct_FTSENT_sz); | ||
| 7726 | return ftsent; | ||
| 7727 | } | ||
| 7728 | |||
| 7729 | INTERCEPTOR(int, fts_set, void *ftsp, void *f, int options) { | ||
| 7730 | void *ctx; | ||
| 7731 | COMMON_INTERCEPTOR_ENTER(ctx, fts_set, ftsp, f, options); | ||
| 7732 | if (ftsp) | ||
| 7733 | COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz); | ||
| 7734 | if (f) | ||
| 7735 | COMMON_INTERCEPTOR_READ_RANGE(ctx, f, struct_FTSENT_sz); | ||
| 7736 | return REAL(fts_set)(ftsp, f, options); | ||
| 7737 | } | ||
| 7738 | |||
| 7739 | INTERCEPTOR(int, fts_close, void *ftsp) { | ||
| 7740 | void *ctx; | ||
| 7741 | COMMON_INTERCEPTOR_ENTER(ctx, fts_close, ftsp); | ||
| 7742 | if (ftsp) | ||
| 7743 | COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz); | ||
| 7744 | return REAL(fts_close)(ftsp); | ||
| 7745 | } | ||
| 7746 | #define INIT_FTS \ | ||
| 7747 | COMMON_INTERCEPT_FUNCTION(fts_open); \ | ||
| 7748 | COMMON_INTERCEPT_FUNCTION(fts_read); \ | ||
| 7749 | COMMON_INTERCEPT_FUNCTION(fts_children); \ | ||
| 7750 | COMMON_INTERCEPT_FUNCTION(fts_set); \ | ||
| 7751 | COMMON_INTERCEPT_FUNCTION(fts_close); | ||
| 7752 | #else | ||
| 7753 | #define INIT_FTS | ||
| 7754 | #endif | ||
| 7755 | |||
| 7756 | #if SANITIZER_INTERCEPT_SYSCTL | ||
| 7757 | INTERCEPTOR(int, sysctl, int *name, unsigned int namelen, void *oldp, | ||
| 7758 | SIZE_T *oldlenp, void *newp, SIZE_T newlen) { | ||
| 7759 | void *ctx; | ||
| 7760 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) | ||
| 7761 | return internal_sysctl(name, namelen, oldp, oldlenp, newp, newlen); | ||
| 7762 | COMMON_INTERCEPTOR_ENTER(ctx, sysctl, name, namelen, oldp, oldlenp, newp, | ||
| 7763 | newlen); | ||
| 7764 | if (name) | ||
| 7765 | COMMON_INTERCEPTOR_READ_RANGE(ctx, name, namelen * sizeof(*name)); | ||
| 7766 | if (oldlenp) | ||
| 7767 | COMMON_INTERCEPTOR_READ_RANGE(ctx, oldlenp, sizeof(*oldlenp)); | ||
| 7768 | if (newp && newlen) | ||
| 7769 | COMMON_INTERCEPTOR_READ_RANGE(ctx, newp, newlen); | ||
| 7770 | int res = REAL(sysctl)(name, namelen, oldp, oldlenp, newp, newlen); | ||
| 7771 | if (!res) { | ||
| 7772 | if (oldlenp) { | ||
| 7773 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldlenp, sizeof(*oldlenp)); | ||
| 7774 | if (oldp) | ||
| 7775 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldp, *oldlenp); | ||
| 7776 | } | ||
| 7777 | } | ||
| 7778 | return res; | ||
| 7779 | } | ||
| 7780 | |||
| 7781 | INTERCEPTOR(int, sysctlbyname, char *sname, void *oldp, SIZE_T *oldlenp, | ||
| 7782 | void *newp, SIZE_T newlen) { | ||
| 7783 | void *ctx; | ||
| 7784 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) | ||
| 7785 | return internal_sysctlbyname(sname, oldp, oldlenp, newp, newlen); | ||
| 7786 | COMMON_INTERCEPTOR_ENTER(ctx, sysctlbyname, sname, oldp, oldlenp, newp, | ||
| 7787 | newlen); | ||
| 7788 | if (sname) | ||
| 7789 | COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, REAL(strlen)(sname) + 1); | ||
| 7790 | if (oldlenp) | ||
| 7791 | COMMON_INTERCEPTOR_READ_RANGE(ctx, oldlenp, sizeof(*oldlenp)); | ||
| 7792 | if (newp && newlen) | ||
| 7793 | COMMON_INTERCEPTOR_READ_RANGE(ctx, newp, newlen); | ||
| 7794 | int res = REAL(sysctlbyname)(sname, oldp, oldlenp, newp, newlen); | ||
| 7795 | if (!res) { | ||
| 7796 | if (oldlenp) { | ||
| 7797 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldlenp, sizeof(*oldlenp)); | ||
| 7798 | if (oldp) | ||
| 7799 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldp, *oldlenp); | ||
| 7800 | } | ||
| 7801 | } | ||
| 7802 | return res; | ||
| 7803 | } | ||
| 7804 | |||
| 7805 | INTERCEPTOR(int, sysctlnametomib, const char *sname, int *name, | ||
| 7806 | SIZE_T *namelenp) { | ||
| 7807 | void *ctx; | ||
| 7808 | COMMON_INTERCEPTOR_ENTER(ctx, sysctlnametomib, sname, name, namelenp); | ||
| 7809 | if (sname) | ||
| 7810 | COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, REAL(strlen)(sname) + 1); | ||
| 7811 | if (namelenp) | ||
| 7812 | COMMON_INTERCEPTOR_READ_RANGE(ctx, namelenp, sizeof(*namelenp)); | ||
| 7813 | int res = REAL(sysctlnametomib)(sname, name, namelenp); | ||
| 7814 | if (!res) { | ||
| 7815 | if (namelenp) { | ||
| 7816 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelenp, sizeof(*namelenp)); | ||
| 7817 | if (name) | ||
| 7818 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, *namelenp * sizeof(*name)); | ||
| 7819 | } | ||
| 7820 | } | ||
| 7821 | return res; | ||
| 7822 | } | ||
| 7823 | |||
| 7824 | #define INIT_SYSCTL \ | ||
| 7825 | COMMON_INTERCEPT_FUNCTION(sysctl); \ | ||
| 7826 | COMMON_INTERCEPT_FUNCTION(sysctlbyname); \ | ||
| 7827 | COMMON_INTERCEPT_FUNCTION(sysctlnametomib); | ||
| 7828 | #else | ||
| 7829 | #define INIT_SYSCTL | ||
| 7830 | #endif | ||
| 7831 | |||
| 7832 | #if SANITIZER_INTERCEPT_ASYSCTL | ||
| 7833 | INTERCEPTOR(void *, asysctl, const int *name, SIZE_T namelen, SIZE_T *len) { | ||
| 7834 | void *ctx; | ||
| 7835 | COMMON_INTERCEPTOR_ENTER(ctx, asysctl, name, namelen, len); | ||
| 7836 | if (name) | ||
| 7837 | COMMON_INTERCEPTOR_READ_RANGE(ctx, name, sizeof(*name) * namelen); | ||
| 7838 | void *res = REAL(asysctl)(name, namelen, len); | ||
| 7839 | if (res && len) { | ||
| 7840 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, len, sizeof(*len)); | ||
| 7841 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, *len); | ||
| 7842 | } | ||
| 7843 | return res; | ||
| 7844 | } | ||
| 7845 | |||
| 7846 | INTERCEPTOR(void *, asysctlbyname, const char *sname, SIZE_T *len) { | ||
| 7847 | void *ctx; | ||
| 7848 | COMMON_INTERCEPTOR_ENTER(ctx, asysctlbyname, sname, len); | ||
| 7849 | if (sname) | ||
| 7850 | COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, REAL(strlen)(sname) + 1); | ||
| 7851 | void *res = REAL(asysctlbyname)(sname, len); | ||
| 7852 | if (res && len) { | ||
| 7853 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, len, sizeof(*len)); | ||
| 7854 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, *len); | ||
| 7855 | } | ||
| 7856 | return res; | ||
| 7857 | } | ||
| 7858 | #define INIT_ASYSCTL \ | ||
| 7859 | COMMON_INTERCEPT_FUNCTION(asysctl); \ | ||
| 7860 | COMMON_INTERCEPT_FUNCTION(asysctlbyname); | ||
| 7861 | #else | ||
| 7862 | #define INIT_ASYSCTL | ||
| 7863 | #endif | ||
| 7864 | |||
| 7865 | #if SANITIZER_INTERCEPT_SYSCTLGETMIBINFO | ||
| 7866 | INTERCEPTOR(int, sysctlgetmibinfo, char *sname, int *name, | ||
| 7867 | unsigned int *namelenp, char *cname, SIZE_T *csz, void **rnode, | ||
| 7868 | int v) { | ||
| 7869 | void *ctx; | ||
| 7870 | COMMON_INTERCEPTOR_ENTER(ctx, sysctlgetmibinfo, sname, name, namelenp, cname, | ||
| 7871 | csz, rnode, v); | ||
| 7872 | if (sname) | ||
| 7873 | COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, REAL(strlen)(sname) + 1); | ||
| 7874 | if (namelenp) | ||
| 7875 | COMMON_INTERCEPTOR_READ_RANGE(ctx, namelenp, sizeof(*namelenp)); | ||
| 7876 | if (csz) | ||
| 7877 | COMMON_INTERCEPTOR_READ_RANGE(ctx, csz, sizeof(*csz)); | ||
| 7878 | // Skip rnode, it's rarely used and not trivial to sanitize | ||
| 7879 | // It's also used mostly internally | ||
| 7880 | int res = REAL(sysctlgetmibinfo)(sname, name, namelenp, cname, csz, rnode, v); | ||
| 7881 | if (!res) { | ||
| 7882 | if (namelenp) { | ||
| 7883 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelenp, sizeof(*namelenp)); | ||
| 7884 | if (name) | ||
| 7885 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, *namelenp * sizeof(*name)); | ||
| 7886 | } | ||
| 7887 | if (csz) { | ||
| 7888 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, csz, sizeof(*csz)); | ||
| 7889 | if (cname) | ||
| 7890 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cname, *csz); | ||
| 7891 | } | ||
| 7892 | } | ||
| 7893 | return res; | ||
| 7894 | } | ||
| 7895 | #define INIT_SYSCTLGETMIBINFO \ | ||
| 7896 | COMMON_INTERCEPT_FUNCTION(sysctlgetmibinfo); | ||
| 7897 | #else | ||
| 7898 | #define INIT_SYSCTLGETMIBINFO | ||
| 7899 | #endif | ||
| 7900 | |||
| 7901 | #if SANITIZER_INTERCEPT_NL_LANGINFO | ||
| 7902 | INTERCEPTOR(char *, nl_langinfo, long item) { | ||
| 7903 | void *ctx; | ||
| 7904 | COMMON_INTERCEPTOR_ENTER(ctx, nl_langinfo, item); | ||
| 7905 | char *ret = REAL(nl_langinfo)(item); | ||
| 7906 | if (ret) | ||
| 7907 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, REAL(strlen)(ret) + 1); | ||
| 7908 | return ret; | ||
| 7909 | } | ||
| 7910 | #define INIT_NL_LANGINFO COMMON_INTERCEPT_FUNCTION(nl_langinfo) | ||
| 7911 | #else | ||
| 7912 | #define INIT_NL_LANGINFO | ||
| 7913 | #endif | ||
| 7914 | |||
| 7915 | #if SANITIZER_INTERCEPT_MODCTL | ||
| 7916 | INTERCEPTOR(int, modctl, int operation, void *argp) { | ||
| 7917 | void *ctx; | ||
| 7918 | int ret; | ||
| 7919 | COMMON_INTERCEPTOR_ENTER(ctx, modctl, operation, argp); | ||
| 7920 | |||
| 7921 | if (operation == modctl_load) { | ||
| 7922 | if (argp) { | ||
| 7923 | __sanitizer_modctl_load_t *ml = (__sanitizer_modctl_load_t *)argp; | ||
| 7924 | COMMON_INTERCEPTOR_READ_RANGE(ctx, ml, sizeof(*ml)); | ||
| 7925 | if (ml->ml_filename) | ||
| 7926 | COMMON_INTERCEPTOR_READ_RANGE(ctx, ml->ml_filename, | ||
| 7927 | REAL(strlen)(ml->ml_filename) + 1); | ||
| 7928 | if (ml->ml_props) | ||
| 7929 | COMMON_INTERCEPTOR_READ_RANGE(ctx, ml->ml_props, ml->ml_propslen); | ||
| 7930 | } | ||
| 7931 | ret = REAL(modctl)(operation, argp); | ||
| 7932 | } else if (operation == modctl_unload) { | ||
| 7933 | if (argp) { | ||
| 7934 | const char *name = (const char *)argp; | ||
| 7935 | COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 7936 | } | ||
| 7937 | ret = REAL(modctl)(operation, argp); | ||
| 7938 | } else if (operation == modctl_stat) { | ||
| 7939 | uptr iov_len; | ||
| 7940 | struct __sanitizer_iovec *iov = (struct __sanitizer_iovec *)argp; | ||
| 7941 | if (iov) { | ||
| 7942 | COMMON_INTERCEPTOR_READ_RANGE(ctx, iov, sizeof(*iov)); | ||
| 7943 | iov_len = iov->iov_len; | ||
| 7944 | } | ||
| 7945 | ret = REAL(modctl)(operation, argp); | ||
| 7946 | if (iov) | ||
| 7947 | COMMON_INTERCEPTOR_WRITE_RANGE( | ||
| 7948 | ctx, iov->iov_base, Min(iov_len, iov->iov_len)); | ||
| 7949 | } else if (operation == modctl_exists) { | ||
| 7950 | ret = REAL(modctl)(operation, argp); | ||
| 7951 | } else { | ||
| 7952 | ret = REAL(modctl)(operation, argp); | ||
| 7953 | } | ||
| 7954 | |||
| 7955 | return ret; | ||
| 7956 | } | ||
| 7957 | #define INIT_MODCTL COMMON_INTERCEPT_FUNCTION(modctl) | ||
| 7958 | #else | ||
| 7959 | #define INIT_MODCTL | ||
| 7960 | #endif | ||
| 7961 | |||
| 7962 | #if SANITIZER_INTERCEPT_STRTONUM | ||
| 7963 | INTERCEPTOR(long long, strtonum, const char *nptr, long long minval, | ||
| 7964 | long long maxval, const char **errstr) { | ||
| 7965 | void *ctx; | ||
| 7966 | COMMON_INTERCEPTOR_ENTER(ctx, strtonum, nptr, minval, maxval, errstr); | ||
| 7967 | |||
| 7968 | // TODO(kamil): Implement strtoll as a common inteceptor | ||
| 7969 | char *real_endptr; | ||
| 7970 | long long ret = (long long)REAL(strtoimax)(nptr, &real_endptr, 10); | ||
| 7971 | StrtolFixAndCheck(ctx, nptr, nullptr, real_endptr, 10); | ||
| 7972 | |||
| 7973 | ret = REAL(strtonum)(nptr, minval, maxval, errstr); | ||
| 7974 | if (errstr) { | ||
| 7975 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, errstr, sizeof(const char *)); | ||
| 7976 | if (*errstr) | ||
| 7977 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *errstr, REAL(strlen)(*errstr) + 1); | ||
| 7978 | } | ||
| 7979 | return ret; | ||
| 7980 | } | ||
| 7981 | #define INIT_STRTONUM COMMON_INTERCEPT_FUNCTION(strtonum) | ||
| 7982 | #else | ||
| 7983 | #define INIT_STRTONUM | ||
| 7984 | #endif | ||
| 7985 | |||
| 7986 | #if SANITIZER_INTERCEPT_FPARSELN | ||
| 7987 | INTERCEPTOR(char *, fparseln, __sanitizer_FILE *stream, SIZE_T *len, | ||
| 7988 | SIZE_T *lineno, const char delim[3], int flags) { | ||
| 7989 | void *ctx; | ||
| 7990 | COMMON_INTERCEPTOR_ENTER(ctx, fparseln, stream, len, lineno, delim, flags); | ||
| 7991 | if (lineno) | ||
| 7992 | COMMON_INTERCEPTOR_READ_RANGE(ctx, lineno, sizeof(*lineno)); | ||
| 7993 | if (delim) | ||
| 7994 | COMMON_INTERCEPTOR_READ_RANGE(ctx, delim, sizeof(delim[0]) * 3); | ||
| 7995 | char *ret = REAL(fparseln)(stream, len, lineno, delim, flags); | ||
| 7996 | if (ret) { | ||
| 7997 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, REAL(strlen)(ret) + 1); | ||
| 7998 | if (len) | ||
| 7999 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, len, sizeof(*len)); | ||
| 8000 | if (lineno) | ||
| 8001 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineno, sizeof(*lineno)); | ||
| 8002 | } | ||
| 8003 | return ret; | ||
| 8004 | } | ||
| 8005 | #define INIT_FPARSELN COMMON_INTERCEPT_FUNCTION(fparseln) | ||
| 8006 | #else | ||
| 8007 | #define INIT_FPARSELN | ||
| 8008 | #endif | ||
| 8009 | |||
| 8010 | #if SANITIZER_INTERCEPT_STATVFS1 | ||
| 8011 | INTERCEPTOR(int, statvfs1, const char *path, void *buf, int flags) { | ||
| 8012 | void *ctx; | ||
| 8013 | COMMON_INTERCEPTOR_ENTER(ctx, statvfs1, path, buf, flags); | ||
| 8014 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 8015 | int res = REAL(statvfs1)(path, buf, flags); | ||
| 8016 | if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz); | ||
| 8017 | return res; | ||
| 8018 | } | ||
| 8019 | INTERCEPTOR(int, fstatvfs1, int fd, void *buf, int flags) { | ||
| 8020 | void *ctx; | ||
| 8021 | COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs1, fd, buf, flags); | ||
| 8022 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 8023 | int res = REAL(fstatvfs1)(fd, buf, flags); | ||
| 8024 | if (!res) { | ||
| 8025 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz); | ||
| 8026 | if (fd >= 0) | ||
| 8027 | COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 8028 | } | ||
| 8029 | return res; | ||
| 8030 | } | ||
| 8031 | #define INIT_STATVFS1 \ | ||
| 8032 | COMMON_INTERCEPT_FUNCTION(statvfs1); \ | ||
| 8033 | COMMON_INTERCEPT_FUNCTION(fstatvfs1); | ||
| 8034 | #else | ||
| 8035 | #define INIT_STATVFS1 | ||
| 8036 | #endif | ||
| 8037 | |||
| 8038 | #if SANITIZER_INTERCEPT_STRTOI | ||
| 8039 | INTERCEPTOR(INTMAX_T, strtoi, const char *nptr, char **endptr, int base, | ||
| 8040 | INTMAX_T low, INTMAX_T high, int *rstatus) { | ||
| 8041 | void *ctx; | ||
| 8042 | COMMON_INTERCEPTOR_ENTER(ctx, strtoi, nptr, endptr, base, low, high, rstatus); | ||
| 8043 | char *real_endptr; | ||
| 8044 | INTMAX_T ret = REAL(strtoi)(nptr, &real_endptr, base, low, high, rstatus); | ||
| 8045 | StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); | ||
| 8046 | if (rstatus) | ||
| 8047 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rstatus, sizeof(*rstatus)); | ||
| 8048 | return ret; | ||
| 8049 | } | ||
| 8050 | |||
| 8051 | INTERCEPTOR(UINTMAX_T, strtou, const char *nptr, char **endptr, int base, | ||
| 8052 | UINTMAX_T low, UINTMAX_T high, int *rstatus) { | ||
| 8053 | void *ctx; | ||
| 8054 | COMMON_INTERCEPTOR_ENTER(ctx, strtou, nptr, endptr, base, low, high, rstatus); | ||
| 8055 | char *real_endptr; | ||
| 8056 | UINTMAX_T ret = REAL(strtou)(nptr, &real_endptr, base, low, high, rstatus); | ||
| 8057 | StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); | ||
| 8058 | if (rstatus) | ||
| 8059 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rstatus, sizeof(*rstatus)); | ||
| 8060 | return ret; | ||
| 8061 | } | ||
| 8062 | #define INIT_STRTOI \ | ||
| 8063 | COMMON_INTERCEPT_FUNCTION(strtoi); \ | ||
| 8064 | COMMON_INTERCEPT_FUNCTION(strtou) | ||
| 8065 | #else | ||
| 8066 | #define INIT_STRTOI | ||
| 8067 | #endif | ||
| 8068 | |||
| 8069 | #if SANITIZER_INTERCEPT_CAPSICUM | ||
| 8070 | #define CAP_RIGHTS_INIT_INTERCEPTOR(cap_rights_init, rights, ...) \ | ||
| 8071 | { \ | ||
| 8072 | void *ctx; \ | ||
| 8073 | COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_init, rights, ##__VA_ARGS__); \ | ||
| 8074 | if (rights) \ | ||
| 8075 | COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); \ | ||
| 8076 | __sanitizer_cap_rights_t *ret = \ | ||
| 8077 | REAL(cap_rights_init)(rights, ##__VA_ARGS__); \ | ||
| 8078 | if (ret) \ | ||
| 8079 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, sizeof(*ret)); \ | ||
| 8080 | return ret; \ | ||
| 8081 | } | ||
| 8082 | |||
| 8083 | #define CAP_RIGHTS_SET_INTERCEPTOR(cap_rights_set, rights, ...) \ | ||
| 8084 | { \ | ||
| 8085 | void *ctx; \ | ||
| 8086 | COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_set, rights, ##__VA_ARGS__); \ | ||
| 8087 | if (rights) \ | ||
| 8088 | COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); \ | ||
| 8089 | __sanitizer_cap_rights_t *ret = \ | ||
| 8090 | REAL(cap_rights_set)(rights, ##__VA_ARGS__); \ | ||
| 8091 | if (ret) \ | ||
| 8092 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, sizeof(*ret)); \ | ||
| 8093 | return ret; \ | ||
| 8094 | } | ||
| 8095 | |||
| 8096 | #define CAP_RIGHTS_CLEAR_INTERCEPTOR(cap_rights_clear, rights, ...) \ | ||
| 8097 | { \ | ||
| 8098 | void *ctx; \ | ||
| 8099 | COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_clear, rights, ##__VA_ARGS__); \ | ||
| 8100 | if (rights) \ | ||
| 8101 | COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); \ | ||
| 8102 | __sanitizer_cap_rights_t *ret = \ | ||
| 8103 | REAL(cap_rights_clear)(rights, ##__VA_ARGS__); \ | ||
| 8104 | if (ret) \ | ||
| 8105 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, sizeof(*ret)); \ | ||
| 8106 | return ret; \ | ||
| 8107 | } | ||
| 8108 | |||
| 8109 | #define CAP_RIGHTS_IS_SET_INTERCEPTOR(cap_rights_is_set, rights, ...) \ | ||
| 8110 | { \ | ||
| 8111 | void *ctx; \ | ||
| 8112 | COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_is_set, rights, ##__VA_ARGS__); \ | ||
| 8113 | if (rights) \ | ||
| 8114 | COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); \ | ||
| 8115 | return REAL(cap_rights_is_set)(rights, ##__VA_ARGS__); \ | ||
| 8116 | } | ||
| 8117 | |||
| 8118 | INTERCEPTOR(__sanitizer_cap_rights_t *, cap_rights_init, | ||
| 8119 | __sanitizer_cap_rights_t *rights) { | ||
| 8120 | CAP_RIGHTS_INIT_INTERCEPTOR(cap_rights_init, rights); | ||
| 8121 | } | ||
| 8122 | |||
| 8123 | INTERCEPTOR(__sanitizer_cap_rights_t *, cap_rights_set, | ||
| 8124 | __sanitizer_cap_rights_t *rights) { | ||
| 8125 | CAP_RIGHTS_SET_INTERCEPTOR(cap_rights_set, rights); | ||
| 8126 | } | ||
| 8127 | |||
| 8128 | INTERCEPTOR(__sanitizer_cap_rights_t *, cap_rights_clear, | ||
| 8129 | __sanitizer_cap_rights_t *rights) { | ||
| 8130 | CAP_RIGHTS_CLEAR_INTERCEPTOR(cap_rights_clear, rights); | ||
| 8131 | } | ||
| 8132 | |||
| 8133 | INTERCEPTOR(bool, cap_rights_is_set, | ||
| 8134 | __sanitizer_cap_rights_t *rights) { | ||
| 8135 | CAP_RIGHTS_IS_SET_INTERCEPTOR(cap_rights_is_set, rights); | ||
| 8136 | } | ||
| 8137 | |||
| 8138 | INTERCEPTOR(int, cap_rights_limit, int fd, | ||
| 8139 | const __sanitizer_cap_rights_t *rights) { | ||
| 8140 | void *ctx; | ||
| 8141 | COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_limit, fd, rights); | ||
| 8142 | if (rights) | ||
| 8143 | COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); | ||
| 8144 | |||
| 8145 | return REAL(cap_rights_limit)(fd, rights); | ||
| 8146 | } | ||
| 8147 | |||
| 8148 | INTERCEPTOR(int, cap_rights_get, int fd, __sanitizer_cap_rights_t *rights) { | ||
| 8149 | void *ctx; | ||
| 8150 | COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_get, fd, rights); | ||
| 8151 | int ret = REAL(cap_rights_get)(fd, rights); | ||
| 8152 | if (!ret && rights) | ||
| 8153 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rights, sizeof(*rights)); | ||
| 8154 | |||
| 8155 | return ret; | ||
| 8156 | } | ||
| 8157 | |||
| 8158 | INTERCEPTOR(bool, cap_rights_is_valid, const __sanitizer_cap_rights_t *rights) { | ||
| 8159 | void *ctx; | ||
| 8160 | COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_is_valid, rights); | ||
| 8161 | if (rights) | ||
| 8162 | COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); | ||
| 8163 | |||
| 8164 | return REAL(cap_rights_is_valid(rights)); | ||
| 8165 | } | ||
| 8166 | |||
| 8167 | INTERCEPTOR(__sanitizer_cap_rights *, cap_rights_merge, | ||
| 8168 | __sanitizer_cap_rights *dst, const __sanitizer_cap_rights *src) { | ||
| 8169 | void *ctx; | ||
| 8170 | COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_merge, dst, src); | ||
| 8171 | if (src) | ||
| 8172 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); | ||
| 8173 | |||
| 8174 | __sanitizer_cap_rights *ret = REAL(cap_rights_merge)(dst, src); | ||
| 8175 | if (dst) | ||
| 8176 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst)); | ||
| 8177 | |||
| 8178 | return ret; | ||
| 8179 | } | ||
| 8180 | |||
| 8181 | INTERCEPTOR(__sanitizer_cap_rights *, cap_rights_remove, | ||
| 8182 | __sanitizer_cap_rights *dst, const __sanitizer_cap_rights *src) { | ||
| 8183 | void *ctx; | ||
| 8184 | COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_remove, dst, src); | ||
| 8185 | if (src) | ||
| 8186 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); | ||
| 8187 | |||
| 8188 | __sanitizer_cap_rights *ret = REAL(cap_rights_remove)(dst, src); | ||
| 8189 | if (dst) | ||
| 8190 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst)); | ||
| 8191 | |||
| 8192 | return ret; | ||
| 8193 | } | ||
| 8194 | |||
| 8195 | INTERCEPTOR(bool, cap_rights_contains, const __sanitizer_cap_rights *big, | ||
| 8196 | const __sanitizer_cap_rights *little) { | ||
| 8197 | void *ctx; | ||
| 8198 | COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_contains, big, little); | ||
| 8199 | if (little) | ||
| 8200 | COMMON_INTERCEPTOR_READ_RANGE(ctx, little, sizeof(*little)); | ||
| 8201 | if (big) | ||
| 8202 | COMMON_INTERCEPTOR_READ_RANGE(ctx, big, sizeof(*big)); | ||
| 8203 | |||
| 8204 | return REAL(cap_rights_contains)(big, little); | ||
| 8205 | } | ||
| 8206 | |||
| 8207 | INTERCEPTOR(int, cap_ioctls_limit, int fd, const uptr *cmds, SIZE_T ncmds) { | ||
| 8208 | void *ctx; | ||
| 8209 | COMMON_INTERCEPTOR_ENTER(ctx, cap_ioctls_limit, fd, cmds, ncmds); | ||
| 8210 | if (cmds) | ||
| 8211 | COMMON_INTERCEPTOR_READ_RANGE(ctx, cmds, sizeof(*cmds) * ncmds); | ||
| 8212 | |||
| 8213 | return REAL(cap_ioctls_limit)(fd, cmds, ncmds); | ||
| 8214 | } | ||
| 8215 | |||
| 8216 | INTERCEPTOR(int, cap_ioctls_get, int fd, uptr *cmds, SIZE_T maxcmds) { | ||
| 8217 | void *ctx; | ||
| 8218 | COMMON_INTERCEPTOR_ENTER(ctx, cap_ioctls_get, fd, cmds, maxcmds); | ||
| 8219 | int ret = REAL(cap_ioctls_get)(fd, cmds, maxcmds); | ||
| 8220 | if (!ret && cmds) | ||
| 8221 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cmds, sizeof(*cmds) * maxcmds); | ||
| 8222 | |||
| 8223 | return ret; | ||
| 8224 | } | ||
| 8225 | #define INIT_CAPSICUM \ | ||
| 8226 | COMMON_INTERCEPT_FUNCTION(cap_rights_init); \ | ||
| 8227 | COMMON_INTERCEPT_FUNCTION(cap_rights_set); \ | ||
| 8228 | COMMON_INTERCEPT_FUNCTION(cap_rights_clear); \ | ||
| 8229 | COMMON_INTERCEPT_FUNCTION(cap_rights_is_set); \ | ||
| 8230 | COMMON_INTERCEPT_FUNCTION(cap_rights_get); \ | ||
| 8231 | COMMON_INTERCEPT_FUNCTION(cap_rights_limit); \ | ||
| 8232 | COMMON_INTERCEPT_FUNCTION(cap_rights_contains); \ | ||
| 8233 | COMMON_INTERCEPT_FUNCTION(cap_rights_remove); \ | ||
| 8234 | COMMON_INTERCEPT_FUNCTION(cap_rights_merge); \ | ||
| 8235 | COMMON_INTERCEPT_FUNCTION(cap_rights_is_valid); \ | ||
| 8236 | COMMON_INTERCEPT_FUNCTION(cap_ioctls_get); \ | ||
| 8237 | COMMON_INTERCEPT_FUNCTION(cap_ioctls_limit) | ||
| 8238 | #else | ||
| 8239 | #define INIT_CAPSICUM | ||
| 8240 | #endif | ||
| 8241 | |||
| 8242 | #if SANITIZER_INTERCEPT_SHA1 | ||
| 8243 | INTERCEPTOR(void, SHA1Init, void *context) { | ||
| 8244 | void *ctx; | ||
| 8245 | COMMON_INTERCEPTOR_ENTER(ctx, SHA1Init, context); | ||
| 8246 | REAL(SHA1Init)(context); | ||
| 8247 | if (context) | ||
| 8248 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, SHA1_CTX_sz); | ||
| 8249 | } | ||
| 8250 | INTERCEPTOR(void, SHA1Update, void *context, const u8 *data, unsigned len) { | ||
| 8251 | void *ctx; | ||
| 8252 | COMMON_INTERCEPTOR_ENTER(ctx, SHA1Update, context, data, len); | ||
| 8253 | if (data && len > 0) | ||
| 8254 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); | ||
| 8255 | if (context) | ||
| 8256 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA1_CTX_sz); | ||
| 8257 | REAL(SHA1Update)(context, data, len); | ||
| 8258 | if (context) | ||
| 8259 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, SHA1_CTX_sz); | ||
| 8260 | } | ||
| 8261 | INTERCEPTOR(void, SHA1Final, u8 digest[20], void *context) { | ||
| 8262 | void *ctx; | ||
| 8263 | COMMON_INTERCEPTOR_ENTER(ctx, SHA1Final, digest, context); | ||
| 8264 | if (context) | ||
| 8265 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA1_CTX_sz); | ||
| 8266 | REAL(SHA1Final)(digest, context); | ||
| 8267 | if (digest) | ||
| 8268 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(u8) * 20); | ||
| 8269 | } | ||
| 8270 | INTERCEPTOR(void, SHA1Transform, u32 state[5], u8 buffer[64]) { | ||
| 8271 | void *ctx; | ||
| 8272 | COMMON_INTERCEPTOR_ENTER(ctx, SHA1Transform, state, buffer); | ||
| 8273 | if (state) | ||
| 8274 | COMMON_INTERCEPTOR_READ_RANGE(ctx, state, sizeof(u32) * 5); | ||
| 8275 | if (buffer) | ||
| 8276 | COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, sizeof(u8) * 64); | ||
| 8277 | REAL(SHA1Transform)(state, buffer); | ||
| 8278 | if (state) | ||
| 8279 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, state, sizeof(u32) * 5); | ||
| 8280 | } | ||
| 8281 | INTERCEPTOR(char *, SHA1End, void *context, char *buf) { | ||
| 8282 | void *ctx; | ||
| 8283 | COMMON_INTERCEPTOR_ENTER(ctx, SHA1End, context, buf); | ||
| 8284 | if (context) | ||
| 8285 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA1_CTX_sz); | ||
| 8286 | char *ret = REAL(SHA1End)(context, buf); | ||
| 8287 | if (ret) | ||
| 8288 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length); | ||
| 8289 | return ret; | ||
| 8290 | } | ||
| 8291 | INTERCEPTOR(char *, SHA1File, char *filename, char *buf) { | ||
| 8292 | void *ctx; | ||
| 8293 | COMMON_INTERCEPTOR_ENTER(ctx, SHA1File, filename, buf); | ||
| 8294 | if (filename) | ||
| 8295 | COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1); | ||
| 8296 | char *ret = REAL(SHA1File)(filename, buf); | ||
| 8297 | if (ret) | ||
| 8298 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length); | ||
| 8299 | return ret; | ||
| 8300 | } | ||
| 8301 | INTERCEPTOR(char *, SHA1FileChunk, char *filename, char *buf, OFF_T offset, | ||
| 8302 | OFF_T length) { | ||
| 8303 | void *ctx; | ||
| 8304 | COMMON_INTERCEPTOR_ENTER(ctx, SHA1FileChunk, filename, buf, offset, length); | ||
| 8305 | if (filename) | ||
| 8306 | COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1); | ||
| 8307 | char *ret = REAL(SHA1FileChunk)(filename, buf, offset, length); | ||
| 8308 | if (ret) | ||
| 8309 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length); | ||
| 8310 | return ret; | ||
| 8311 | } | ||
| 8312 | INTERCEPTOR(char *, SHA1Data, u8 *data, SIZE_T len, char *buf) { | ||
| 8313 | void *ctx; | ||
| 8314 | COMMON_INTERCEPTOR_ENTER(ctx, SHA1Data, data, len, buf); | ||
| 8315 | if (data) | ||
| 8316 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); | ||
| 8317 | char *ret = REAL(SHA1Data)(data, len, buf); | ||
| 8318 | if (ret) | ||
| 8319 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length); | ||
| 8320 | return ret; | ||
| 8321 | } | ||
| 8322 | #define INIT_SHA1 \ | ||
| 8323 | COMMON_INTERCEPT_FUNCTION(SHA1Init); \ | ||
| 8324 | COMMON_INTERCEPT_FUNCTION(SHA1Update); \ | ||
| 8325 | COMMON_INTERCEPT_FUNCTION(SHA1Final); \ | ||
| 8326 | COMMON_INTERCEPT_FUNCTION(SHA1Transform); \ | ||
| 8327 | COMMON_INTERCEPT_FUNCTION(SHA1End); \ | ||
| 8328 | COMMON_INTERCEPT_FUNCTION(SHA1File); \ | ||
| 8329 | COMMON_INTERCEPT_FUNCTION(SHA1FileChunk); \ | ||
| 8330 | COMMON_INTERCEPT_FUNCTION(SHA1Data) | ||
| 8331 | #else | ||
| 8332 | #define INIT_SHA1 | ||
| 8333 | #endif | ||
| 8334 | |||
| 8335 | #if SANITIZER_INTERCEPT_MD4 | ||
| 8336 | INTERCEPTOR(void, MD4Init, void *context) { | ||
| 8337 | void *ctx; | ||
| 8338 | COMMON_INTERCEPTOR_ENTER(ctx, MD4Init, context); | ||
| 8339 | REAL(MD4Init)(context); | ||
| 8340 | if (context) | ||
| 8341 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD4_CTX_sz); | ||
| 8342 | } | ||
| 8343 | |||
| 8344 | INTERCEPTOR(void, MD4Update, void *context, const unsigned char *data, | ||
| 8345 | unsigned int len) { | ||
| 8346 | void *ctx; | ||
| 8347 | COMMON_INTERCEPTOR_ENTER(ctx, MD4Update, context, data, len); | ||
| 8348 | if (data && len > 0) | ||
| 8349 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); | ||
| 8350 | if (context) | ||
| 8351 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD4_CTX_sz); | ||
| 8352 | REAL(MD4Update)(context, data, len); | ||
| 8353 | if (context) | ||
| 8354 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD4_CTX_sz); | ||
| 8355 | } | ||
| 8356 | |||
| 8357 | INTERCEPTOR(void, MD4Final, unsigned char digest[16], void *context) { | ||
| 8358 | void *ctx; | ||
| 8359 | COMMON_INTERCEPTOR_ENTER(ctx, MD4Final, digest, context); | ||
| 8360 | if (context) | ||
| 8361 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD4_CTX_sz); | ||
| 8362 | REAL(MD4Final)(digest, context); | ||
| 8363 | if (digest) | ||
| 8364 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(unsigned char) * 16); | ||
| 8365 | } | ||
| 8366 | |||
| 8367 | INTERCEPTOR(char *, MD4End, void *context, char *buf) { | ||
| 8368 | void *ctx; | ||
| 8369 | COMMON_INTERCEPTOR_ENTER(ctx, MD4End, context, buf); | ||
| 8370 | if (context) | ||
| 8371 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD4_CTX_sz); | ||
| 8372 | char *ret = REAL(MD4End)(context, buf); | ||
| 8373 | if (ret) | ||
| 8374 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD4_return_length); | ||
| 8375 | return ret; | ||
| 8376 | } | ||
| 8377 | |||
| 8378 | INTERCEPTOR(char *, MD4File, const char *filename, char *buf) { | ||
| 8379 | void *ctx; | ||
| 8380 | COMMON_INTERCEPTOR_ENTER(ctx, MD4File, filename, buf); | ||
| 8381 | if (filename) | ||
| 8382 | COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1); | ||
| 8383 | char *ret = REAL(MD4File)(filename, buf); | ||
| 8384 | if (ret) | ||
| 8385 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD4_return_length); | ||
| 8386 | return ret; | ||
| 8387 | } | ||
| 8388 | |||
| 8389 | INTERCEPTOR(char *, MD4Data, const unsigned char *data, unsigned int len, | ||
| 8390 | char *buf) { | ||
| 8391 | void *ctx; | ||
| 8392 | COMMON_INTERCEPTOR_ENTER(ctx, MD4Data, data, len, buf); | ||
| 8393 | if (data && len > 0) | ||
| 8394 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); | ||
| 8395 | char *ret = REAL(MD4Data)(data, len, buf); | ||
| 8396 | if (ret) | ||
| 8397 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD4_return_length); | ||
| 8398 | return ret; | ||
| 8399 | } | ||
| 8400 | |||
| 8401 | #define INIT_MD4 \ | ||
| 8402 | COMMON_INTERCEPT_FUNCTION(MD4Init); \ | ||
| 8403 | COMMON_INTERCEPT_FUNCTION(MD4Update); \ | ||
| 8404 | COMMON_INTERCEPT_FUNCTION(MD4Final); \ | ||
| 8405 | COMMON_INTERCEPT_FUNCTION(MD4End); \ | ||
| 8406 | COMMON_INTERCEPT_FUNCTION(MD4File); \ | ||
| 8407 | COMMON_INTERCEPT_FUNCTION(MD4Data) | ||
| 8408 | #else | ||
| 8409 | #define INIT_MD4 | ||
| 8410 | #endif | ||
| 8411 | |||
| 8412 | #if SANITIZER_INTERCEPT_RMD160 | ||
| 8413 | INTERCEPTOR(void, RMD160Init, void *context) { | ||
| 8414 | void *ctx; | ||
| 8415 | COMMON_INTERCEPTOR_ENTER(ctx, RMD160Init, context); | ||
| 8416 | REAL(RMD160Init)(context); | ||
| 8417 | if (context) | ||
| 8418 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, RMD160_CTX_sz); | ||
| 8419 | } | ||
| 8420 | INTERCEPTOR(void, RMD160Update, void *context, const u8 *data, unsigned len) { | ||
| 8421 | void *ctx; | ||
| 8422 | COMMON_INTERCEPTOR_ENTER(ctx, RMD160Update, context, data, len); | ||
| 8423 | if (data && len > 0) | ||
| 8424 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); | ||
| 8425 | if (context) | ||
| 8426 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, RMD160_CTX_sz); | ||
| 8427 | REAL(RMD160Update)(context, data, len); | ||
| 8428 | if (context) | ||
| 8429 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, RMD160_CTX_sz); | ||
| 8430 | } | ||
| 8431 | INTERCEPTOR(void, RMD160Final, u8 digest[20], void *context) { | ||
| 8432 | void *ctx; | ||
| 8433 | COMMON_INTERCEPTOR_ENTER(ctx, RMD160Final, digest, context); | ||
| 8434 | if (context) | ||
| 8435 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, RMD160_CTX_sz); | ||
| 8436 | REAL(RMD160Final)(digest, context); | ||
| 8437 | if (digest) | ||
| 8438 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(u8) * 20); | ||
| 8439 | } | ||
| 8440 | INTERCEPTOR(void, RMD160Transform, u32 state[5], u16 buffer[16]) { | ||
| 8441 | void *ctx; | ||
| 8442 | COMMON_INTERCEPTOR_ENTER(ctx, RMD160Transform, state, buffer); | ||
| 8443 | if (state) | ||
| 8444 | COMMON_INTERCEPTOR_READ_RANGE(ctx, state, sizeof(u32) * 5); | ||
| 8445 | if (buffer) | ||
| 8446 | COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, sizeof(u32) * 16); | ||
| 8447 | REAL(RMD160Transform)(state, buffer); | ||
| 8448 | if (state) | ||
| 8449 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, state, sizeof(u32) * 5); | ||
| 8450 | } | ||
| 8451 | INTERCEPTOR(char *, RMD160End, void *context, char *buf) { | ||
| 8452 | void *ctx; | ||
| 8453 | COMMON_INTERCEPTOR_ENTER(ctx, RMD160End, context, buf); | ||
| 8454 | if (context) | ||
| 8455 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, RMD160_CTX_sz); | ||
| 8456 | char *ret = REAL(RMD160End)(context, buf); | ||
| 8457 | if (ret) | ||
| 8458 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length); | ||
| 8459 | return ret; | ||
| 8460 | } | ||
| 8461 | INTERCEPTOR(char *, RMD160File, char *filename, char *buf) { | ||
| 8462 | void *ctx; | ||
| 8463 | COMMON_INTERCEPTOR_ENTER(ctx, RMD160File, filename, buf); | ||
| 8464 | if (filename) | ||
| 8465 | COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1); | ||
| 8466 | char *ret = REAL(RMD160File)(filename, buf); | ||
| 8467 | if (ret) | ||
| 8468 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length); | ||
| 8469 | return ret; | ||
| 8470 | } | ||
| 8471 | INTERCEPTOR(char *, RMD160FileChunk, char *filename, char *buf, OFF_T offset, | ||
| 8472 | OFF_T length) { | ||
| 8473 | void *ctx; | ||
| 8474 | COMMON_INTERCEPTOR_ENTER(ctx, RMD160FileChunk, filename, buf, offset, length); | ||
| 8475 | if (filename) | ||
| 8476 | COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1); | ||
| 8477 | char *ret = REAL(RMD160FileChunk)(filename, buf, offset, length); | ||
| 8478 | if (ret) | ||
| 8479 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length); | ||
| 8480 | return ret; | ||
| 8481 | } | ||
| 8482 | INTERCEPTOR(char *, RMD160Data, u8 *data, SIZE_T len, char *buf) { | ||
| 8483 | void *ctx; | ||
| 8484 | COMMON_INTERCEPTOR_ENTER(ctx, RMD160Data, data, len, buf); | ||
| 8485 | if (data && len > 0) | ||
| 8486 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); | ||
| 8487 | char *ret = REAL(RMD160Data)(data, len, buf); | ||
| 8488 | if (ret) | ||
| 8489 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length); | ||
| 8490 | return ret; | ||
| 8491 | } | ||
| 8492 | #define INIT_RMD160 \ | ||
| 8493 | COMMON_INTERCEPT_FUNCTION(RMD160Init); \ | ||
| 8494 | COMMON_INTERCEPT_FUNCTION(RMD160Update); \ | ||
| 8495 | COMMON_INTERCEPT_FUNCTION(RMD160Final); \ | ||
| 8496 | COMMON_INTERCEPT_FUNCTION(RMD160Transform); \ | ||
| 8497 | COMMON_INTERCEPT_FUNCTION(RMD160End); \ | ||
| 8498 | COMMON_INTERCEPT_FUNCTION(RMD160File); \ | ||
| 8499 | COMMON_INTERCEPT_FUNCTION(RMD160FileChunk); \ | ||
| 8500 | COMMON_INTERCEPT_FUNCTION(RMD160Data) | ||
| 8501 | #else | ||
| 8502 | #define INIT_RMD160 | ||
| 8503 | #endif | ||
| 8504 | |||
| 8505 | #if SANITIZER_INTERCEPT_MD5 | ||
| 8506 | INTERCEPTOR(void, MD5Init, void *context) { | ||
| 8507 | void *ctx; | ||
| 8508 | COMMON_INTERCEPTOR_ENTER(ctx, MD5Init, context); | ||
| 8509 | REAL(MD5Init)(context); | ||
| 8510 | if (context) | ||
| 8511 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD5_CTX_sz); | ||
| 8512 | } | ||
| 8513 | |||
| 8514 | INTERCEPTOR(void, MD5Update, void *context, const unsigned char *data, | ||
| 8515 | unsigned int len) { | ||
| 8516 | void *ctx; | ||
| 8517 | COMMON_INTERCEPTOR_ENTER(ctx, MD5Update, context, data, len); | ||
| 8518 | if (data && len > 0) | ||
| 8519 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); | ||
| 8520 | if (context) | ||
| 8521 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD5_CTX_sz); | ||
| 8522 | REAL(MD5Update)(context, data, len); | ||
| 8523 | if (context) | ||
| 8524 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD5_CTX_sz); | ||
| 8525 | } | ||
| 8526 | |||
| 8527 | INTERCEPTOR(void, MD5Final, unsigned char digest[16], void *context) { | ||
| 8528 | void *ctx; | ||
| 8529 | COMMON_INTERCEPTOR_ENTER(ctx, MD5Final, digest, context); | ||
| 8530 | if (context) | ||
| 8531 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD5_CTX_sz); | ||
| 8532 | REAL(MD5Final)(digest, context); | ||
| 8533 | if (digest) | ||
| 8534 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(unsigned char) * 16); | ||
| 8535 | } | ||
| 8536 | |||
| 8537 | INTERCEPTOR(char *, MD5End, void *context, char *buf) { | ||
| 8538 | void *ctx; | ||
| 8539 | COMMON_INTERCEPTOR_ENTER(ctx, MD5End, context, buf); | ||
| 8540 | if (context) | ||
| 8541 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD5_CTX_sz); | ||
| 8542 | char *ret = REAL(MD5End)(context, buf); | ||
| 8543 | if (ret) | ||
| 8544 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD5_return_length); | ||
| 8545 | return ret; | ||
| 8546 | } | ||
| 8547 | |||
| 8548 | INTERCEPTOR(char *, MD5File, const char *filename, char *buf) { | ||
| 8549 | void *ctx; | ||
| 8550 | COMMON_INTERCEPTOR_ENTER(ctx, MD5File, filename, buf); | ||
| 8551 | if (filename) | ||
| 8552 | COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1); | ||
| 8553 | char *ret = REAL(MD5File)(filename, buf); | ||
| 8554 | if (ret) | ||
| 8555 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD5_return_length); | ||
| 8556 | return ret; | ||
| 8557 | } | ||
| 8558 | |||
| 8559 | INTERCEPTOR(char *, MD5Data, const unsigned char *data, unsigned int len, | ||
| 8560 | char *buf) { | ||
| 8561 | void *ctx; | ||
| 8562 | COMMON_INTERCEPTOR_ENTER(ctx, MD5Data, data, len, buf); | ||
| 8563 | if (data && len > 0) | ||
| 8564 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); | ||
| 8565 | char *ret = REAL(MD5Data)(data, len, buf); | ||
| 8566 | if (ret) | ||
| 8567 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD5_return_length); | ||
| 8568 | return ret; | ||
| 8569 | } | ||
| 8570 | |||
| 8571 | #define INIT_MD5 \ | ||
| 8572 | COMMON_INTERCEPT_FUNCTION(MD5Init); \ | ||
| 8573 | COMMON_INTERCEPT_FUNCTION(MD5Update); \ | ||
| 8574 | COMMON_INTERCEPT_FUNCTION(MD5Final); \ | ||
| 8575 | COMMON_INTERCEPT_FUNCTION(MD5End); \ | ||
| 8576 | COMMON_INTERCEPT_FUNCTION(MD5File); \ | ||
| 8577 | COMMON_INTERCEPT_FUNCTION(MD5Data) | ||
| 8578 | #else | ||
| 8579 | #define INIT_MD5 | ||
| 8580 | #endif | ||
| 8581 | |||
| 8582 | #if SANITIZER_INTERCEPT_FSEEK | ||
| 8583 | INTERCEPTOR(int, fseek, __sanitizer_FILE *stream, long int offset, int whence) { | ||
| 8584 | void *ctx; | ||
| 8585 | COMMON_INTERCEPTOR_ENTER(ctx, fseek, stream, offset, whence); | ||
| 8586 | return REAL(fseek)(stream, offset, whence); | ||
| 8587 | } | ||
| 8588 | INTERCEPTOR(int, fseeko, __sanitizer_FILE *stream, OFF_T offset, int whence) { | ||
| 8589 | void *ctx; | ||
| 8590 | COMMON_INTERCEPTOR_ENTER(ctx, fseeko, stream, offset, whence); | ||
| 8591 | return REAL(fseeko)(stream, offset, whence); | ||
| 8592 | } | ||
| 8593 | INTERCEPTOR(long int, ftell, __sanitizer_FILE *stream) { | ||
| 8594 | void *ctx; | ||
| 8595 | COMMON_INTERCEPTOR_ENTER(ctx, ftell, stream); | ||
| 8596 | return REAL(ftell)(stream); | ||
| 8597 | } | ||
| 8598 | INTERCEPTOR(OFF_T, ftello, __sanitizer_FILE *stream) { | ||
| 8599 | void *ctx; | ||
| 8600 | COMMON_INTERCEPTOR_ENTER(ctx, ftello, stream); | ||
| 8601 | return REAL(ftello)(stream); | ||
| 8602 | } | ||
| 8603 | INTERCEPTOR(void, rewind, __sanitizer_FILE *stream) { | ||
| 8604 | void *ctx; | ||
| 8605 | COMMON_INTERCEPTOR_ENTER(ctx, rewind, stream); | ||
| 8606 | return REAL(rewind)(stream); | ||
| 8607 | } | ||
| 8608 | INTERCEPTOR(int, fgetpos, __sanitizer_FILE *stream, void *pos) { | ||
| 8609 | void *ctx; | ||
| 8610 | COMMON_INTERCEPTOR_ENTER(ctx, fgetpos, stream, pos); | ||
| 8611 | int ret = REAL(fgetpos)(stream, pos); | ||
| 8612 | if (pos && !ret) | ||
| 8613 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pos, fpos_t_sz); | ||
| 8614 | return ret; | ||
| 8615 | } | ||
| 8616 | INTERCEPTOR(int, fsetpos, __sanitizer_FILE *stream, const void *pos) { | ||
| 8617 | void *ctx; | ||
| 8618 | COMMON_INTERCEPTOR_ENTER(ctx, fsetpos, stream, pos); | ||
| 8619 | if (pos) | ||
| 8620 | COMMON_INTERCEPTOR_READ_RANGE(ctx, pos, fpos_t_sz); | ||
| 8621 | return REAL(fsetpos)(stream, pos); | ||
| 8622 | } | ||
| 8623 | #define INIT_FSEEK \ | ||
| 8624 | COMMON_INTERCEPT_FUNCTION(fseek); \ | ||
| 8625 | COMMON_INTERCEPT_FUNCTION(fseeko); \ | ||
| 8626 | COMMON_INTERCEPT_FUNCTION(ftell); \ | ||
| 8627 | COMMON_INTERCEPT_FUNCTION(ftello); \ | ||
| 8628 | COMMON_INTERCEPT_FUNCTION(rewind); \ | ||
| 8629 | COMMON_INTERCEPT_FUNCTION(fgetpos); \ | ||
| 8630 | COMMON_INTERCEPT_FUNCTION(fsetpos) | ||
| 8631 | #else | ||
| 8632 | #define INIT_FSEEK | ||
| 8633 | #endif | ||
| 8634 | |||
| 8635 | #if SANITIZER_INTERCEPT_MD2 | ||
| 8636 | INTERCEPTOR(void, MD2Init, void *context) { | ||
| 8637 | void *ctx; | ||
| 8638 | COMMON_INTERCEPTOR_ENTER(ctx, MD2Init, context); | ||
| 8639 | REAL(MD2Init)(context); | ||
| 8640 | if (context) | ||
| 8641 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD2_CTX_sz); | ||
| 8642 | } | ||
| 8643 | |||
| 8644 | INTERCEPTOR(void, MD2Update, void *context, const unsigned char *data, | ||
| 8645 | unsigned int len) { | ||
| 8646 | void *ctx; | ||
| 8647 | COMMON_INTERCEPTOR_ENTER(ctx, MD2Update, context, data, len); | ||
| 8648 | if (data && len > 0) | ||
| 8649 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); | ||
| 8650 | if (context) | ||
| 8651 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD2_CTX_sz); | ||
| 8652 | REAL(MD2Update)(context, data, len); | ||
| 8653 | if (context) | ||
| 8654 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD2_CTX_sz); | ||
| 8655 | } | ||
| 8656 | |||
| 8657 | INTERCEPTOR(void, MD2Final, unsigned char digest[16], void *context) { | ||
| 8658 | void *ctx; | ||
| 8659 | COMMON_INTERCEPTOR_ENTER(ctx, MD2Final, digest, context); | ||
| 8660 | if (context) | ||
| 8661 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD2_CTX_sz); | ||
| 8662 | REAL(MD2Final)(digest, context); | ||
| 8663 | if (digest) | ||
| 8664 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(unsigned char) * 16); | ||
| 8665 | } | ||
| 8666 | |||
| 8667 | INTERCEPTOR(char *, MD2End, void *context, char *buf) { | ||
| 8668 | void *ctx; | ||
| 8669 | COMMON_INTERCEPTOR_ENTER(ctx, MD2End, context, buf); | ||
| 8670 | if (context) | ||
| 8671 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD2_CTX_sz); | ||
| 8672 | char *ret = REAL(MD2End)(context, buf); | ||
| 8673 | if (ret) | ||
| 8674 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD2_return_length); | ||
| 8675 | return ret; | ||
| 8676 | } | ||
| 8677 | |||
| 8678 | INTERCEPTOR(char *, MD2File, const char *filename, char *buf) { | ||
| 8679 | void *ctx; | ||
| 8680 | COMMON_INTERCEPTOR_ENTER(ctx, MD2File, filename, buf); | ||
| 8681 | if (filename) | ||
| 8682 | COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1); | ||
| 8683 | char *ret = REAL(MD2File)(filename, buf); | ||
| 8684 | if (ret) | ||
| 8685 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD2_return_length); | ||
| 8686 | return ret; | ||
| 8687 | } | ||
| 8688 | |||
| 8689 | INTERCEPTOR(char *, MD2Data, const unsigned char *data, unsigned int len, | ||
| 8690 | char *buf) { | ||
| 8691 | void *ctx; | ||
| 8692 | COMMON_INTERCEPTOR_ENTER(ctx, MD2Data, data, len, buf); | ||
| 8693 | if (data && len > 0) | ||
| 8694 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); | ||
| 8695 | char *ret = REAL(MD2Data)(data, len, buf); | ||
| 8696 | if (ret) | ||
| 8697 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD2_return_length); | ||
| 8698 | return ret; | ||
| 8699 | } | ||
| 8700 | |||
| 8701 | #define INIT_MD2 \ | ||
| 8702 | COMMON_INTERCEPT_FUNCTION(MD2Init); \ | ||
| 8703 | COMMON_INTERCEPT_FUNCTION(MD2Update); \ | ||
| 8704 | COMMON_INTERCEPT_FUNCTION(MD2Final); \ | ||
| 8705 | COMMON_INTERCEPT_FUNCTION(MD2End); \ | ||
| 8706 | COMMON_INTERCEPT_FUNCTION(MD2File); \ | ||
| 8707 | COMMON_INTERCEPT_FUNCTION(MD2Data) | ||
| 8708 | #else | ||
| 8709 | #define INIT_MD2 | ||
| 8710 | #endif | ||
| 8711 | |||
| 8712 | #if SANITIZER_INTERCEPT_SHA2 | ||
| 8713 | #define SHA2_INTERCEPTORS(LEN, SHA2_STATE_T) \ | ||
| 8714 | INTERCEPTOR(void, SHA##LEN##_Init, void *context) { \ | ||
| 8715 | void *ctx; \ | ||
| 8716 | COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_Init, context); \ | ||
| 8717 | REAL(SHA##LEN##_Init)(context); \ | ||
| 8718 | if (context) \ | ||
| 8719 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, SHA##LEN##_CTX_sz); \ | ||
| 8720 | } \ | ||
| 8721 | INTERCEPTOR(void, SHA##LEN##_Update, void *context, \ | ||
| 8722 | const u8 *data, SIZE_T len) { \ | ||
| 8723 | void *ctx; \ | ||
| 8724 | COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_Update, context, data, len); \ | ||
| 8725 | if (data && len > 0) \ | ||
| 8726 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); \ | ||
| 8727 | if (context) \ | ||
| 8728 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA##LEN##_CTX_sz); \ | ||
| 8729 | REAL(SHA##LEN##_Update)(context, data, len); \ | ||
| 8730 | if (context) \ | ||
| 8731 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, SHA##LEN##_CTX_sz); \ | ||
| 8732 | } \ | ||
| 8733 | INTERCEPTOR(void, SHA##LEN##_Final, u8 digest[LEN/8], \ | ||
| 8734 | void *context) { \ | ||
| 8735 | void *ctx; \ | ||
| 8736 | CHECK_EQ(SHA##LEN##_digest_length, LEN/8); \ | ||
| 8737 | COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_Final, digest, context); \ | ||
| 8738 | if (context) \ | ||
| 8739 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA##LEN##_CTX_sz); \ | ||
| 8740 | REAL(SHA##LEN##_Final)(digest, context); \ | ||
| 8741 | if (digest) \ | ||
| 8742 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, \ | ||
| 8743 | sizeof(digest[0]) * \ | ||
| 8744 | SHA##LEN##_digest_length); \ | ||
| 8745 | } \ | ||
| 8746 | INTERCEPTOR(char *, SHA##LEN##_End, void *context, char *buf) { \ | ||
| 8747 | void *ctx; \ | ||
| 8748 | COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_End, context, buf); \ | ||
| 8749 | if (context) \ | ||
| 8750 | COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA##LEN##_CTX_sz); \ | ||
| 8751 | char *ret = REAL(SHA##LEN##_End)(context, buf); \ | ||
| 8752 | if (ret) \ | ||
| 8753 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA##LEN##_return_length); \ | ||
| 8754 | return ret; \ | ||
| 8755 | } \ | ||
| 8756 | INTERCEPTOR(char *, SHA##LEN##_File, const char *filename, char *buf) { \ | ||
| 8757 | void *ctx; \ | ||
| 8758 | COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_File, filename, buf); \ | ||
| 8759 | if (filename) \ | ||
| 8760 | COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1);\ | ||
| 8761 | char *ret = REAL(SHA##LEN##_File)(filename, buf); \ | ||
| 8762 | if (ret) \ | ||
| 8763 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA##LEN##_return_length); \ | ||
| 8764 | return ret; \ | ||
| 8765 | } \ | ||
| 8766 | INTERCEPTOR(char *, SHA##LEN##_FileChunk, const char *filename, char *buf, \ | ||
| 8767 | OFF_T offset, OFF_T length) { \ | ||
| 8768 | void *ctx; \ | ||
| 8769 | COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_FileChunk, filename, buf, offset, \ | ||
| 8770 | length); \ | ||
| 8771 | if (filename) \ | ||
| 8772 | COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1);\ | ||
| 8773 | char *ret = REAL(SHA##LEN##_FileChunk)(filename, buf, offset, length); \ | ||
| 8774 | if (ret) \ | ||
| 8775 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA##LEN##_return_length); \ | ||
| 8776 | return ret; \ | ||
| 8777 | } \ | ||
| 8778 | INTERCEPTOR(char *, SHA##LEN##_Data, u8 *data, SIZE_T len, char *buf) { \ | ||
| 8779 | void *ctx; \ | ||
| 8780 | COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_Data, data, len, buf); \ | ||
| 8781 | if (data && len > 0) \ | ||
| 8782 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); \ | ||
| 8783 | char *ret = REAL(SHA##LEN##_Data)(data, len, buf); \ | ||
| 8784 | if (ret) \ | ||
| 8785 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA##LEN##_return_length); \ | ||
| 8786 | return ret; \ | ||
| 8787 | } | ||
| 8788 | |||
| 8789 | SHA2_INTERCEPTORS(224, u32); | ||
| 8790 | SHA2_INTERCEPTORS(256, u32); | ||
| 8791 | SHA2_INTERCEPTORS(384, u64); | ||
| 8792 | SHA2_INTERCEPTORS(512, u64); | ||
| 8793 | |||
| 8794 | #define INIT_SHA2_INTECEPTORS(LEN) \ | ||
| 8795 | COMMON_INTERCEPT_FUNCTION(SHA##LEN##_Init); \ | ||
| 8796 | COMMON_INTERCEPT_FUNCTION(SHA##LEN##_Update); \ | ||
| 8797 | COMMON_INTERCEPT_FUNCTION(SHA##LEN##_Final); \ | ||
| 8798 | COMMON_INTERCEPT_FUNCTION(SHA##LEN##_End); \ | ||
| 8799 | COMMON_INTERCEPT_FUNCTION(SHA##LEN##_File); \ | ||
| 8800 | COMMON_INTERCEPT_FUNCTION(SHA##LEN##_FileChunk); \ | ||
| 8801 | COMMON_INTERCEPT_FUNCTION(SHA##LEN##_Data) | ||
| 8802 | |||
| 8803 | #define INIT_SHA2 \ | ||
| 8804 | INIT_SHA2_INTECEPTORS(224); \ | ||
| 8805 | INIT_SHA2_INTECEPTORS(256); \ | ||
| 8806 | INIT_SHA2_INTECEPTORS(384); \ | ||
| 8807 | INIT_SHA2_INTECEPTORS(512) | ||
| 8808 | #undef SHA2_INTERCEPTORS | ||
| 8809 | #else | ||
| 8810 | #define INIT_SHA2 | ||
| 8811 | #endif | ||
| 8812 | |||
| 8813 | #if SANITIZER_INTERCEPT_VIS | ||
| 8814 | INTERCEPTOR(char *, vis, char *dst, int c, int flag, int nextc) { | ||
| 8815 | void *ctx; | ||
| 8816 | COMMON_INTERCEPTOR_ENTER(ctx, vis, dst, c, flag, nextc); | ||
| 8817 | char *end = REAL(vis)(dst, c, flag, nextc); | ||
| 8818 | // dst is NULL terminated and end points to the NULL char | ||
| 8819 | if (dst && end) | ||
| 8820 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, end - dst + 1); | ||
| 8821 | return end; | ||
| 8822 | } | ||
| 8823 | INTERCEPTOR(char *, nvis, char *dst, SIZE_T dlen, int c, int flag, int nextc) { | ||
| 8824 | void *ctx; | ||
| 8825 | COMMON_INTERCEPTOR_ENTER(ctx, nvis, dst, dlen, c, flag, nextc); | ||
| 8826 | char *end = REAL(nvis)(dst, dlen, c, flag, nextc); | ||
| 8827 | // nvis cannot make sure the dst is NULL terminated | ||
| 8828 | if (dst && end) | ||
| 8829 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, end - dst + 1); | ||
| 8830 | return end; | ||
| 8831 | } | ||
| 8832 | INTERCEPTOR(int, strvis, char *dst, const char *src, int flag) { | ||
| 8833 | void *ctx; | ||
| 8834 | COMMON_INTERCEPTOR_ENTER(ctx, strvis, dst, src, flag); | ||
| 8835 | if (src) | ||
| 8836 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); | ||
| 8837 | int len = REAL(strvis)(dst, src, flag); | ||
| 8838 | if (dst) | ||
| 8839 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, len + 1); | ||
| 8840 | return len; | ||
| 8841 | } | ||
| 8842 | INTERCEPTOR(int, stravis, char **dst, const char *src, int flag) { | ||
| 8843 | void *ctx; | ||
| 8844 | COMMON_INTERCEPTOR_ENTER(ctx, stravis, dst, src, flag); | ||
| 8845 | if (src) | ||
| 8846 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); | ||
| 8847 | int len = REAL(stravis)(dst, src, flag); | ||
| 8848 | if (dst) { | ||
| 8849 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(char *)); | ||
| 8850 | if (*dst) | ||
| 8851 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *dst, len + 1); | ||
| 8852 | } | ||
| 8853 | return len; | ||
| 8854 | } | ||
| 8855 | INTERCEPTOR(int, strnvis, char *dst, SIZE_T dlen, const char *src, int flag) { | ||
| 8856 | void *ctx; | ||
| 8857 | COMMON_INTERCEPTOR_ENTER(ctx, strnvis, dst, dlen, src, flag); | ||
| 8858 | if (src) | ||
| 8859 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); | ||
| 8860 | int len = REAL(strnvis)(dst, dlen, src, flag); | ||
| 8861 | // The interface will be valid even if there is no space for NULL char | ||
| 8862 | if (dst && len > 0) | ||
| 8863 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, len + 1); | ||
| 8864 | return len; | ||
| 8865 | } | ||
| 8866 | INTERCEPTOR(int, strvisx, char *dst, const char *src, SIZE_T len, int flag) { | ||
| 8867 | void *ctx; | ||
| 8868 | COMMON_INTERCEPTOR_ENTER(ctx, strvisx, dst, src, len, flag); | ||
| 8869 | if (src) | ||
| 8870 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); | ||
| 8871 | int ret = REAL(strvisx)(dst, src, len, flag); | ||
| 8872 | if (dst) | ||
| 8873 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); | ||
| 8874 | return ret; | ||
| 8875 | } | ||
| 8876 | INTERCEPTOR(int, strnvisx, char *dst, SIZE_T dlen, const char *src, SIZE_T len, | ||
| 8877 | int flag) { | ||
| 8878 | void *ctx; | ||
| 8879 | COMMON_INTERCEPTOR_ENTER(ctx, strnvisx, dst, dlen, src, len, flag); | ||
| 8880 | if (src) | ||
| 8881 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); | ||
| 8882 | int ret = REAL(strnvisx)(dst, dlen, src, len, flag); | ||
| 8883 | if (dst && ret >= 0) | ||
| 8884 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); | ||
| 8885 | return ret; | ||
| 8886 | } | ||
| 8887 | INTERCEPTOR(int, strenvisx, char *dst, SIZE_T dlen, const char *src, SIZE_T len, | ||
| 8888 | int flag, int *cerr_ptr) { | ||
| 8889 | void *ctx; | ||
| 8890 | COMMON_INTERCEPTOR_ENTER(ctx, strenvisx, dst, dlen, src, len, flag, cerr_ptr); | ||
| 8891 | if (src) | ||
| 8892 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); | ||
| 8893 | // FIXME: only need to be checked when "flag | VIS_NOLOCALE" doesn't hold | ||
| 8894 | // according to the implementation | ||
| 8895 | if (cerr_ptr) | ||
| 8896 | COMMON_INTERCEPTOR_READ_RANGE(ctx, cerr_ptr, sizeof(int)); | ||
| 8897 | int ret = REAL(strenvisx)(dst, dlen, src, len, flag, cerr_ptr); | ||
| 8898 | if (dst && ret >= 0) | ||
| 8899 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); | ||
| 8900 | if (cerr_ptr) | ||
| 8901 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cerr_ptr, sizeof(int)); | ||
| 8902 | return ret; | ||
| 8903 | } | ||
| 8904 | INTERCEPTOR(char *, svis, char *dst, int c, int flag, int nextc, | ||
| 8905 | const char *extra) { | ||
| 8906 | void *ctx; | ||
| 8907 | COMMON_INTERCEPTOR_ENTER(ctx, svis, dst, c, flag, nextc, extra); | ||
| 8908 | if (extra) | ||
| 8909 | COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1); | ||
| 8910 | char *end = REAL(svis)(dst, c, flag, nextc, extra); | ||
| 8911 | if (dst && end) | ||
| 8912 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, end - dst + 1); | ||
| 8913 | return end; | ||
| 8914 | } | ||
| 8915 | INTERCEPTOR(char *, snvis, char *dst, SIZE_T dlen, int c, int flag, int nextc, | ||
| 8916 | const char *extra) { | ||
| 8917 | void *ctx; | ||
| 8918 | COMMON_INTERCEPTOR_ENTER(ctx, snvis, dst, dlen, c, flag, nextc, extra); | ||
| 8919 | if (extra) | ||
| 8920 | COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1); | ||
| 8921 | char *end = REAL(snvis)(dst, dlen, c, flag, nextc, extra); | ||
| 8922 | if (dst && end) | ||
| 8923 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, | ||
| 8924 | Min((SIZE_T)(end - dst + 1), dlen)); | ||
| 8925 | return end; | ||
| 8926 | } | ||
| 8927 | INTERCEPTOR(int, strsvis, char *dst, const char *src, int flag, | ||
| 8928 | const char *extra) { | ||
| 8929 | void *ctx; | ||
| 8930 | COMMON_INTERCEPTOR_ENTER(ctx, strsvis, dst, src, flag, extra); | ||
| 8931 | if (src) | ||
| 8932 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); | ||
| 8933 | if (extra) | ||
| 8934 | COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1); | ||
| 8935 | int len = REAL(strsvis)(dst, src, flag, extra); | ||
| 8936 | if (dst) | ||
| 8937 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, len + 1); | ||
| 8938 | return len; | ||
| 8939 | } | ||
| 8940 | INTERCEPTOR(int, strsnvis, char *dst, SIZE_T dlen, const char *src, int flag, | ||
| 8941 | const char *extra) { | ||
| 8942 | void *ctx; | ||
| 8943 | COMMON_INTERCEPTOR_ENTER(ctx, strsnvis, dst, dlen, src, flag, extra); | ||
| 8944 | if (src) | ||
| 8945 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); | ||
| 8946 | if (extra) | ||
| 8947 | COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1); | ||
| 8948 | int len = REAL(strsnvis)(dst, dlen, src, flag, extra); | ||
| 8949 | // The interface will be valid even if there is no space for NULL char | ||
| 8950 | if (dst && len >= 0) | ||
| 8951 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, len + 1); | ||
| 8952 | return len; | ||
| 8953 | } | ||
| 8954 | INTERCEPTOR(int, strsvisx, char *dst, const char *src, SIZE_T len, int flag, | ||
| 8955 | const char *extra) { | ||
| 8956 | void *ctx; | ||
| 8957 | COMMON_INTERCEPTOR_ENTER(ctx, strsvisx, dst, src, len, flag, extra); | ||
| 8958 | if (src) | ||
| 8959 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); | ||
| 8960 | if (extra) | ||
| 8961 | COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1); | ||
| 8962 | int ret = REAL(strsvisx)(dst, src, len, flag, extra); | ||
| 8963 | if (dst) | ||
| 8964 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); | ||
| 8965 | return ret; | ||
| 8966 | } | ||
| 8967 | INTERCEPTOR(int, strsnvisx, char *dst, SIZE_T dlen, const char *src, SIZE_T len, | ||
| 8968 | int flag, const char *extra) { | ||
| 8969 | void *ctx; | ||
| 8970 | COMMON_INTERCEPTOR_ENTER(ctx, strsnvisx, dst, dlen, src, len, flag, extra); | ||
| 8971 | if (src) | ||
| 8972 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); | ||
| 8973 | if (extra) | ||
| 8974 | COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1); | ||
| 8975 | int ret = REAL(strsnvisx)(dst, dlen, src, len, flag, extra); | ||
| 8976 | if (dst && ret >= 0) | ||
| 8977 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); | ||
| 8978 | return ret; | ||
| 8979 | } | ||
| 8980 | INTERCEPTOR(int, strsenvisx, char *dst, SIZE_T dlen, const char *src, | ||
| 8981 | SIZE_T len, int flag, const char *extra, int *cerr_ptr) { | ||
| 8982 | void *ctx; | ||
| 8983 | COMMON_INTERCEPTOR_ENTER(ctx, strsenvisx, dst, dlen, src, len, flag, extra, | ||
| 8984 | cerr_ptr); | ||
| 8985 | if (src) | ||
| 8986 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); | ||
| 8987 | if (extra) | ||
| 8988 | COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1); | ||
| 8989 | // FIXME: only need to be checked when "flag | VIS_NOLOCALE" doesn't hold | ||
| 8990 | // according to the implementation | ||
| 8991 | if (cerr_ptr) | ||
| 8992 | COMMON_INTERCEPTOR_READ_RANGE(ctx, cerr_ptr, sizeof(int)); | ||
| 8993 | int ret = REAL(strsenvisx)(dst, dlen, src, len, flag, extra, cerr_ptr); | ||
| 8994 | if (dst && ret >= 0) | ||
| 8995 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); | ||
| 8996 | if (cerr_ptr) | ||
| 8997 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cerr_ptr, sizeof(int)); | ||
| 8998 | return ret; | ||
| 8999 | } | ||
| 9000 | INTERCEPTOR(int, unvis, char *cp, int c, int *astate, int flag) { | ||
| 9001 | void *ctx; | ||
| 9002 | COMMON_INTERCEPTOR_ENTER(ctx, unvis, cp, c, astate, flag); | ||
| 9003 | if (astate) | ||
| 9004 | COMMON_INTERCEPTOR_READ_RANGE(ctx, astate, sizeof(*astate)); | ||
| 9005 | int ret = REAL(unvis)(cp, c, astate, flag); | ||
| 9006 | if (ret == unvis_valid || ret == unvis_validpush) { | ||
| 9007 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cp, sizeof(*cp)); | ||
| 9008 | } | ||
| 9009 | return ret; | ||
| 9010 | } | ||
| 9011 | INTERCEPTOR(int, strunvis, char *dst, const char *src) { | ||
| 9012 | void *ctx; | ||
| 9013 | COMMON_INTERCEPTOR_ENTER(ctx, strunvis, dst, src); | ||
| 9014 | if (src) | ||
| 9015 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); | ||
| 9016 | int ret = REAL(strunvis)(dst, src); | ||
| 9017 | if (ret != -1) | ||
| 9018 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); | ||
| 9019 | return ret; | ||
| 9020 | } | ||
| 9021 | INTERCEPTOR(int, strnunvis, char *dst, SIZE_T dlen, const char *src) { | ||
| 9022 | void *ctx; | ||
| 9023 | COMMON_INTERCEPTOR_ENTER(ctx, strnunvis, dst, dlen, src); | ||
| 9024 | if (src) | ||
| 9025 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); | ||
| 9026 | int ret = REAL(strnunvis)(dst, dlen, src); | ||
| 9027 | if (ret != -1) | ||
| 9028 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); | ||
| 9029 | return ret; | ||
| 9030 | } | ||
| 9031 | INTERCEPTOR(int, strunvisx, char *dst, const char *src, int flag) { | ||
| 9032 | void *ctx; | ||
| 9033 | COMMON_INTERCEPTOR_ENTER(ctx, strunvisx, dst, src, flag); | ||
| 9034 | if (src) | ||
| 9035 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); | ||
| 9036 | int ret = REAL(strunvisx)(dst, src, flag); | ||
| 9037 | if (ret != -1) | ||
| 9038 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); | ||
| 9039 | return ret; | ||
| 9040 | } | ||
| 9041 | INTERCEPTOR(int, strnunvisx, char *dst, SIZE_T dlen, const char *src, | ||
| 9042 | int flag) { | ||
| 9043 | void *ctx; | ||
| 9044 | COMMON_INTERCEPTOR_ENTER(ctx, strnunvisx, dst, dlen, src, flag); | ||
| 9045 | if (src) | ||
| 9046 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); | ||
| 9047 | int ret = REAL(strnunvisx)(dst, dlen, src, flag); | ||
| 9048 | if (ret != -1) | ||
| 9049 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); | ||
| 9050 | return ret; | ||
| 9051 | } | ||
| 9052 | #define INIT_VIS \ | ||
| 9053 | COMMON_INTERCEPT_FUNCTION(vis); \ | ||
| 9054 | COMMON_INTERCEPT_FUNCTION(nvis); \ | ||
| 9055 | COMMON_INTERCEPT_FUNCTION(strvis); \ | ||
| 9056 | COMMON_INTERCEPT_FUNCTION(stravis); \ | ||
| 9057 | COMMON_INTERCEPT_FUNCTION(strnvis); \ | ||
| 9058 | COMMON_INTERCEPT_FUNCTION(strvisx); \ | ||
| 9059 | COMMON_INTERCEPT_FUNCTION(strnvisx); \ | ||
| 9060 | COMMON_INTERCEPT_FUNCTION(strenvisx); \ | ||
| 9061 | COMMON_INTERCEPT_FUNCTION(svis); \ | ||
| 9062 | COMMON_INTERCEPT_FUNCTION(snvis); \ | ||
| 9063 | COMMON_INTERCEPT_FUNCTION(strsvis); \ | ||
| 9064 | COMMON_INTERCEPT_FUNCTION(strsnvis); \ | ||
| 9065 | COMMON_INTERCEPT_FUNCTION(strsvisx); \ | ||
| 9066 | COMMON_INTERCEPT_FUNCTION(strsnvisx); \ | ||
| 9067 | COMMON_INTERCEPT_FUNCTION(strsenvisx); \ | ||
| 9068 | COMMON_INTERCEPT_FUNCTION(unvis); \ | ||
| 9069 | COMMON_INTERCEPT_FUNCTION(strunvis); \ | ||
| 9070 | COMMON_INTERCEPT_FUNCTION(strnunvis); \ | ||
| 9071 | COMMON_INTERCEPT_FUNCTION(strunvisx); \ | ||
| 9072 | COMMON_INTERCEPT_FUNCTION(strnunvisx) | ||
| 9073 | #else | ||
| 9074 | #define INIT_VIS | ||
| 9075 | #endif | ||
| 9076 | |||
| 9077 | #if SANITIZER_INTERCEPT_CDB | ||
| 9078 | INTERCEPTOR(struct __sanitizer_cdbr *, cdbr_open, const char *path, int flags) { | ||
| 9079 | void *ctx; | ||
| 9080 | COMMON_INTERCEPTOR_ENTER(ctx, cdbr_open, path, flags); | ||
| 9081 | if (path) | ||
| 9082 | COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 9083 | struct __sanitizer_cdbr *cdbr = REAL(cdbr_open)(path, flags); | ||
| 9084 | if (cdbr) | ||
| 9085 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbr, sizeof(*cdbr)); | ||
| 9086 | return cdbr; | ||
| 9087 | } | ||
| 9088 | |||
| 9089 | INTERCEPTOR(struct __sanitizer_cdbr *, cdbr_open_mem, void *base, SIZE_T size, | ||
| 9090 | int flags, void (*unmap)(void *, void *, SIZE_T), void *cookie) { | ||
| 9091 | void *ctx; | ||
| 9092 | COMMON_INTERCEPTOR_ENTER(ctx, cdbr_open_mem, base, size, flags, unmap, | ||
| 9093 | cookie); | ||
| 9094 | if (base && size) | ||
| 9095 | COMMON_INTERCEPTOR_READ_RANGE(ctx, base, size); | ||
| 9096 | struct __sanitizer_cdbr *cdbr = | ||
| 9097 | REAL(cdbr_open_mem)(base, size, flags, unmap, cookie); | ||
| 9098 | if (cdbr) | ||
| 9099 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbr, sizeof(*cdbr)); | ||
| 9100 | return cdbr; | ||
| 9101 | } | ||
| 9102 | |||
| 9103 | INTERCEPTOR(u32, cdbr_entries, struct __sanitizer_cdbr *cdbr) { | ||
| 9104 | void *ctx; | ||
| 9105 | COMMON_INTERCEPTOR_ENTER(ctx, cdbr_entries, cdbr); | ||
| 9106 | if (cdbr) | ||
| 9107 | COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbr, sizeof(*cdbr)); | ||
| 9108 | return REAL(cdbr_entries)(cdbr); | ||
| 9109 | } | ||
| 9110 | |||
| 9111 | INTERCEPTOR(int, cdbr_get, struct __sanitizer_cdbr *cdbr, u32 index, | ||
| 9112 | const void **data, SIZE_T *datalen) { | ||
| 9113 | void *ctx; | ||
| 9114 | COMMON_INTERCEPTOR_ENTER(ctx, cdbr_get, cdbr, index, data, datalen); | ||
| 9115 | if (cdbr) | ||
| 9116 | COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbr, sizeof(*cdbr)); | ||
| 9117 | int ret = REAL(cdbr_get)(cdbr, index, data, datalen); | ||
| 9118 | if (!ret) { | ||
| 9119 | if (data) | ||
| 9120 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(*data)); | ||
| 9121 | if (datalen) | ||
| 9122 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datalen, sizeof(*datalen)); | ||
| 9123 | if (data && datalen) | ||
| 9124 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *data, *datalen); | ||
| 9125 | } | ||
| 9126 | return ret; | ||
| 9127 | } | ||
| 9128 | |||
| 9129 | INTERCEPTOR(int, cdbr_find, struct __sanitizer_cdbr *cdbr, const void *key, | ||
| 9130 | SIZE_T keylen, const void **data, SIZE_T *datalen) { | ||
| 9131 | void *ctx; | ||
| 9132 | COMMON_INTERCEPTOR_ENTER(ctx, cdbr_find, cdbr, key, keylen, data, datalen); | ||
| 9133 | if (cdbr) | ||
| 9134 | COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbr, sizeof(*cdbr)); | ||
| 9135 | if (key) | ||
| 9136 | COMMON_INTERCEPTOR_READ_RANGE(ctx, key, keylen); | ||
| 9137 | int ret = REAL(cdbr_find)(cdbr, key, keylen, data, datalen); | ||
| 9138 | if (!ret) { | ||
| 9139 | if (data) | ||
| 9140 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(*data)); | ||
| 9141 | if (datalen) | ||
| 9142 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datalen, sizeof(*datalen)); | ||
| 9143 | if (data && datalen) | ||
| 9144 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *data, *datalen); | ||
| 9145 | } | ||
| 9146 | return ret; | ||
| 9147 | } | ||
| 9148 | |||
| 9149 | INTERCEPTOR(void, cdbr_close, struct __sanitizer_cdbr *cdbr) { | ||
| 9150 | void *ctx; | ||
| 9151 | COMMON_INTERCEPTOR_ENTER(ctx, cdbr_close, cdbr); | ||
| 9152 | if (cdbr) | ||
| 9153 | COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbr, sizeof(*cdbr)); | ||
| 9154 | REAL(cdbr_close)(cdbr); | ||
| 9155 | } | ||
| 9156 | |||
| 9157 | INTERCEPTOR(struct __sanitizer_cdbw *, cdbw_open) { | ||
| 9158 | void *ctx; | ||
| 9159 | COMMON_INTERCEPTOR_ENTER(ctx, cdbw_open); | ||
| 9160 | struct __sanitizer_cdbw *ret = REAL(cdbw_open)(); | ||
| 9161 | if (ret) | ||
| 9162 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, sizeof(*ret)); | ||
| 9163 | return ret; | ||
| 9164 | } | ||
| 9165 | |||
| 9166 | INTERCEPTOR(int, cdbw_put, struct __sanitizer_cdbw *cdbw, const void *key, | ||
| 9167 | SIZE_T keylen, const void *data, SIZE_T datalen) { | ||
| 9168 | void *ctx; | ||
| 9169 | COMMON_INTERCEPTOR_ENTER(ctx, cdbw_put, cdbw, key, keylen, data, datalen); | ||
| 9170 | if (cdbw) | ||
| 9171 | COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbw, sizeof(*cdbw)); | ||
| 9172 | if (data && datalen) | ||
| 9173 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, datalen); | ||
| 9174 | if (key && keylen) | ||
| 9175 | COMMON_INTERCEPTOR_READ_RANGE(ctx, key, keylen); | ||
| 9176 | int ret = REAL(cdbw_put)(cdbw, key, keylen, data, datalen); | ||
| 9177 | if (!ret && cdbw) | ||
| 9178 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbw, sizeof(*cdbw)); | ||
| 9179 | return ret; | ||
| 9180 | } | ||
| 9181 | |||
| 9182 | INTERCEPTOR(int, cdbw_put_data, struct __sanitizer_cdbw *cdbw, const void *data, | ||
| 9183 | SIZE_T datalen, u32 *index) { | ||
| 9184 | void *ctx; | ||
| 9185 | COMMON_INTERCEPTOR_ENTER(ctx, cdbw_put_data, cdbw, data, datalen, index); | ||
| 9186 | if (cdbw) | ||
| 9187 | COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbw, sizeof(*cdbw)); | ||
| 9188 | if (data && datalen) | ||
| 9189 | COMMON_INTERCEPTOR_READ_RANGE(ctx, data, datalen); | ||
| 9190 | int ret = REAL(cdbw_put_data)(cdbw, data, datalen, index); | ||
| 9191 | if (!ret) { | ||
| 9192 | if (index) | ||
| 9193 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, index, sizeof(*index)); | ||
| 9194 | if (cdbw) | ||
| 9195 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbw, sizeof(*cdbw)); | ||
| 9196 | } | ||
| 9197 | return ret; | ||
| 9198 | } | ||
| 9199 | |||
| 9200 | INTERCEPTOR(int, cdbw_put_key, struct __sanitizer_cdbw *cdbw, const void *key, | ||
| 9201 | SIZE_T keylen, u32 index) { | ||
| 9202 | void *ctx; | ||
| 9203 | COMMON_INTERCEPTOR_ENTER(ctx, cdbw_put_key, cdbw, key, keylen, index); | ||
| 9204 | if (cdbw) | ||
| 9205 | COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbw, sizeof(*cdbw)); | ||
| 9206 | if (key && keylen) | ||
| 9207 | COMMON_INTERCEPTOR_READ_RANGE(ctx, key, keylen); | ||
| 9208 | int ret = REAL(cdbw_put_key)(cdbw, key, keylen, index); | ||
| 9209 | if (!ret && cdbw) | ||
| 9210 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbw, sizeof(*cdbw)); | ||
| 9211 | return ret; | ||
| 9212 | } | ||
| 9213 | |||
| 9214 | INTERCEPTOR(int, cdbw_output, struct __sanitizer_cdbw *cdbw, int output, | ||
| 9215 | const char descr[16], u32 (*seedgen)(void)) { | ||
| 9216 | void *ctx; | ||
| 9217 | COMMON_INTERCEPTOR_ENTER(ctx, cdbw_output, cdbw, output, descr, seedgen); | ||
| 9218 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, output); | ||
| 9219 | if (cdbw) | ||
| 9220 | COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbw, sizeof(*cdbw)); | ||
| 9221 | if (descr) | ||
| 9222 | COMMON_INTERCEPTOR_READ_RANGE(ctx, descr, internal_strnlen(descr, 16)); | ||
| 9223 | if (seedgen) | ||
| 9224 | COMMON_INTERCEPTOR_READ_RANGE(ctx, (void *)seedgen, sizeof(seedgen)); | ||
| 9225 | int ret = REAL(cdbw_output)(cdbw, output, descr, seedgen); | ||
| 9226 | if (!ret) { | ||
| 9227 | if (cdbw) | ||
| 9228 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbw, sizeof(*cdbw)); | ||
| 9229 | if (output >= 0) | ||
| 9230 | COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, output); | ||
| 9231 | } | ||
| 9232 | return ret; | ||
| 9233 | } | ||
| 9234 | |||
| 9235 | INTERCEPTOR(void, cdbw_close, struct __sanitizer_cdbw *cdbw) { | ||
| 9236 | void *ctx; | ||
| 9237 | COMMON_INTERCEPTOR_ENTER(ctx, cdbw_close, cdbw); | ||
| 9238 | if (cdbw) | ||
| 9239 | COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbw, sizeof(*cdbw)); | ||
| 9240 | REAL(cdbw_close)(cdbw); | ||
| 9241 | } | ||
| 9242 | |||
| 9243 | #define INIT_CDB \ | ||
| 9244 | COMMON_INTERCEPT_FUNCTION(cdbr_open); \ | ||
| 9245 | COMMON_INTERCEPT_FUNCTION(cdbr_open_mem); \ | ||
| 9246 | COMMON_INTERCEPT_FUNCTION(cdbr_entries); \ | ||
| 9247 | COMMON_INTERCEPT_FUNCTION(cdbr_get); \ | ||
| 9248 | COMMON_INTERCEPT_FUNCTION(cdbr_find); \ | ||
| 9249 | COMMON_INTERCEPT_FUNCTION(cdbr_close); \ | ||
| 9250 | COMMON_INTERCEPT_FUNCTION(cdbw_open); \ | ||
| 9251 | COMMON_INTERCEPT_FUNCTION(cdbw_put); \ | ||
| 9252 | COMMON_INTERCEPT_FUNCTION(cdbw_put_data); \ | ||
| 9253 | COMMON_INTERCEPT_FUNCTION(cdbw_put_key); \ | ||
| 9254 | COMMON_INTERCEPT_FUNCTION(cdbw_output); \ | ||
| 9255 | COMMON_INTERCEPT_FUNCTION(cdbw_close) | ||
| 9256 | #else | ||
| 9257 | #define INIT_CDB | ||
| 9258 | #endif | ||
| 9259 | |||
| 9260 | #if SANITIZER_INTERCEPT_GETFSENT | ||
| 9261 | INTERCEPTOR(void *, getfsent) { | ||
| 9262 | void *ctx; | ||
| 9263 | COMMON_INTERCEPTOR_ENTER(ctx, getfsent); | ||
| 9264 | void *ret = REAL(getfsent)(); | ||
| 9265 | if (ret) | ||
| 9266 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, struct_fstab_sz); | ||
| 9267 | return ret; | ||
| 9268 | } | ||
| 9269 | |||
| 9270 | INTERCEPTOR(void *, getfsspec, const char *spec) { | ||
| 9271 | void *ctx; | ||
| 9272 | COMMON_INTERCEPTOR_ENTER(ctx, getfsspec, spec); | ||
| 9273 | if (spec) | ||
| 9274 | COMMON_INTERCEPTOR_READ_RANGE(ctx, spec, REAL(strlen)(spec) + 1); | ||
| 9275 | void *ret = REAL(getfsspec)(spec); | ||
| 9276 | if (ret) | ||
| 9277 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, struct_fstab_sz); | ||
| 9278 | return ret; | ||
| 9279 | } | ||
| 9280 | |||
| 9281 | INTERCEPTOR(void *, getfsfile, const char *file) { | ||
| 9282 | void *ctx; | ||
| 9283 | COMMON_INTERCEPTOR_ENTER(ctx, getfsfile, file); | ||
| 9284 | if (file) | ||
| 9285 | COMMON_INTERCEPTOR_READ_RANGE(ctx, file, REAL(strlen)(file) + 1); | ||
| 9286 | void *ret = REAL(getfsfile)(file); | ||
| 9287 | if (ret) | ||
| 9288 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, struct_fstab_sz); | ||
| 9289 | return ret; | ||
| 9290 | } | ||
| 9291 | |||
| 9292 | #define INIT_GETFSENT \ | ||
| 9293 | COMMON_INTERCEPT_FUNCTION(getfsent); \ | ||
| 9294 | COMMON_INTERCEPT_FUNCTION(getfsspec); \ | ||
| 9295 | COMMON_INTERCEPT_FUNCTION(getfsfile); | ||
| 9296 | #else | ||
| 9297 | #define INIT_GETFSENT | ||
| 9298 | #endif | ||
| 9299 | |||
| 9300 | #if SANITIZER_INTERCEPT_ARC4RANDOM | ||
| 9301 | INTERCEPTOR(void, arc4random_buf, void *buf, SIZE_T len) { | ||
| 9302 | void *ctx; | ||
| 9303 | COMMON_INTERCEPTOR_ENTER(ctx, arc4random_buf, buf, len); | ||
| 9304 | REAL(arc4random_buf)(buf, len); | ||
| 9305 | if (buf && len) | ||
| 9306 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, len); | ||
| 9307 | } | ||
| 9308 | |||
| 9309 | INTERCEPTOR(void, arc4random_addrandom, u8 *dat, int datlen) { | ||
| 9310 | void *ctx; | ||
| 9311 | COMMON_INTERCEPTOR_ENTER(ctx, arc4random_addrandom, dat, datlen); | ||
| 9312 | if (dat && datlen) | ||
| 9313 | COMMON_INTERCEPTOR_READ_RANGE(ctx, dat, datlen); | ||
| 9314 | REAL(arc4random_addrandom)(dat, datlen); | ||
| 9315 | } | ||
| 9316 | |||
| 9317 | #define INIT_ARC4RANDOM \ | ||
| 9318 | COMMON_INTERCEPT_FUNCTION(arc4random_buf); \ | ||
| 9319 | COMMON_INTERCEPT_FUNCTION(arc4random_addrandom); | ||
| 9320 | #else | ||
| 9321 | #define INIT_ARC4RANDOM | ||
| 9322 | #endif | ||
| 9323 | |||
| 9324 | #if SANITIZER_INTERCEPT_POPEN | ||
| 9325 | INTERCEPTOR(__sanitizer_FILE *, popen, const char *command, const char *type) { | ||
| 9326 | void *ctx; | ||
| 9327 | COMMON_INTERCEPTOR_ENTER(ctx, popen, command, type); | ||
| 9328 | if (command) | ||
| 9329 | COMMON_INTERCEPTOR_READ_RANGE(ctx, command, REAL(strlen)(command) + 1); | ||
| 9330 | if (type) | ||
| 9331 | COMMON_INTERCEPTOR_READ_RANGE(ctx, type, REAL(strlen)(type) + 1); | ||
| 9332 | __sanitizer_FILE *res = REAL(popen)(command, type); | ||
| 9333 | COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, nullptr); | ||
| 9334 | if (res) unpoison_file(res); | ||
| 9335 | return res; | ||
| 9336 | } | ||
| 9337 | #define INIT_POPEN COMMON_INTERCEPT_FUNCTION(popen) | ||
| 9338 | #else | ||
| 9339 | #define INIT_POPEN | ||
| 9340 | #endif | ||
| 9341 | |||
| 9342 | #if SANITIZER_INTERCEPT_POPENVE | ||
| 9343 | INTERCEPTOR(__sanitizer_FILE *, popenve, const char *path, | ||
| 9344 | char *const *argv, char *const *envp, const char *type) { | ||
| 9345 | void *ctx; | ||
| 9346 | COMMON_INTERCEPTOR_ENTER(ctx, popenve, path, argv, envp, type); | ||
| 9347 | if (path) | ||
| 9348 | COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 9349 | if (argv) { | ||
| 9350 | for (char *const *pa = argv; ; ++pa) { | ||
| 9351 | COMMON_INTERCEPTOR_READ_RANGE(ctx, pa, sizeof(char **)); | ||
| 9352 | if (!*pa) | ||
| 9353 | break; | ||
| 9354 | COMMON_INTERCEPTOR_READ_RANGE(ctx, *pa, REAL(strlen)(*pa) + 1); | ||
| 9355 | } | ||
| 9356 | } | ||
| 9357 | if (envp) { | ||
| 9358 | for (char *const *pa = envp; ; ++pa) { | ||
| 9359 | COMMON_INTERCEPTOR_READ_RANGE(ctx, pa, sizeof(char **)); | ||
| 9360 | if (!*pa) | ||
| 9361 | break; | ||
| 9362 | COMMON_INTERCEPTOR_READ_RANGE(ctx, *pa, REAL(strlen)(*pa) + 1); | ||
| 9363 | } | ||
| 9364 | } | ||
| 9365 | if (type) | ||
| 9366 | COMMON_INTERCEPTOR_READ_RANGE(ctx, type, REAL(strlen)(type) + 1); | ||
| 9367 | __sanitizer_FILE *res = REAL(popenve)(path, argv, envp, type); | ||
| 9368 | COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, nullptr); | ||
| 9369 | if (res) unpoison_file(res); | ||
| 9370 | return res; | ||
| 9371 | } | ||
| 9372 | #define INIT_POPENVE COMMON_INTERCEPT_FUNCTION(popenve) | ||
| 9373 | #else | ||
| 9374 | #define INIT_POPENVE | ||
| 9375 | #endif | ||
| 9376 | |||
| 9377 | #if SANITIZER_INTERCEPT_PCLOSE | ||
| 9378 | INTERCEPTOR(int, pclose, __sanitizer_FILE *fp) { | ||
| 9379 | void *ctx; | ||
| 9380 | COMMON_INTERCEPTOR_ENTER(ctx, pclose, fp); | ||
| 9381 | COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); | ||
| 9382 | const FileMetadata *m = GetInterceptorMetadata(fp); | ||
| 9383 | int res = REAL(pclose)(fp); | ||
| 9384 | if (m) { | ||
| 9385 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size); | ||
| 9386 | DeleteInterceptorMetadata(fp); | ||
| 9387 | } | ||
| 9388 | return res; | ||
| 9389 | } | ||
| 9390 | #define INIT_PCLOSE COMMON_INTERCEPT_FUNCTION(pclose); | ||
| 9391 | #else | ||
| 9392 | #define INIT_PCLOSE | ||
| 9393 | #endif | ||
| 9394 | |||
| 9395 | #if SANITIZER_INTERCEPT_FUNOPEN | ||
| 9396 | typedef int (*funopen_readfn)(void *cookie, char *buf, int len); | ||
| 9397 | typedef int (*funopen_writefn)(void *cookie, const char *buf, int len); | ||
| 9398 | typedef OFF_T (*funopen_seekfn)(void *cookie, OFF_T offset, int whence); | ||
| 9399 | typedef int (*funopen_closefn)(void *cookie); | ||
| 9400 | |||
| 9401 | struct WrappedFunopenCookie { | ||
| 9402 | void *real_cookie; | ||
| 9403 | funopen_readfn real_read; | ||
| 9404 | funopen_writefn real_write; | ||
| 9405 | funopen_seekfn real_seek; | ||
| 9406 | funopen_closefn real_close; | ||
| 9407 | }; | ||
| 9408 | |||
| 9409 | static int wrapped_funopen_read(void *cookie, char *buf, int len) { | ||
| 9410 | COMMON_INTERCEPTOR_UNPOISON_PARAM(3); | ||
| 9411 | WrappedFunopenCookie *wrapped_cookie = (WrappedFunopenCookie *)cookie; | ||
| 9412 | funopen_readfn real_read = wrapped_cookie->real_read; | ||
| 9413 | return real_read(wrapped_cookie->real_cookie, buf, len); | ||
| 9414 | } | ||
| 9415 | |||
| 9416 | static int wrapped_funopen_write(void *cookie, const char *buf, int len) { | ||
| 9417 | COMMON_INTERCEPTOR_UNPOISON_PARAM(3); | ||
| 9418 | WrappedFunopenCookie *wrapped_cookie = (WrappedFunopenCookie *)cookie; | ||
| 9419 | funopen_writefn real_write = wrapped_cookie->real_write; | ||
| 9420 | return real_write(wrapped_cookie->real_cookie, buf, len); | ||
| 9421 | } | ||
| 9422 | |||
| 9423 | static OFF_T wrapped_funopen_seek(void *cookie, OFF_T offset, int whence) { | ||
| 9424 | COMMON_INTERCEPTOR_UNPOISON_PARAM(3); | ||
| 9425 | WrappedFunopenCookie *wrapped_cookie = (WrappedFunopenCookie *)cookie; | ||
| 9426 | funopen_seekfn real_seek = wrapped_cookie->real_seek; | ||
| 9427 | return real_seek(wrapped_cookie->real_cookie, offset, whence); | ||
| 9428 | } | ||
| 9429 | |||
| 9430 | static int wrapped_funopen_close(void *cookie) { | ||
| 9431 | COMMON_INTERCEPTOR_UNPOISON_PARAM(1); | ||
| 9432 | WrappedFunopenCookie *wrapped_cookie = (WrappedFunopenCookie *)cookie; | ||
| 9433 | funopen_closefn real_close = wrapped_cookie->real_close; | ||
| 9434 | int res = real_close(wrapped_cookie->real_cookie); | ||
| 9435 | InternalFree(wrapped_cookie); | ||
| 9436 | return res; | ||
| 9437 | } | ||
| 9438 | |||
| 9439 | INTERCEPTOR(__sanitizer_FILE *, funopen, void *cookie, funopen_readfn readfn, | ||
| 9440 | funopen_writefn writefn, funopen_seekfn seekfn, | ||
| 9441 | funopen_closefn closefn) { | ||
| 9442 | void *ctx; | ||
| 9443 | COMMON_INTERCEPTOR_ENTER(ctx, funopen, cookie, readfn, writefn, seekfn, | ||
| 9444 | closefn); | ||
| 9445 | |||
| 9446 | WrappedFunopenCookie *wrapped_cookie = | ||
| 9447 | (WrappedFunopenCookie *)InternalAlloc(sizeof(WrappedFunopenCookie)); | ||
| 9448 | wrapped_cookie->real_cookie = cookie; | ||
| 9449 | wrapped_cookie->real_read = readfn; | ||
| 9450 | wrapped_cookie->real_write = writefn; | ||
| 9451 | wrapped_cookie->real_seek = seekfn; | ||
| 9452 | wrapped_cookie->real_close = closefn; | ||
| 9453 | |||
| 9454 | __sanitizer_FILE *res = | ||
| 9455 | REAL(funopen)(wrapped_cookie, | ||
| 9456 | readfn ? wrapped_funopen_read : nullptr, | ||
| 9457 | writefn ? wrapped_funopen_write : nullptr, | ||
| 9458 | seekfn ? wrapped_funopen_seek : nullptr, | ||
| 9459 | closefn ? wrapped_funopen_close : nullptr); | ||
| 9460 | if (res) | ||
| 9461 | unpoison_file(res); | ||
| 9462 | return res; | ||
| 9463 | } | ||
| 9464 | #define INIT_FUNOPEN COMMON_INTERCEPT_FUNCTION(funopen) | ||
| 9465 | #else | ||
| 9466 | #define INIT_FUNOPEN | ||
| 9467 | #endif | ||
| 9468 | |||
| 9469 | #if SANITIZER_INTERCEPT_FUNOPEN2 | ||
| 9470 | typedef SSIZE_T (*funopen2_readfn)(void *cookie, void *buf, SIZE_T len); | ||
| 9471 | typedef SSIZE_T (*funopen2_writefn)(void *cookie, const void *buf, SIZE_T len); | ||
| 9472 | typedef OFF_T (*funopen2_seekfn)(void *cookie, OFF_T offset, int whence); | ||
| 9473 | typedef int (*funopen2_flushfn)(void *cookie); | ||
| 9474 | typedef int (*funopen2_closefn)(void *cookie); | ||
| 9475 | |||
| 9476 | struct WrappedFunopen2Cookie { | ||
| 9477 | void *real_cookie; | ||
| 9478 | funopen2_readfn real_read; | ||
| 9479 | funopen2_writefn real_write; | ||
| 9480 | funopen2_seekfn real_seek; | ||
| 9481 | funopen2_flushfn real_flush; | ||
| 9482 | funopen2_closefn real_close; | ||
| 9483 | }; | ||
| 9484 | |||
| 9485 | static SSIZE_T wrapped_funopen2_read(void *cookie, void *buf, SIZE_T len) { | ||
| 9486 | COMMON_INTERCEPTOR_UNPOISON_PARAM(3); | ||
| 9487 | WrappedFunopen2Cookie *wrapped_cookie = (WrappedFunopen2Cookie *)cookie; | ||
| 9488 | funopen2_readfn real_read = wrapped_cookie->real_read; | ||
| 9489 | return real_read(wrapped_cookie->real_cookie, buf, len); | ||
| 9490 | } | ||
| 9491 | |||
| 9492 | static SSIZE_T wrapped_funopen2_write(void *cookie, const void *buf, | ||
| 9493 | SIZE_T len) { | ||
| 9494 | COMMON_INTERCEPTOR_UNPOISON_PARAM(3); | ||
| 9495 | WrappedFunopen2Cookie *wrapped_cookie = (WrappedFunopen2Cookie *)cookie; | ||
| 9496 | funopen2_writefn real_write = wrapped_cookie->real_write; | ||
| 9497 | return real_write(wrapped_cookie->real_cookie, buf, len); | ||
| 9498 | } | ||
| 9499 | |||
| 9500 | static OFF_T wrapped_funopen2_seek(void *cookie, OFF_T offset, int whence) { | ||
| 9501 | COMMON_INTERCEPTOR_UNPOISON_PARAM(3); | ||
| 9502 | WrappedFunopen2Cookie *wrapped_cookie = (WrappedFunopen2Cookie *)cookie; | ||
| 9503 | funopen2_seekfn real_seek = wrapped_cookie->real_seek; | ||
| 9504 | return real_seek(wrapped_cookie->real_cookie, offset, whence); | ||
| 9505 | } | ||
| 9506 | |||
| 9507 | static int wrapped_funopen2_flush(void *cookie) { | ||
| 9508 | COMMON_INTERCEPTOR_UNPOISON_PARAM(1); | ||
| 9509 | WrappedFunopen2Cookie *wrapped_cookie = (WrappedFunopen2Cookie *)cookie; | ||
| 9510 | funopen2_flushfn real_flush = wrapped_cookie->real_flush; | ||
| 9511 | return real_flush(wrapped_cookie->real_cookie); | ||
| 9512 | } | ||
| 9513 | |||
| 9514 | static int wrapped_funopen2_close(void *cookie) { | ||
| 9515 | COMMON_INTERCEPTOR_UNPOISON_PARAM(1); | ||
| 9516 | WrappedFunopen2Cookie *wrapped_cookie = (WrappedFunopen2Cookie *)cookie; | ||
| 9517 | funopen2_closefn real_close = wrapped_cookie->real_close; | ||
| 9518 | int res = real_close(wrapped_cookie->real_cookie); | ||
| 9519 | InternalFree(wrapped_cookie); | ||
| 9520 | return res; | ||
| 9521 | } | ||
| 9522 | |||
| 9523 | INTERCEPTOR(__sanitizer_FILE *, funopen2, void *cookie, funopen2_readfn readfn, | ||
| 9524 | funopen2_writefn writefn, funopen2_seekfn seekfn, | ||
| 9525 | funopen2_flushfn flushfn, funopen2_closefn closefn) { | ||
| 9526 | void *ctx; | ||
| 9527 | COMMON_INTERCEPTOR_ENTER(ctx, funopen2, cookie, readfn, writefn, seekfn, | ||
| 9528 | flushfn, closefn); | ||
| 9529 | |||
| 9530 | WrappedFunopen2Cookie *wrapped_cookie = | ||
| 9531 | (WrappedFunopen2Cookie *)InternalAlloc(sizeof(WrappedFunopen2Cookie)); | ||
| 9532 | wrapped_cookie->real_cookie = cookie; | ||
| 9533 | wrapped_cookie->real_read = readfn; | ||
| 9534 | wrapped_cookie->real_write = writefn; | ||
| 9535 | wrapped_cookie->real_seek = seekfn; | ||
| 9536 | wrapped_cookie->real_flush = flushfn; | ||
| 9537 | wrapped_cookie->real_close = closefn; | ||
| 9538 | |||
| 9539 | __sanitizer_FILE *res = | ||
| 9540 | REAL(funopen2)(wrapped_cookie, | ||
| 9541 | readfn ? wrapped_funopen2_read : nullptr, | ||
| 9542 | writefn ? wrapped_funopen2_write : nullptr, | ||
| 9543 | seekfn ? wrapped_funopen2_seek : nullptr, | ||
| 9544 | flushfn ? wrapped_funopen2_flush : nullptr, | ||
| 9545 | closefn ? wrapped_funopen2_close : nullptr); | ||
| 9546 | if (res) | ||
| 9547 | unpoison_file(res); | ||
| 9548 | return res; | ||
| 9549 | } | ||
| 9550 | #define INIT_FUNOPEN2 COMMON_INTERCEPT_FUNCTION(funopen2) | ||
| 9551 | #else | ||
| 9552 | #define INIT_FUNOPEN2 | ||
| 9553 | #endif | ||
| 9554 | |||
| 9555 | #if SANITIZER_INTERCEPT_FDEVNAME | ||
| 9556 | INTERCEPTOR(char *, fdevname, int fd) { | ||
| 9557 | void *ctx; | ||
| 9558 | COMMON_INTERCEPTOR_ENTER(ctx, fdevname, fd); | ||
| 9559 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 9560 | char *name = REAL(fdevname)(fd); | ||
| 9561 | if (name) { | ||
| 9562 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, REAL(strlen)(name) + 1); | ||
| 9563 | if (fd > 0) | ||
| 9564 | COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 9565 | } | ||
| 9566 | return name; | ||
| 9567 | } | ||
| 9568 | |||
| 9569 | INTERCEPTOR(char *, fdevname_r, int fd, char *buf, SIZE_T len) { | ||
| 9570 | void *ctx; | ||
| 9571 | COMMON_INTERCEPTOR_ENTER(ctx, fdevname_r, fd, buf, len); | ||
| 9572 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 9573 | char *name = REAL(fdevname_r)(fd, buf, len); | ||
| 9574 | if (name && buf && len > 0) { | ||
| 9575 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, REAL(strlen)(buf) + 1); | ||
| 9576 | if (fd > 0) | ||
| 9577 | COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 9578 | } | ||
| 9579 | return name; | ||
| 9580 | } | ||
| 9581 | |||
| 9582 | #define INIT_FDEVNAME \ | ||
| 9583 | COMMON_INTERCEPT_FUNCTION(fdevname); \ | ||
| 9584 | COMMON_INTERCEPT_FUNCTION(fdevname_r); | ||
| 9585 | #else | ||
| 9586 | #define INIT_FDEVNAME | ||
| 9587 | #endif | ||
| 9588 | |||
| 9589 | #if SANITIZER_INTERCEPT_GETUSERSHELL | ||
| 9590 | INTERCEPTOR(char *, getusershell) { | ||
| 9591 | void *ctx; | ||
| 9592 | COMMON_INTERCEPTOR_ENTER(ctx, getusershell); | ||
| 9593 | char *res = REAL(getusershell)(); | ||
| 9594 | if (res) | ||
| 9595 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); | ||
| 9596 | return res; | ||
| 9597 | } | ||
| 9598 | |||
| 9599 | #define INIT_GETUSERSHELL COMMON_INTERCEPT_FUNCTION(getusershell); | ||
| 9600 | #else | ||
| 9601 | #define INIT_GETUSERSHELL | ||
| 9602 | #endif | ||
| 9603 | |||
| 9604 | #if SANITIZER_INTERCEPT_SL_INIT | ||
| 9605 | INTERCEPTOR(void *, sl_init) { | ||
| 9606 | void *ctx; | ||
| 9607 | COMMON_INTERCEPTOR_ENTER(ctx, sl_init); | ||
| 9608 | void *res = REAL(sl_init)(); | ||
| 9609 | if (res) | ||
| 9610 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, __sanitizer::struct_StringList_sz); | ||
| 9611 | return res; | ||
| 9612 | } | ||
| 9613 | |||
| 9614 | INTERCEPTOR(int, sl_add, void *sl, char *item) { | ||
| 9615 | void *ctx; | ||
| 9616 | COMMON_INTERCEPTOR_ENTER(ctx, sl_add, sl, item); | ||
| 9617 | if (sl) | ||
| 9618 | COMMON_INTERCEPTOR_READ_RANGE(ctx, sl, __sanitizer::struct_StringList_sz); | ||
| 9619 | if (item) | ||
| 9620 | COMMON_INTERCEPTOR_READ_RANGE(ctx, item, REAL(strlen)(item) + 1); | ||
| 9621 | int res = REAL(sl_add)(sl, item); | ||
| 9622 | if (!res) | ||
| 9623 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sl, __sanitizer::struct_StringList_sz); | ||
| 9624 | return res; | ||
| 9625 | } | ||
| 9626 | |||
| 9627 | INTERCEPTOR(char *, sl_find, void *sl, const char *item) { | ||
| 9628 | void *ctx; | ||
| 9629 | COMMON_INTERCEPTOR_ENTER(ctx, sl_find, sl, item); | ||
| 9630 | if (sl) | ||
| 9631 | COMMON_INTERCEPTOR_READ_RANGE(ctx, sl, __sanitizer::struct_StringList_sz); | ||
| 9632 | if (item) | ||
| 9633 | COMMON_INTERCEPTOR_READ_RANGE(ctx, item, REAL(strlen)(item) + 1); | ||
| 9634 | char *res = REAL(sl_find)(sl, item); | ||
| 9635 | if (res) | ||
| 9636 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); | ||
| 9637 | return res; | ||
| 9638 | } | ||
| 9639 | |||
| 9640 | INTERCEPTOR(void, sl_free, void *sl, int freeall) { | ||
| 9641 | void *ctx; | ||
| 9642 | COMMON_INTERCEPTOR_ENTER(ctx, sl_free, sl, freeall); | ||
| 9643 | if (sl) | ||
| 9644 | COMMON_INTERCEPTOR_READ_RANGE(ctx, sl, __sanitizer::struct_StringList_sz); | ||
| 9645 | REAL(sl_free)(sl, freeall); | ||
| 9646 | } | ||
| 9647 | |||
| 9648 | #define INIT_SL_INIT \ | ||
| 9649 | COMMON_INTERCEPT_FUNCTION(sl_init); \ | ||
| 9650 | COMMON_INTERCEPT_FUNCTION(sl_add); \ | ||
| 9651 | COMMON_INTERCEPT_FUNCTION(sl_find); \ | ||
| 9652 | COMMON_INTERCEPT_FUNCTION(sl_free); | ||
| 9653 | #else | ||
| 9654 | #define INIT_SL_INIT | ||
| 9655 | #endif | ||
| 9656 | |||
| 9657 | #if SANITIZER_INTERCEPT_GETRANDOM | ||
| 9658 | INTERCEPTOR(SSIZE_T, getrandom, void *buf, SIZE_T buflen, unsigned int flags) { | ||
| 9659 | void *ctx; | ||
| 9660 | COMMON_INTERCEPTOR_ENTER(ctx, getrandom, buf, buflen, flags); | ||
| 9661 | SSIZE_T n = REAL(getrandom)(buf, buflen, flags); | ||
| 9662 | if (n > 0) { | ||
| 9663 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, n); | ||
| 9664 | } | ||
| 9665 | return n; | ||
| 9666 | } | ||
| 9667 | #define INIT_GETRANDOM COMMON_INTERCEPT_FUNCTION(getrandom) | ||
| 9668 | #else | ||
| 9669 | #define INIT_GETRANDOM | ||
| 9670 | #endif | ||
| 9671 | |||
| 9672 | #if SANITIZER_INTERCEPT_CRYPT | ||
| 9673 | INTERCEPTOR(char *, crypt, char *key, char *salt) { | ||
| 9674 | void *ctx; | ||
| 9675 | COMMON_INTERCEPTOR_ENTER(ctx, crypt, key, salt); | ||
| 9676 | COMMON_INTERCEPTOR_READ_RANGE(ctx, key, internal_strlen(key) + 1); | ||
| 9677 | COMMON_INTERCEPTOR_READ_RANGE(ctx, salt, internal_strlen(salt) + 1); | ||
| 9678 | char *res = REAL(crypt)(key, salt); | ||
| 9679 | if (res != nullptr) | ||
| 9680 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); | ||
| 9681 | return res; | ||
| 9682 | } | ||
| 9683 | #define INIT_CRYPT COMMON_INTERCEPT_FUNCTION(crypt); | ||
| 9684 | #else | ||
| 9685 | #define INIT_CRYPT | ||
| 9686 | #endif | ||
| 9687 | |||
| 9688 | #if SANITIZER_INTERCEPT_CRYPT_R | ||
| 9689 | INTERCEPTOR(char *, crypt_r, char *key, char *salt, void *data) { | ||
| 9690 | void *ctx; | ||
| 9691 | COMMON_INTERCEPTOR_ENTER(ctx, crypt_r, key, salt, data); | ||
| 9692 | COMMON_INTERCEPTOR_READ_RANGE(ctx, key, internal_strlen(key) + 1); | ||
| 9693 | COMMON_INTERCEPTOR_READ_RANGE(ctx, salt, internal_strlen(salt) + 1); | ||
| 9694 | char *res = REAL(crypt_r)(key, salt, data); | ||
| 9695 | if (res != nullptr) { | ||
| 9696 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, | ||
| 9697 | __sanitizer::struct_crypt_data_sz); | ||
| 9698 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, internal_strlen(res) + 1); | ||
| 9699 | } | ||
| 9700 | return res; | ||
| 9701 | } | ||
| 9702 | #define INIT_CRYPT_R COMMON_INTERCEPT_FUNCTION(crypt_r); | ||
| 9703 | #else | ||
| 9704 | #define INIT_CRYPT_R | ||
| 9705 | #endif | ||
| 9706 | |||
| 9707 | #if SANITIZER_INTERCEPT_GETENTROPY | ||
| 9708 | INTERCEPTOR(int, getentropy, void *buf, SIZE_T buflen) { | ||
| 9709 | void *ctx; | ||
| 9710 | COMMON_INTERCEPTOR_ENTER(ctx, getentropy, buf, buflen); | ||
| 9711 | int r = REAL(getentropy)(buf, buflen); | ||
| 9712 | if (r == 0) { | ||
| 9713 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen); | ||
| 9714 | } | ||
| 9715 | return r; | ||
| 9716 | } | ||
| 9717 | #define INIT_GETENTROPY COMMON_INTERCEPT_FUNCTION(getentropy) | ||
| 9718 | #else | ||
| 9719 | #define INIT_GETENTROPY | ||
| 9720 | #endif | ||
| 9721 | |||
| 9722 | #if SANITIZER_INTERCEPT_QSORT | ||
| 9723 | // Glibc qsort uses a temporary buffer allocated either on stack or on heap. | ||
| 9724 | // Poisoned memory from there may get copied into the comparator arguments, | ||
| 9725 | // where it needs to be dealt with. But even that is not enough - the results of | ||
| 9726 | // the sort may be copied into the input/output array based on the results of | ||
| 9727 | // the comparator calls, but directly from the temp memory, bypassing the | ||
| 9728 | // unpoisoning done in wrapped_qsort_compar. We deal with this by, again, | ||
| 9729 | // unpoisoning the entire array after the sort is done. | ||
| 9730 | // | ||
| 9731 | // We can not check that the entire array is initialized at the beginning. IMHO, | ||
| 9732 | // it's fine for parts of the sorted objects to contain uninitialized memory, | ||
| 9733 | // ex. as padding in structs. | ||
| 9734 | typedef int (*qsort_compar_f)(const void *, const void *); | ||
| 9735 | static THREADLOCAL qsort_compar_f qsort_compar; | ||
| 9736 | static THREADLOCAL SIZE_T qsort_size; | ||
| 9737 | int wrapped_qsort_compar(const void *a, const void *b) { | ||
| 9738 | COMMON_INTERCEPTOR_UNPOISON_PARAM(2); | ||
| 9739 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, qsort_size); | ||
| 9740 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, qsort_size); | ||
| 9741 | return qsort_compar(a, b); | ||
| 9742 | } | ||
| 9743 | |||
| 9744 | INTERCEPTOR(void, qsort, void *base, SIZE_T nmemb, SIZE_T size, | ||
| 9745 | qsort_compar_f compar) { | ||
| 9746 | void *ctx; | ||
| 9747 | COMMON_INTERCEPTOR_ENTER(ctx, qsort, base, nmemb, size, compar); | ||
| 9748 | // Run the comparator over all array elements to detect any memory issues. | ||
| 9749 | if (nmemb > 1) { | ||
| 9750 | for (SIZE_T i = 0; i < nmemb - 1; ++i) { | ||
| 9751 | void *p = (void *)((char *)base + i * size); | ||
| 9752 | void *q = (void *)((char *)base + (i + 1) * size); | ||
| 9753 | COMMON_INTERCEPTOR_UNPOISON_PARAM(2); | ||
| 9754 | compar(p, q); | ||
| 9755 | } | ||
| 9756 | } | ||
| 9757 | qsort_compar_f old_compar = qsort_compar; | ||
| 9758 | qsort_compar = compar; | ||
| 9759 | SIZE_T old_size = qsort_size; | ||
| 9760 | qsort_size = size; | ||
| 9761 | REAL(qsort)(base, nmemb, size, wrapped_qsort_compar); | ||
| 9762 | qsort_compar = old_compar; | ||
| 9763 | qsort_size = old_size; | ||
| 9764 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size); | ||
| 9765 | } | ||
| 9766 | #define INIT_QSORT COMMON_INTERCEPT_FUNCTION(qsort) | ||
| 9767 | #else | ||
| 9768 | #define INIT_QSORT | ||
| 9769 | #endif | ||
| 9770 | |||
| 9771 | #if SANITIZER_INTERCEPT_QSORT_R | ||
| 9772 | typedef int (*qsort_r_compar_f)(const void *, const void *, void *); | ||
| 9773 | static THREADLOCAL qsort_r_compar_f qsort_r_compar; | ||
| 9774 | static THREADLOCAL SIZE_T qsort_r_size; | ||
| 9775 | int wrapped_qsort_r_compar(const void *a, const void *b, void *arg) { | ||
| 9776 | COMMON_INTERCEPTOR_UNPOISON_PARAM(3); | ||
| 9777 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, qsort_r_size); | ||
| 9778 | COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, qsort_r_size); | ||
| 9779 | return qsort_r_compar(a, b, arg); | ||
| 9780 | } | ||
| 9781 | |||
| 9782 | INTERCEPTOR(void, qsort_r, void *base, SIZE_T nmemb, SIZE_T size, | ||
| 9783 | qsort_r_compar_f compar, void *arg) { | ||
| 9784 | void *ctx; | ||
| 9785 | COMMON_INTERCEPTOR_ENTER(ctx, qsort_r, base, nmemb, size, compar, arg); | ||
| 9786 | // Run the comparator over all array elements to detect any memory issues. | ||
| 9787 | if (nmemb > 1) { | ||
| 9788 | for (SIZE_T i = 0; i < nmemb - 1; ++i) { | ||
| 9789 | void *p = (void *)((char *)base + i * size); | ||
| 9790 | void *q = (void *)((char *)base + (i + 1) * size); | ||
| 9791 | COMMON_INTERCEPTOR_UNPOISON_PARAM(3); | ||
| 9792 | compar(p, q, arg); | ||
| 9793 | } | ||
| 9794 | } | ||
| 9795 | qsort_r_compar_f old_compar = qsort_r_compar; | ||
| 9796 | qsort_r_compar = compar; | ||
| 9797 | SIZE_T old_size = qsort_r_size; | ||
| 9798 | qsort_r_size = size; | ||
| 9799 | REAL(qsort_r)(base, nmemb, size, wrapped_qsort_r_compar, arg); | ||
| 9800 | qsort_r_compar = old_compar; | ||
| 9801 | qsort_r_size = old_size; | ||
| 9802 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size); | ||
| 9803 | } | ||
| 9804 | #define INIT_QSORT_R COMMON_INTERCEPT_FUNCTION(qsort_r) | ||
| 9805 | #else | ||
| 9806 | #define INIT_QSORT_R | ||
| 9807 | #endif | ||
| 9808 | |||
| 9809 | #if SANITIZER_INTERCEPT_SIGALTSTACK | ||
| 9810 | INTERCEPTOR(int, sigaltstack, void *ss, void *oss) { | ||
| 9811 | void *ctx; | ||
| 9812 | COMMON_INTERCEPTOR_ENTER(ctx, sigaltstack, ss, oss); | ||
| 9813 | int r = REAL(sigaltstack)(ss, oss); | ||
| 9814 | if (r == 0 && oss != nullptr) { | ||
| 9815 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oss, struct_stack_t_sz); | ||
| 9816 | } | ||
| 9817 | return r; | ||
| 9818 | } | ||
| 9819 | #define INIT_SIGALTSTACK COMMON_INTERCEPT_FUNCTION(sigaltstack) | ||
| 9820 | #else | ||
| 9821 | #define INIT_SIGALTSTACK | ||
| 9822 | #endif | ||
| 9823 | |||
| 9824 | #if SANITIZER_INTERCEPT_UNAME | ||
| 9825 | INTERCEPTOR(int, uname, struct utsname *utsname) { | ||
| 9826 | #if SANITIZER_LINUX | ||
| 9827 | if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) | ||
| 9828 | return internal_uname(utsname); | ||
| 9829 | #endif | ||
| 9830 | void *ctx; | ||
| 9831 | COMMON_INTERCEPTOR_ENTER(ctx, uname, utsname); | ||
| 9832 | int res = REAL(uname)(utsname); | ||
| 9833 | if (!res) | ||
| 9834 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname, | ||
| 9835 | __sanitizer::struct_utsname_sz); | ||
| 9836 | return res; | ||
| 9837 | } | ||
| 9838 | #define INIT_UNAME COMMON_INTERCEPT_FUNCTION(uname) | ||
| 9839 | #else | ||
| 9840 | #define INIT_UNAME | ||
| 9841 | #endif | ||
| 9842 | |||
| 9843 | #if SANITIZER_INTERCEPT___XUNAME | ||
| 9844 | // FreeBSD's <sys/utsname.h> define uname() as | ||
| 9845 | // static __inline int uname(struct utsname *name) { | ||
| 9846 | // return __xuname(SYS_NMLN, (void*)name); | ||
| 9847 | // } | ||
| 9848 | INTERCEPTOR(int, __xuname, int size, void *utsname) { | ||
| 9849 | void *ctx; | ||
| 9850 | COMMON_INTERCEPTOR_ENTER(ctx, __xuname, size, utsname); | ||
| 9851 | int res = REAL(__xuname)(size, utsname); | ||
| 9852 | if (!res) | ||
| 9853 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname, | ||
| 9854 | __sanitizer::struct_utsname_sz); | ||
| 9855 | return res; | ||
| 9856 | } | ||
| 9857 | #define INIT___XUNAME COMMON_INTERCEPT_FUNCTION(__xuname) | ||
| 9858 | #else | ||
| 9859 | #define INIT___XUNAME | ||
| 9860 | #endif | ||
| 9861 | |||
| 9862 | #include "sanitizer_common_interceptors_netbsd_compat.inc" | ||
| 9863 | |||
| 9864 | static void InitializeCommonInterceptors() { | ||
| 9865 | #if SI_POSIX | ||
| 9866 | static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1]; | ||
| 9867 | interceptor_metadata_map = new ((void *)&metadata_mem) MetadataHashMap(); | ||
| 9868 | #endif | ||
| 9869 | |||
| 9870 | INIT_MMAP; | ||
| 9871 | INIT_MMAP64; | ||
| 9872 | INIT_TEXTDOMAIN; | ||
| 9873 | INIT_STRLEN; | ||
| 9874 | INIT_STRNLEN; | ||
| 9875 | INIT_STRNDUP; | ||
| 9876 | INIT___STRNDUP; | ||
| 9877 | INIT_STRCMP; | ||
| 9878 | INIT_STRNCMP; | ||
| 9879 | INIT_STRCASECMP; | ||
| 9880 | INIT_STRNCASECMP; | ||
| 9881 | INIT_STRSTR; | ||
| 9882 | INIT_STRCASESTR; | ||
| 9883 | INIT_STRCHR; | ||
| 9884 | INIT_STRCHRNUL; | ||
| 9885 | INIT_STRRCHR; | ||
| 9886 | INIT_STRSPN; | ||
| 9887 | INIT_STRTOK; | ||
| 9888 | INIT_STRPBRK; | ||
| 9889 | INIT_STRXFRM; | ||
| 9890 | INIT___STRXFRM_L; | ||
| 9891 | INIT_MEMSET; | ||
| 9892 | INIT_MEMMOVE; | ||
| 9893 | INIT_MEMCPY; | ||
| 9894 | INIT_MEMCHR; | ||
| 9895 | INIT_MEMCMP; | ||
| 9896 | INIT_BCMP; | ||
| 9897 | INIT_MEMRCHR; | ||
| 9898 | INIT_MEMMEM; | ||
| 9899 | INIT_READ; | ||
| 9900 | INIT_FREAD; | ||
| 9901 | INIT_PREAD; | ||
| 9902 | INIT_PREAD64; | ||
| 9903 | INIT_READV; | ||
| 9904 | INIT_PREADV; | ||
| 9905 | INIT_PREADV64; | ||
| 9906 | INIT_WRITE; | ||
| 9907 | INIT_FWRITE; | ||
| 9908 | INIT_PWRITE; | ||
| 9909 | INIT_PWRITE64; | ||
| 9910 | INIT_WRITEV; | ||
| 9911 | INIT_PWRITEV; | ||
| 9912 | INIT_PWRITEV64; | ||
| 9913 | INIT_FGETS; | ||
| 9914 | INIT_FPUTS; | ||
| 9915 | INIT_PUTS; | ||
| 9916 | INIT_PRCTL; | ||
| 9917 | INIT_LOCALTIME_AND_FRIENDS; | ||
| 9918 | INIT_STRPTIME; | ||
| 9919 | INIT_SCANF; | ||
| 9920 | INIT_ISOC99_SCANF; | ||
| 9921 | INIT_PRINTF; | ||
| 9922 | INIT_PRINTF_L; | ||
| 9923 | INIT_ISOC99_PRINTF; | ||
| 9924 | INIT_FREXP; | ||
| 9925 | INIT_FREXPF_FREXPL; | ||
| 9926 | INIT_GETPWNAM_AND_FRIENDS; | ||
| 9927 | INIT_GETPWNAM_R_AND_FRIENDS; | ||
| 9928 | INIT_GETPWENT; | ||
| 9929 | INIT_FGETPWENT; | ||
| 9930 | INIT_GETPWENT_R; | ||
| 9931 | INIT_FGETPWENT_R; | ||
| 9932 | INIT_FGETGRENT_R; | ||
| 9933 | INIT_SETPWENT; | ||
| 9934 | INIT_CLOCK_GETTIME; | ||
| 9935 | INIT_CLOCK_GETCPUCLOCKID; | ||
| 9936 | INIT_GETITIMER; | ||
| 9937 | INIT_TIME; | ||
| 9938 | INIT_GLOB; | ||
| 9939 | INIT_GLOB64; | ||
| 9940 | INIT_WAIT; | ||
| 9941 | INIT_WAIT4; | ||
| 9942 | INIT_INET; | ||
| 9943 | INIT_PTHREAD_GETSCHEDPARAM; | ||
| 9944 | INIT_GETADDRINFO; | ||
| 9945 | INIT_GETNAMEINFO; | ||
| 9946 | INIT_GETSOCKNAME; | ||
| 9947 | INIT_GETHOSTBYNAME; | ||
| 9948 | INIT_GETHOSTBYNAME2; | ||
| 9949 | INIT_GETHOSTBYNAME_R; | ||
| 9950 | INIT_GETHOSTBYNAME2_R; | ||
| 9951 | INIT_GETHOSTBYADDR_R; | ||
| 9952 | INIT_GETHOSTENT_R; | ||
| 9953 | INIT_GETSOCKOPT; | ||
| 9954 | INIT_ACCEPT; | ||
| 9955 | INIT_ACCEPT4; | ||
| 9956 | INIT_PACCEPT; | ||
| 9957 | INIT_MODF; | ||
| 9958 | INIT_RECVMSG; | ||
| 9959 | INIT_SENDMSG; | ||
| 9960 | INIT_RECVMMSG; | ||
| 9961 | INIT_SENDMMSG; | ||
| 9962 | INIT_SYSMSG; | ||
| 9963 | INIT_GETPEERNAME; | ||
| 9964 | INIT_IOCTL; | ||
| 9965 | INIT_INET_ATON; | ||
| 9966 | INIT_SYSINFO; | ||
| 9967 | INIT_READDIR; | ||
| 9968 | INIT_READDIR64; | ||
| 9969 | INIT_PTRACE; | ||
| 9970 | INIT_SETLOCALE; | ||
| 9971 | INIT_GETCWD; | ||
| 9972 | INIT_GET_CURRENT_DIR_NAME; | ||
| 9973 | INIT_STRTOIMAX; | ||
| 9974 | INIT_MBSTOWCS; | ||
| 9975 | INIT_MBSNRTOWCS; | ||
| 9976 | INIT_WCSTOMBS; | ||
| 9977 | INIT_WCSNRTOMBS; | ||
| 9978 | INIT_WCRTOMB; | ||
| 9979 | INIT_WCTOMB; | ||
| 9980 | INIT_TCGETATTR; | ||
| 9981 | INIT_REALPATH; | ||
| 9982 | INIT_CANONICALIZE_FILE_NAME; | ||
| 9983 | INIT_CONFSTR; | ||
| 9984 | INIT_SCHED_GETAFFINITY; | ||
| 9985 | INIT_SCHED_GETPARAM; | ||
| 9986 | INIT_STRERROR; | ||
| 9987 | INIT_STRERROR_R; | ||
| 9988 | INIT_XPG_STRERROR_R; | ||
| 9989 | INIT_SCANDIR; | ||
| 9990 | INIT_SCANDIR64; | ||
| 9991 | INIT_GETGROUPS; | ||
| 9992 | INIT_POLL; | ||
| 9993 | INIT_PPOLL; | ||
| 9994 | INIT_WORDEXP; | ||
| 9995 | INIT_SIGWAIT; | ||
| 9996 | INIT_SIGWAITINFO; | ||
| 9997 | INIT_SIGTIMEDWAIT; | ||
| 9998 | INIT_SIGSETOPS; | ||
| 9999 | INIT_SIGPENDING; | ||
| 10000 | INIT_SIGPROCMASK; | ||
| 10001 | INIT_PTHREAD_SIGMASK; | ||
| 10002 | INIT_BACKTRACE; | ||
| 10003 | INIT__EXIT; | ||
| 10004 | INIT_PTHREAD_MUTEX_LOCK; | ||
| 10005 | INIT_PTHREAD_MUTEX_UNLOCK; | ||
| 10006 | INIT___PTHREAD_MUTEX_LOCK; | ||
| 10007 | INIT___PTHREAD_MUTEX_UNLOCK; | ||
| 10008 | INIT___LIBC_MUTEX_LOCK; | ||
| 10009 | INIT___LIBC_MUTEX_UNLOCK; | ||
| 10010 | INIT___LIBC_THR_SETCANCELSTATE; | ||
| 10011 | INIT_GETMNTENT; | ||
| 10012 | INIT_GETMNTENT_R; | ||
| 10013 | INIT_STATFS; | ||
| 10014 | INIT_STATFS64; | ||
| 10015 | INIT_STATVFS; | ||
| 10016 | INIT_STATVFS64; | ||
| 10017 | INIT_INITGROUPS; | ||
| 10018 | INIT_ETHER_NTOA_ATON; | ||
| 10019 | INIT_ETHER_HOST; | ||
| 10020 | INIT_ETHER_R; | ||
| 10021 | INIT_SHMCTL; | ||
| 10022 | INIT_RANDOM_R; | ||
| 10023 | INIT_PTHREAD_ATTR_GET; | ||
| 10024 | INIT_PTHREAD_ATTR_GET_SCHED; | ||
| 10025 | INIT_PTHREAD_ATTR_GETINHERITSCHED; | ||
| 10026 | INIT_PTHREAD_ATTR_GETAFFINITY_NP; | ||
| 10027 | INIT_PTHREAD_MUTEXATTR_GETPSHARED; | ||
| 10028 | INIT_PTHREAD_MUTEXATTR_GETTYPE; | ||
| 10029 | INIT_PTHREAD_MUTEXATTR_GETPROTOCOL; | ||
| 10030 | INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING; | ||
| 10031 | INIT_PTHREAD_MUTEXATTR_GETROBUST; | ||
| 10032 | INIT_PTHREAD_MUTEXATTR_GETROBUST_NP; | ||
| 10033 | INIT_PTHREAD_RWLOCKATTR_GETPSHARED; | ||
| 10034 | INIT_PTHREAD_RWLOCKATTR_GETKIND_NP; | ||
| 10035 | INIT_PTHREAD_CONDATTR_GETPSHARED; | ||
| 10036 | INIT_PTHREAD_CONDATTR_GETCLOCK; | ||
| 10037 | INIT_PTHREAD_BARRIERATTR_GETPSHARED; | ||
| 10038 | INIT_TMPNAM; | ||
| 10039 | INIT_TMPNAM_R; | ||
| 10040 | INIT_TTYNAME; | ||
| 10041 | INIT_TTYNAME_R; | ||
| 10042 | INIT_TEMPNAM; | ||
| 10043 | INIT_PTHREAD_SETNAME_NP; | ||
| 10044 | INIT_PTHREAD_GETNAME_NP; | ||
| 10045 | INIT_SINCOS; | ||
| 10046 | INIT_REMQUO; | ||
| 10047 | INIT_REMQUOL; | ||
| 10048 | INIT_LGAMMA; | ||
| 10049 | INIT_LGAMMAL; | ||
| 10050 | INIT_LGAMMA_R; | ||
| 10051 | INIT_LGAMMAL_R; | ||
| 10052 | INIT_DRAND48_R; | ||
| 10053 | INIT_RAND_R; | ||
| 10054 | INIT_GETLINE; | ||
| 10055 | INIT_ICONV; | ||
| 10056 | INIT_TIMES; | ||
| 10057 | INIT_TLS_GET_ADDR; | ||
| 10058 | INIT_LISTXATTR; | ||
| 10059 | INIT_GETXATTR; | ||
| 10060 | INIT_GETRESID; | ||
| 10061 | INIT_GETIFADDRS; | ||
| 10062 | INIT_IF_INDEXTONAME; | ||
| 10063 | INIT_CAPGET; | ||
| 10064 | INIT_AEABI_MEM; | ||
| 10065 | INIT___BZERO; | ||
| 10066 | INIT_BZERO; | ||
| 10067 | INIT_FTIME; | ||
| 10068 | INIT_XDR; | ||
| 10069 | INIT_TSEARCH; | ||
| 10070 | INIT_LIBIO_INTERNALS; | ||
| 10071 | INIT_FOPEN; | ||
| 10072 | INIT_FOPEN64; | ||
| 10073 | INIT_OPEN_MEMSTREAM; | ||
| 10074 | INIT_OBSTACK; | ||
| 10075 | INIT_FFLUSH; | ||
| 10076 | INIT_FCLOSE; | ||
| 10077 | INIT_DLOPEN_DLCLOSE; | ||
| 10078 | INIT_GETPASS; | ||
| 10079 | INIT_TIMERFD; | ||
| 10080 | INIT_MLOCKX; | ||
| 10081 | INIT_FOPENCOOKIE; | ||
| 10082 | INIT_SEM; | ||
| 10083 | INIT_PTHREAD_SETCANCEL; | ||
| 10084 | INIT_MINCORE; | ||
| 10085 | INIT_PROCESS_VM_READV; | ||
| 10086 | INIT_CTERMID; | ||
| 10087 | INIT_CTERMID_R; | ||
| 10088 | INIT_RECV_RECVFROM; | ||
| 10089 | INIT_SEND_SENDTO; | ||
| 10090 | INIT_STAT; | ||
| 10091 | INIT_EVENTFD_READ_WRITE; | ||
| 10092 | INIT_LSTAT; | ||
| 10093 | INIT___XSTAT; | ||
| 10094 | INIT___XSTAT64; | ||
| 10095 | INIT___LXSTAT; | ||
| 10096 | INIT___LXSTAT64; | ||
| 10097 | // FIXME: add other *stat interceptors. | ||
| 10098 | INIT_UTMP; | ||
| 10099 | INIT_UTMPX; | ||
| 10100 | INIT_GETLOADAVG; | ||
| 10101 | INIT_WCSLEN; | ||
| 10102 | INIT_WCSCAT; | ||
| 10103 | INIT_WCSDUP; | ||
| 10104 | INIT_WCSXFRM; | ||
| 10105 | INIT___WCSXFRM_L; | ||
| 10106 | INIT_ACCT; | ||
| 10107 | INIT_USER_FROM_UID; | ||
| 10108 | INIT_UID_FROM_USER; | ||
| 10109 | INIT_GROUP_FROM_GID; | ||
| 10110 | INIT_GID_FROM_GROUP; | ||
| 10111 | INIT_ACCESS; | ||
| 10112 | INIT_FACCESSAT; | ||
| 10113 | INIT_GETGROUPLIST; | ||
| 10114 | INIT_GETGROUPMEMBERSHIP; | ||
| 10115 | INIT_READLINK; | ||
| 10116 | INIT_READLINKAT; | ||
| 10117 | INIT_NAME_TO_HANDLE_AT; | ||
| 10118 | INIT_OPEN_BY_HANDLE_AT; | ||
| 10119 | INIT_STRLCPY; | ||
| 10120 | INIT_DEVNAME; | ||
| 10121 | INIT_DEVNAME_R; | ||
| 10122 | INIT_FGETLN; | ||
| 10123 | INIT_STRMODE; | ||
| 10124 | INIT_TTYENT; | ||
| 10125 | INIT_PROTOENT; | ||
| 10126 | INIT_PROTOENT_R; | ||
| 10127 | INIT_NETENT; | ||
| 10128 | INIT_GETMNTINFO; | ||
| 10129 | INIT_MI_VECTOR_HASH; | ||
| 10130 | INIT_SETVBUF; | ||
| 10131 | INIT_GETVFSSTAT; | ||
| 10132 | INIT_REGEX; | ||
| 10133 | INIT_REGEXSUB; | ||
| 10134 | INIT_FTS; | ||
| 10135 | INIT_SYSCTL; | ||
| 10136 | INIT_ASYSCTL; | ||
| 10137 | INIT_SYSCTLGETMIBINFO; | ||
| 10138 | INIT_NL_LANGINFO; | ||
| 10139 | INIT_MODCTL; | ||
| 10140 | INIT_STRTONUM; | ||
| 10141 | INIT_FPARSELN; | ||
| 10142 | INIT_STATVFS1; | ||
| 10143 | INIT_STRTOI; | ||
| 10144 | INIT_CAPSICUM; | ||
| 10145 | INIT_SHA1; | ||
| 10146 | INIT_MD4; | ||
| 10147 | INIT_RMD160; | ||
| 10148 | INIT_MD5; | ||
| 10149 | INIT_FSEEK; | ||
| 10150 | INIT_MD2; | ||
| 10151 | INIT_SHA2; | ||
| 10152 | INIT_VIS; | ||
| 10153 | INIT_CDB; | ||
| 10154 | INIT_GETFSENT; | ||
| 10155 | INIT_ARC4RANDOM; | ||
| 10156 | INIT_POPEN; | ||
| 10157 | INIT_POPENVE; | ||
| 10158 | INIT_PCLOSE; | ||
| 10159 | INIT_FUNOPEN; | ||
| 10160 | INIT_FUNOPEN2; | ||
| 10161 | INIT_FDEVNAME; | ||
| 10162 | INIT_GETUSERSHELL; | ||
| 10163 | INIT_SL_INIT; | ||
| 10164 | INIT_GETRANDOM; | ||
| 10165 | INIT_CRYPT; | ||
| 10166 | INIT_CRYPT_R; | ||
| 10167 | INIT_GETENTROPY; | ||
| 10168 | INIT_QSORT; | ||
| 10169 | INIT_QSORT_R; | ||
| 10170 | INIT_SIGALTSTACK; | ||
| 10171 | INIT_UNAME; | ||
| 10172 | INIT___XUNAME; | ||
| 10173 | |||
| 10174 | INIT___PRINTF_CHK; | ||
| 10175 | } | ||
lib/tsan/sanitizer_common/sanitizer_common_interceptors_format.inc created+562| ... | @@ -0,0 +1,562 @@ | ||
| 1 | //===-- sanitizer_common_interceptors_format.inc ----------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Scanf/printf implementation for use in *Sanitizer interceptors. | ||
| 10 | // Follows http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html | ||
| 11 | // and http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html | ||
| 12 | // with a few common GNU extensions. | ||
| 13 | // | ||
| 14 | //===----------------------------------------------------------------------===// | ||
| 15 | |||
| 16 | #include <stdarg.h> | ||
| 17 | |||
| 18 | static const char *parse_number(const char *p, int *out) { | ||
| 19 | *out = internal_atoll(p); | ||
| 20 | while (*p >= '0' && *p <= '9') | ||
| 21 | ++p; | ||
| 22 | return p; | ||
| 23 | } | ||
| 24 | |||
| 25 | static const char *maybe_parse_param_index(const char *p, int *out) { | ||
| 26 | // n$ | ||
| 27 | if (*p >= '0' && *p <= '9') { | ||
| 28 | int number; | ||
| 29 | const char *q = parse_number(p, &number); | ||
| 30 | CHECK(q); | ||
| 31 | if (*q == '$') { | ||
| 32 | *out = number; | ||
| 33 | p = q + 1; | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | // Otherwise, do not change p. This will be re-parsed later as the field | ||
| 38 | // width. | ||
| 39 | return p; | ||
| 40 | } | ||
| 41 | |||
| 42 | static bool char_is_one_of(char c, const char *s) { | ||
| 43 | return !!internal_strchr(s, c); | ||
| 44 | } | ||
| 45 | |||
| 46 | static const char *maybe_parse_length_modifier(const char *p, char ll[2]) { | ||
| 47 | if (char_is_one_of(*p, "jztLq")) { | ||
| 48 | ll[0] = *p; | ||
| 49 | ++p; | ||
| 50 | } else if (*p == 'h') { | ||
| 51 | ll[0] = 'h'; | ||
| 52 | ++p; | ||
| 53 | if (*p == 'h') { | ||
| 54 | ll[1] = 'h'; | ||
| 55 | ++p; | ||
| 56 | } | ||
| 57 | } else if (*p == 'l') { | ||
| 58 | ll[0] = 'l'; | ||
| 59 | ++p; | ||
| 60 | if (*p == 'l') { | ||
| 61 | ll[1] = 'l'; | ||
| 62 | ++p; | ||
| 63 | } | ||
| 64 | } | ||
| 65 | return p; | ||
| 66 | } | ||
| 67 | |||
| 68 | // Returns true if the character is an integer conversion specifier. | ||
| 69 | static bool format_is_integer_conv(char c) { | ||
| 70 | return char_is_one_of(c, "diouxXn"); | ||
| 71 | } | ||
| 72 | |||
| 73 | // Returns true if the character is an floating point conversion specifier. | ||
| 74 | static bool format_is_float_conv(char c) { | ||
| 75 | return char_is_one_of(c, "aAeEfFgG"); | ||
| 76 | } | ||
| 77 | |||
| 78 | // Returns string output character size for string-like conversions, | ||
| 79 | // or 0 if the conversion is invalid. | ||
| 80 | static int format_get_char_size(char convSpecifier, | ||
| 81 | const char lengthModifier[2]) { | ||
| 82 | if (char_is_one_of(convSpecifier, "CS")) { | ||
| 83 | return sizeof(wchar_t); | ||
| 84 | } | ||
| 85 | |||
| 86 | if (char_is_one_of(convSpecifier, "cs[")) { | ||
| 87 | if (lengthModifier[0] == 'l' && lengthModifier[1] == '\0') | ||
| 88 | return sizeof(wchar_t); | ||
| 89 | else if (lengthModifier[0] == '\0') | ||
| 90 | return sizeof(char); | ||
| 91 | } | ||
| 92 | |||
| 93 | return 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | enum FormatStoreSize { | ||
| 97 | // Store size not known in advance; can be calculated as wcslen() of the | ||
| 98 | // destination buffer. | ||
| 99 | FSS_WCSLEN = -2, | ||
| 100 | // Store size not known in advance; can be calculated as strlen() of the | ||
| 101 | // destination buffer. | ||
| 102 | FSS_STRLEN = -1, | ||
| 103 | // Invalid conversion specifier. | ||
| 104 | FSS_INVALID = 0 | ||
| 105 | }; | ||
| 106 | |||
| 107 | // Returns the memory size of a format directive (if >0), or a value of | ||
| 108 | // FormatStoreSize. | ||
| 109 | static int format_get_value_size(char convSpecifier, | ||
| 110 | const char lengthModifier[2], | ||
| 111 | bool promote_float) { | ||
| 112 | if (format_is_integer_conv(convSpecifier)) { | ||
| 113 | switch (lengthModifier[0]) { | ||
| 114 | case 'h': | ||
| 115 | return lengthModifier[1] == 'h' ? sizeof(char) : sizeof(short); | ||
| 116 | case 'l': | ||
| 117 | return lengthModifier[1] == 'l' ? sizeof(long long) : sizeof(long); | ||
| 118 | case 'q': | ||
| 119 | return sizeof(long long); | ||
| 120 | case 'L': | ||
| 121 | return sizeof(long long); | ||
| 122 | case 'j': | ||
| 123 | return sizeof(INTMAX_T); | ||
| 124 | case 'z': | ||
| 125 | return sizeof(SIZE_T); | ||
| 126 | case 't': | ||
| 127 | return sizeof(PTRDIFF_T); | ||
| 128 | case 0: | ||
| 129 | return sizeof(int); | ||
| 130 | default: | ||
| 131 | return FSS_INVALID; | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | if (format_is_float_conv(convSpecifier)) { | ||
| 136 | switch (lengthModifier[0]) { | ||
| 137 | case 'L': | ||
| 138 | case 'q': | ||
| 139 | return sizeof(long double); | ||
| 140 | case 'l': | ||
| 141 | return lengthModifier[1] == 'l' ? sizeof(long double) | ||
| 142 | : sizeof(double); | ||
| 143 | case 0: | ||
| 144 | // Printf promotes floats to doubles but scanf does not | ||
| 145 | return promote_float ? sizeof(double) : sizeof(float); | ||
| 146 | default: | ||
| 147 | return FSS_INVALID; | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | if (convSpecifier == 'p') { | ||
| 152 | if (lengthModifier[0] != 0) | ||
| 153 | return FSS_INVALID; | ||
| 154 | return sizeof(void *); | ||
| 155 | } | ||
| 156 | |||
| 157 | return FSS_INVALID; | ||
| 158 | } | ||
| 159 | |||
| 160 | struct ScanfDirective { | ||
| 161 | int argIdx; // argument index, or -1 if not specified ("%n$") | ||
| 162 | int fieldWidth; | ||
| 163 | const char *begin; | ||
| 164 | const char *end; | ||
| 165 | bool suppressed; // suppress assignment ("*") | ||
| 166 | bool allocate; // allocate space ("m") | ||
| 167 | char lengthModifier[2]; | ||
| 168 | char convSpecifier; | ||
| 169 | bool maybeGnuMalloc; | ||
| 170 | }; | ||
| 171 | |||
| 172 | // Parse scanf format string. If a valid directive in encountered, it is | ||
| 173 | // returned in dir. This function returns the pointer to the first | ||
| 174 | // unprocessed character, or 0 in case of error. | ||
| 175 | // In case of the end-of-string, a pointer to the closing \0 is returned. | ||
| 176 | static const char *scanf_parse_next(const char *p, bool allowGnuMalloc, | ||
| 177 | ScanfDirective *dir) { | ||
| 178 | internal_memset(dir, 0, sizeof(*dir)); | ||
| 179 | dir->argIdx = -1; | ||
| 180 | |||
| 181 | while (*p) { | ||
| 182 | if (*p != '%') { | ||
| 183 | ++p; | ||
| 184 | continue; | ||
| 185 | } | ||
| 186 | dir->begin = p; | ||
| 187 | ++p; | ||
| 188 | // %% | ||
| 189 | if (*p == '%') { | ||
| 190 | ++p; | ||
| 191 | continue; | ||
| 192 | } | ||
| 193 | if (*p == '\0') { | ||
| 194 | return nullptr; | ||
| 195 | } | ||
| 196 | // %n$ | ||
| 197 | p = maybe_parse_param_index(p, &dir->argIdx); | ||
| 198 | CHECK(p); | ||
| 199 | // * | ||
| 200 | if (*p == '*') { | ||
| 201 | dir->suppressed = true; | ||
| 202 | ++p; | ||
| 203 | } | ||
| 204 | // Field width | ||
| 205 | if (*p >= '0' && *p <= '9') { | ||
| 206 | p = parse_number(p, &dir->fieldWidth); | ||
| 207 | CHECK(p); | ||
| 208 | if (dir->fieldWidth <= 0) // Width if at all must be non-zero | ||
| 209 | return nullptr; | ||
| 210 | } | ||
| 211 | // m | ||
| 212 | if (*p == 'm') { | ||
| 213 | dir->allocate = true; | ||
| 214 | ++p; | ||
| 215 | } | ||
| 216 | // Length modifier. | ||
| 217 | p = maybe_parse_length_modifier(p, dir->lengthModifier); | ||
| 218 | // Conversion specifier. | ||
| 219 | dir->convSpecifier = *p++; | ||
| 220 | // Consume %[...] expression. | ||
| 221 | if (dir->convSpecifier == '[') { | ||
| 222 | if (*p == '^') | ||
| 223 | ++p; | ||
| 224 | if (*p == ']') | ||
| 225 | ++p; | ||
| 226 | while (*p && *p != ']') | ||
| 227 | ++p; | ||
| 228 | if (*p == 0) | ||
| 229 | return nullptr; // unexpected end of string | ||
| 230 | // Consume the closing ']'. | ||
| 231 | ++p; | ||
| 232 | } | ||
| 233 | // This is unfortunately ambiguous between old GNU extension | ||
| 234 | // of %as, %aS and %a[...] and newer POSIX %a followed by | ||
| 235 | // letters s, S or [. | ||
| 236 | if (allowGnuMalloc && dir->convSpecifier == 'a' && | ||
| 237 | !dir->lengthModifier[0]) { | ||
| 238 | if (*p == 's' || *p == 'S') { | ||
| 239 | dir->maybeGnuMalloc = true; | ||
| 240 | ++p; | ||
| 241 | } else if (*p == '[') { | ||
| 242 | // Watch for %a[h-j%d], if % appears in the | ||
| 243 | // [...] range, then we need to give up, we don't know | ||
| 244 | // if scanf will parse it as POSIX %a [h-j %d ] or | ||
| 245 | // GNU allocation of string with range dh-j plus %. | ||
| 246 | const char *q = p + 1; | ||
| 247 | if (*q == '^') | ||
| 248 | ++q; | ||
| 249 | if (*q == ']') | ||
| 250 | ++q; | ||
| 251 | while (*q && *q != ']' && *q != '%') | ||
| 252 | ++q; | ||
| 253 | if (*q == 0 || *q == '%') | ||
| 254 | return nullptr; | ||
| 255 | p = q + 1; // Consume the closing ']'. | ||
| 256 | dir->maybeGnuMalloc = true; | ||
| 257 | } | ||
| 258 | } | ||
| 259 | dir->end = p; | ||
| 260 | break; | ||
| 261 | } | ||
| 262 | return p; | ||
| 263 | } | ||
| 264 | |||
| 265 | static int scanf_get_value_size(ScanfDirective *dir) { | ||
| 266 | if (dir->allocate) { | ||
| 267 | if (!char_is_one_of(dir->convSpecifier, "cCsS[")) | ||
| 268 | return FSS_INVALID; | ||
| 269 | return sizeof(char *); | ||
| 270 | } | ||
| 271 | |||
| 272 | if (dir->maybeGnuMalloc) { | ||
| 273 | if (dir->convSpecifier != 'a' || dir->lengthModifier[0]) | ||
| 274 | return FSS_INVALID; | ||
| 275 | // This is ambiguous, so check the smaller size of char * (if it is | ||
| 276 | // a GNU extension of %as, %aS or %a[...]) and float (if it is | ||
| 277 | // POSIX %a followed by s, S or [ letters). | ||
| 278 | return sizeof(char *) < sizeof(float) ? sizeof(char *) : sizeof(float); | ||
| 279 | } | ||
| 280 | |||
| 281 | if (char_is_one_of(dir->convSpecifier, "cCsS[")) { | ||
| 282 | bool needsTerminator = char_is_one_of(dir->convSpecifier, "sS["); | ||
| 283 | unsigned charSize = | ||
| 284 | format_get_char_size(dir->convSpecifier, dir->lengthModifier); | ||
| 285 | if (charSize == 0) | ||
| 286 | return FSS_INVALID; | ||
| 287 | if (dir->fieldWidth == 0) { | ||
| 288 | if (!needsTerminator) | ||
| 289 | return charSize; | ||
| 290 | return (charSize == sizeof(char)) ? FSS_STRLEN : FSS_WCSLEN; | ||
| 291 | } | ||
| 292 | return (dir->fieldWidth + needsTerminator) * charSize; | ||
| 293 | } | ||
| 294 | |||
| 295 | return format_get_value_size(dir->convSpecifier, dir->lengthModifier, false); | ||
| 296 | } | ||
| 297 | |||
| 298 | // Common part of *scanf interceptors. | ||
| 299 | // Process format string and va_list, and report all store ranges. | ||
| 300 | // Stops when "consuming" n_inputs input items. | ||
| 301 | static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc, | ||
| 302 | const char *format, va_list aq) { | ||
| 303 | CHECK_GT(n_inputs, 0); | ||
| 304 | const char *p = format; | ||
| 305 | |||
| 306 | COMMON_INTERCEPTOR_READ_RANGE(ctx, format, internal_strlen(format) + 1); | ||
| 307 | |||
| 308 | while (*p) { | ||
| 309 | ScanfDirective dir; | ||
| 310 | p = scanf_parse_next(p, allowGnuMalloc, &dir); | ||
| 311 | if (!p) | ||
| 312 | break; | ||
| 313 | if (dir.convSpecifier == 0) { | ||
| 314 | // This can only happen at the end of the format string. | ||
| 315 | CHECK_EQ(*p, 0); | ||
| 316 | break; | ||
| 317 | } | ||
| 318 | // Here the directive is valid. Do what it says. | ||
| 319 | if (dir.argIdx != -1) { | ||
| 320 | // Unsupported. | ||
| 321 | break; | ||
| 322 | } | ||
| 323 | if (dir.suppressed) | ||
| 324 | continue; | ||
| 325 | int size = scanf_get_value_size(&dir); | ||
| 326 | if (size == FSS_INVALID) { | ||
| 327 | Report("%s: WARNING: unexpected format specifier in scanf interceptor: ", | ||
| 328 | SanitizerToolName, "%.*s\n", dir.end - dir.begin, dir.begin); | ||
| 329 | break; | ||
| 330 | } | ||
| 331 | void *argp = va_arg(aq, void *); | ||
| 332 | if (dir.convSpecifier != 'n') | ||
| 333 | --n_inputs; | ||
| 334 | if (n_inputs < 0) | ||
| 335 | break; | ||
| 336 | if (size == FSS_STRLEN) { | ||
| 337 | size = internal_strlen((const char *)argp) + 1; | ||
| 338 | } else if (size == FSS_WCSLEN) { | ||
| 339 | // FIXME: actually use wcslen() to calculate it. | ||
| 340 | size = 0; | ||
| 341 | } | ||
| 342 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size); | ||
| 343 | } | ||
| 344 | } | ||
| 345 | |||
| 346 | #if SANITIZER_INTERCEPT_PRINTF | ||
| 347 | |||
| 348 | struct PrintfDirective { | ||
| 349 | int fieldWidth; | ||
| 350 | int fieldPrecision; | ||
| 351 | int argIdx; // width argument index, or -1 if not specified ("%*n$") | ||
| 352 | int precisionIdx; // precision argument index, or -1 if not specified (".*n$") | ||
| 353 | const char *begin; | ||
| 354 | const char *end; | ||
| 355 | bool starredWidth; | ||
| 356 | bool starredPrecision; | ||
| 357 | char lengthModifier[2]; | ||
| 358 | char convSpecifier; | ||
| 359 | }; | ||
| 360 | |||
| 361 | static const char *maybe_parse_number(const char *p, int *out) { | ||
| 362 | if (*p >= '0' && *p <= '9') | ||
| 363 | p = parse_number(p, out); | ||
| 364 | return p; | ||
| 365 | } | ||
| 366 | |||
| 367 | static const char *maybe_parse_number_or_star(const char *p, int *out, | ||
| 368 | bool *star) { | ||
| 369 | if (*p == '*') { | ||
| 370 | *star = true; | ||
| 371 | ++p; | ||
| 372 | } else { | ||
| 373 | *star = false; | ||
| 374 | p = maybe_parse_number(p, out); | ||
| 375 | } | ||
| 376 | return p; | ||
| 377 | } | ||
| 378 | |||
| 379 | // Parse printf format string. Same as scanf_parse_next. | ||
| 380 | static const char *printf_parse_next(const char *p, PrintfDirective *dir) { | ||
| 381 | internal_memset(dir, 0, sizeof(*dir)); | ||
| 382 | dir->argIdx = -1; | ||
| 383 | dir->precisionIdx = -1; | ||
| 384 | |||
| 385 | while (*p) { | ||
| 386 | if (*p != '%') { | ||
| 387 | ++p; | ||
| 388 | continue; | ||
| 389 | } | ||
| 390 | dir->begin = p; | ||
| 391 | ++p; | ||
| 392 | // %% | ||
| 393 | if (*p == '%') { | ||
| 394 | ++p; | ||
| 395 | continue; | ||
| 396 | } | ||
| 397 | if (*p == '\0') { | ||
| 398 | return nullptr; | ||
| 399 | } | ||
| 400 | // %n$ | ||
| 401 | p = maybe_parse_param_index(p, &dir->precisionIdx); | ||
| 402 | CHECK(p); | ||
| 403 | // Flags | ||
| 404 | while (char_is_one_of(*p, "'-+ #0")) { | ||
| 405 | ++p; | ||
| 406 | } | ||
| 407 | // Field width | ||
| 408 | p = maybe_parse_number_or_star(p, &dir->fieldWidth, | ||
| 409 | &dir->starredWidth); | ||
| 410 | if (!p) | ||
| 411 | return nullptr; | ||
| 412 | // Precision | ||
| 413 | if (*p == '.') { | ||
| 414 | ++p; | ||
| 415 | // Actual precision is optional (surprise!) | ||
| 416 | p = maybe_parse_number_or_star(p, &dir->fieldPrecision, | ||
| 417 | &dir->starredPrecision); | ||
| 418 | if (!p) | ||
| 419 | return nullptr; | ||
| 420 | // m$ | ||
| 421 | if (dir->starredPrecision) { | ||
| 422 | p = maybe_parse_param_index(p, &dir->precisionIdx); | ||
| 423 | CHECK(p); | ||
| 424 | } | ||
| 425 | } | ||
| 426 | // Length modifier. | ||
| 427 | p = maybe_parse_length_modifier(p, dir->lengthModifier); | ||
| 428 | // Conversion specifier. | ||
| 429 | dir->convSpecifier = *p++; | ||
| 430 | dir->end = p; | ||
| 431 | break; | ||
| 432 | } | ||
| 433 | return p; | ||
| 434 | } | ||
| 435 | |||
| 436 | static int printf_get_value_size(PrintfDirective *dir) { | ||
| 437 | if (char_is_one_of(dir->convSpecifier, "cCsS")) { | ||
| 438 | unsigned charSize = | ||
| 439 | format_get_char_size(dir->convSpecifier, dir->lengthModifier); | ||
| 440 | if (charSize == 0) | ||
| 441 | return FSS_INVALID; | ||
| 442 | if (char_is_one_of(dir->convSpecifier, "sS")) { | ||
| 443 | return (charSize == sizeof(char)) ? FSS_STRLEN : FSS_WCSLEN; | ||
| 444 | } | ||
| 445 | return charSize; | ||
| 446 | } | ||
| 447 | |||
| 448 | return format_get_value_size(dir->convSpecifier, dir->lengthModifier, true); | ||
| 449 | } | ||
| 450 | |||
| 451 | #define SKIP_SCALAR_ARG(aq, convSpecifier, size) \ | ||
| 452 | do { \ | ||
| 453 | if (format_is_float_conv(convSpecifier)) { \ | ||
| 454 | switch (size) { \ | ||
| 455 | case 8: \ | ||
| 456 | va_arg(*aq, double); \ | ||
| 457 | break; \ | ||
| 458 | case 12: \ | ||
| 459 | va_arg(*aq, long double); \ | ||
| 460 | break; \ | ||
| 461 | case 16: \ | ||
| 462 | va_arg(*aq, long double); \ | ||
| 463 | break; \ | ||
| 464 | default: \ | ||
| 465 | Report("WARNING: unexpected floating-point arg size" \ | ||
| 466 | " in printf interceptor: %d\n", size); \ | ||
| 467 | return; \ | ||
| 468 | } \ | ||
| 469 | } else { \ | ||
| 470 | switch (size) { \ | ||
| 471 | case 1: \ | ||
| 472 | case 2: \ | ||
| 473 | case 4: \ | ||
| 474 | va_arg(*aq, u32); \ | ||
| 475 | break; \ | ||
| 476 | case 8: \ | ||
| 477 | va_arg(*aq, u64); \ | ||
| 478 | break; \ | ||
| 479 | default: \ | ||
| 480 | Report("WARNING: unexpected arg size" \ | ||
| 481 | " in printf interceptor: %d\n", size); \ | ||
| 482 | return; \ | ||
| 483 | } \ | ||
| 484 | } \ | ||
| 485 | } while (0) | ||
| 486 | |||
| 487 | // Common part of *printf interceptors. | ||
| 488 | // Process format string and va_list, and report all load ranges. | ||
| 489 | static void printf_common(void *ctx, const char *format, va_list aq) { | ||
| 490 | COMMON_INTERCEPTOR_READ_RANGE(ctx, format, internal_strlen(format) + 1); | ||
| 491 | |||
| 492 | const char *p = format; | ||
| 493 | |||
| 494 | while (*p) { | ||
| 495 | PrintfDirective dir; | ||
| 496 | p = printf_parse_next(p, &dir); | ||
| 497 | if (!p) | ||
| 498 | break; | ||
| 499 | if (dir.convSpecifier == 0) { | ||
| 500 | // This can only happen at the end of the format string. | ||
| 501 | CHECK_EQ(*p, 0); | ||
| 502 | break; | ||
| 503 | } | ||
| 504 | // Here the directive is valid. Do what it says. | ||
| 505 | if (dir.argIdx != -1 || dir.precisionIdx != -1) { | ||
| 506 | // Unsupported. | ||
| 507 | break; | ||
| 508 | } | ||
| 509 | if (dir.starredWidth) { | ||
| 510 | // Dynamic width | ||
| 511 | SKIP_SCALAR_ARG(&aq, 'd', sizeof(int)); | ||
| 512 | } | ||
| 513 | if (dir.starredPrecision) { | ||
| 514 | // Dynamic precision | ||
| 515 | SKIP_SCALAR_ARG(&aq, 'd', sizeof(int)); | ||
| 516 | } | ||
| 517 | // %m does not require an argument: strlen(errno). | ||
| 518 | if (dir.convSpecifier == 'm') | ||
| 519 | continue; | ||
| 520 | int size = printf_get_value_size(&dir); | ||
| 521 | if (size == FSS_INVALID) { | ||
| 522 | static int ReportedOnce; | ||
| 523 | if (!ReportedOnce++) | ||
| 524 | Report( | ||
| 525 | "%s: WARNING: unexpected format specifier in printf " | ||
| 526 | "interceptor: %.*s (reported once per process)\n", | ||
| 527 | SanitizerToolName, dir.end - dir.begin, dir.begin); | ||
| 528 | break; | ||
| 529 | } | ||
| 530 | if (dir.convSpecifier == 'n') { | ||
| 531 | void *argp = va_arg(aq, void *); | ||
| 532 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size); | ||
| 533 | continue; | ||
| 534 | } else if (size == FSS_STRLEN) { | ||
| 535 | if (void *argp = va_arg(aq, void *)) { | ||
| 536 | if (dir.starredPrecision) { | ||
| 537 | // FIXME: properly support starred precision for strings. | ||
| 538 | size = 0; | ||
| 539 | } else if (dir.fieldPrecision > 0) { | ||
| 540 | // Won't read more than "precision" symbols. | ||
| 541 | size = internal_strnlen((const char *)argp, dir.fieldPrecision); | ||
| 542 | if (size < dir.fieldPrecision) size++; | ||
| 543 | } else { | ||
| 544 | // Whole string will be accessed. | ||
| 545 | size = internal_strlen((const char *)argp) + 1; | ||
| 546 | } | ||
| 547 | COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, size); | ||
| 548 | } | ||
| 549 | } else if (size == FSS_WCSLEN) { | ||
| 550 | if (void *argp = va_arg(aq, void *)) { | ||
| 551 | // FIXME: Properly support wide-character strings (via wcsrtombs). | ||
| 552 | size = 0; | ||
| 553 | COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, size); | ||
| 554 | } | ||
| 555 | } else { | ||
| 556 | // Skip non-pointer args | ||
| 557 | SKIP_SCALAR_ARG(&aq, dir.convSpecifier, size); | ||
| 558 | } | ||
| 559 | } | ||
| 560 | } | ||
| 561 | |||
| 562 | #endif // SANITIZER_INTERCEPT_PRINTF | ||
lib/tsan/sanitizer_common/sanitizer_common_interceptors_ioctl.inc created+609| ... | @@ -0,0 +1,609 @@ | ||
| 1 | //===-- sanitizer_common_interceptors_ioctl.inc -----------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Ioctl handling in common sanitizer interceptors. | ||
| 10 | //===----------------------------------------------------------------------===// | ||
| 11 | |||
| 12 | #if !SANITIZER_NETBSD | ||
| 13 | |||
| 14 | #include "sanitizer_flags.h" | ||
| 15 | |||
| 16 | struct ioctl_desc { | ||
| 17 | unsigned req; | ||
| 18 | // FIXME: support read+write arguments. Currently READWRITE and WRITE do the | ||
| 19 | // same thing. | ||
| 20 | // XXX: The declarations below may use WRITE instead of READWRITE, unless | ||
| 21 | // explicitly noted. | ||
| 22 | enum { | ||
| 23 | NONE, | ||
| 24 | READ, | ||
| 25 | WRITE, | ||
| 26 | READWRITE, | ||
| 27 | CUSTOM | ||
| 28 | } type : 3; | ||
| 29 | unsigned size : 29; | ||
| 30 | const char* name; | ||
| 31 | }; | ||
| 32 | |||
| 33 | const unsigned ioctl_table_max = 500; | ||
| 34 | static ioctl_desc ioctl_table[ioctl_table_max]; | ||
| 35 | static unsigned ioctl_table_size = 0; | ||
| 36 | |||
| 37 | // This can not be declared as a global, because references to struct_*_sz | ||
| 38 | // require a global initializer. And this table must be available before global | ||
| 39 | // initializers are run. | ||
| 40 | static void ioctl_table_fill() { | ||
| 41 | #define _(rq, tp, sz) \ | ||
| 42 | if (IOCTL_##rq != IOCTL_NOT_PRESENT) { \ | ||
| 43 | CHECK(ioctl_table_size < ioctl_table_max); \ | ||
| 44 | ioctl_table[ioctl_table_size].req = IOCTL_##rq; \ | ||
| 45 | ioctl_table[ioctl_table_size].type = ioctl_desc::tp; \ | ||
| 46 | ioctl_table[ioctl_table_size].size = sz; \ | ||
| 47 | ioctl_table[ioctl_table_size].name = #rq; \ | ||
| 48 | ++ioctl_table_size; \ | ||
| 49 | } | ||
| 50 | |||
| 51 | _(FIOASYNC, READ, sizeof(int)); | ||
| 52 | _(FIOCLEX, NONE, 0); | ||
| 53 | _(FIOGETOWN, WRITE, sizeof(int)); | ||
| 54 | _(FIONBIO, READ, sizeof(int)); | ||
| 55 | _(FIONCLEX, NONE, 0); | ||
| 56 | _(FIOSETOWN, READ, sizeof(int)); | ||
| 57 | _(SIOCATMARK, WRITE, sizeof(int)); | ||
| 58 | _(SIOCGIFCONF, CUSTOM, 0); | ||
| 59 | _(SIOCGPGRP, WRITE, sizeof(int)); | ||
| 60 | _(SIOCSPGRP, READ, sizeof(int)); | ||
| 61 | #if !SANITIZER_SOLARIS | ||
| 62 | _(TIOCCONS, NONE, 0); | ||
| 63 | #endif | ||
| 64 | _(TIOCEXCL, NONE, 0); | ||
| 65 | _(TIOCGETD, WRITE, sizeof(int)); | ||
| 66 | _(TIOCGPGRP, WRITE, pid_t_sz); | ||
| 67 | _(TIOCGWINSZ, WRITE, struct_winsize_sz); | ||
| 68 | _(TIOCMBIC, READ, sizeof(int)); | ||
| 69 | _(TIOCMBIS, READ, sizeof(int)); | ||
| 70 | _(TIOCMGET, WRITE, sizeof(int)); | ||
| 71 | _(TIOCMSET, READ, sizeof(int)); | ||
| 72 | _(TIOCNOTTY, NONE, 0); | ||
| 73 | _(TIOCNXCL, NONE, 0); | ||
| 74 | _(TIOCOUTQ, WRITE, sizeof(int)); | ||
| 75 | _(TIOCPKT, READ, sizeof(int)); | ||
| 76 | _(TIOCSCTTY, NONE, 0); | ||
| 77 | _(TIOCSETD, READ, sizeof(int)); | ||
| 78 | _(TIOCSPGRP, READ, pid_t_sz); | ||
| 79 | _(TIOCSTI, READ, sizeof(char)); | ||
| 80 | _(TIOCSWINSZ, READ, struct_winsize_sz); | ||
| 81 | |||
| 82 | #if !SANITIZER_IOS | ||
| 83 | _(SIOCADDMULTI, READ, struct_ifreq_sz); | ||
| 84 | _(SIOCDELMULTI, READ, struct_ifreq_sz); | ||
| 85 | _(SIOCGIFADDR, WRITE, struct_ifreq_sz); | ||
| 86 | _(SIOCGIFBRDADDR, WRITE, struct_ifreq_sz); | ||
| 87 | _(SIOCGIFDSTADDR, WRITE, struct_ifreq_sz); | ||
| 88 | _(SIOCGIFFLAGS, WRITE, struct_ifreq_sz); | ||
| 89 | _(SIOCGIFMETRIC, WRITE, struct_ifreq_sz); | ||
| 90 | _(SIOCGIFMTU, WRITE, struct_ifreq_sz); | ||
| 91 | _(SIOCGIFNETMASK, WRITE, struct_ifreq_sz); | ||
| 92 | _(SIOCSIFADDR, READ, struct_ifreq_sz); | ||
| 93 | _(SIOCSIFBRDADDR, READ, struct_ifreq_sz); | ||
| 94 | _(SIOCSIFDSTADDR, READ, struct_ifreq_sz); | ||
| 95 | _(SIOCSIFFLAGS, READ, struct_ifreq_sz); | ||
| 96 | _(SIOCSIFMETRIC, READ, struct_ifreq_sz); | ||
| 97 | _(SIOCSIFMTU, READ, struct_ifreq_sz); | ||
| 98 | _(SIOCSIFNETMASK, READ, struct_ifreq_sz); | ||
| 99 | #endif | ||
| 100 | |||
| 101 | #if (SANITIZER_LINUX && !SANITIZER_ANDROID) | ||
| 102 | _(SIOCGETSGCNT, WRITE, struct_sioc_sg_req_sz); | ||
| 103 | _(SIOCGETVIFCNT, WRITE, struct_sioc_vif_req_sz); | ||
| 104 | #endif | ||
| 105 | |||
| 106 | #if SANITIZER_LINUX | ||
| 107 | // Conflicting request ids. | ||
| 108 | // _(CDROMAUDIOBUFSIZ, NONE, 0); | ||
| 109 | // _(SNDCTL_TMR_CONTINUE, NONE, 0); | ||
| 110 | // _(SNDCTL_TMR_START, NONE, 0); | ||
| 111 | // _(SNDCTL_TMR_STOP, NONE, 0); | ||
| 112 | // _(SOUND_MIXER_READ_LOUD, WRITE, sizeof(int)); // same as ...READ_ENHANCE | ||
| 113 | // _(SOUND_MIXER_READ_MUTE, WRITE, sizeof(int)); // same as ...READ_ENHANCE | ||
| 114 | // _(SOUND_MIXER_WRITE_LOUD, WRITE, sizeof(int)); // same as ...WRITE_ENHANCE | ||
| 115 | // _(SOUND_MIXER_WRITE_MUTE, WRITE, sizeof(int)); // same as ...WRITE_ENHANCE | ||
| 116 | _(BLKFLSBUF, NONE, 0); | ||
| 117 | _(BLKGETSIZE, WRITE, sizeof(uptr)); | ||
| 118 | _(BLKRAGET, WRITE, sizeof(int)); | ||
| 119 | _(BLKRASET, NONE, 0); | ||
| 120 | _(BLKROGET, WRITE, sizeof(int)); | ||
| 121 | _(BLKROSET, READ, sizeof(int)); | ||
| 122 | _(BLKRRPART, NONE, 0); | ||
| 123 | _(CDROMEJECT, NONE, 0); | ||
| 124 | _(CDROMEJECT_SW, NONE, 0); | ||
| 125 | _(CDROMMULTISESSION, WRITE, struct_cdrom_multisession_sz); | ||
| 126 | _(CDROMPAUSE, NONE, 0); | ||
| 127 | _(CDROMPLAYMSF, READ, struct_cdrom_msf_sz); | ||
| 128 | _(CDROMPLAYTRKIND, READ, struct_cdrom_ti_sz); | ||
| 129 | _(CDROMREADAUDIO, READ, struct_cdrom_read_audio_sz); | ||
| 130 | _(CDROMREADCOOKED, READ, struct_cdrom_msf_sz); | ||
| 131 | _(CDROMREADMODE1, READ, struct_cdrom_msf_sz); | ||
| 132 | _(CDROMREADMODE2, READ, struct_cdrom_msf_sz); | ||
| 133 | _(CDROMREADRAW, READ, struct_cdrom_msf_sz); | ||
| 134 | _(CDROMREADTOCENTRY, WRITE, struct_cdrom_tocentry_sz); | ||
| 135 | _(CDROMREADTOCHDR, WRITE, struct_cdrom_tochdr_sz); | ||
| 136 | _(CDROMRESET, NONE, 0); | ||
| 137 | _(CDROMRESUME, NONE, 0); | ||
| 138 | _(CDROMSEEK, READ, struct_cdrom_msf_sz); | ||
| 139 | _(CDROMSTART, NONE, 0); | ||
| 140 | _(CDROMSTOP, NONE, 0); | ||
| 141 | _(CDROMSUBCHNL, WRITE, struct_cdrom_subchnl_sz); | ||
| 142 | _(CDROMVOLCTRL, READ, struct_cdrom_volctrl_sz); | ||
| 143 | _(CDROMVOLREAD, WRITE, struct_cdrom_volctrl_sz); | ||
| 144 | _(CDROM_GET_UPC, WRITE, 8); | ||
| 145 | _(EVIOCGABS, WRITE, struct_input_absinfo_sz); // fixup | ||
| 146 | _(EVIOCGBIT, WRITE, struct_input_id_sz); // fixup | ||
| 147 | _(EVIOCGEFFECTS, WRITE, sizeof(int)); | ||
| 148 | _(EVIOCGID, WRITE, struct_input_id_sz); | ||
| 149 | _(EVIOCGKEY, WRITE, 0); | ||
| 150 | _(EVIOCGKEYCODE, WRITE, sizeof(int) * 2); | ||
| 151 | _(EVIOCGLED, WRITE, 0); | ||
| 152 | _(EVIOCGNAME, WRITE, 0); | ||
| 153 | _(EVIOCGPHYS, WRITE, 0); | ||
| 154 | _(EVIOCGRAB, READ, sizeof(int)); | ||
| 155 | _(EVIOCGREP, WRITE, sizeof(int) * 2); | ||
| 156 | _(EVIOCGSND, WRITE, 0); | ||
| 157 | _(EVIOCGSW, WRITE, 0); | ||
| 158 | _(EVIOCGUNIQ, WRITE, 0); | ||
| 159 | _(EVIOCGVERSION, WRITE, sizeof(int)); | ||
| 160 | _(EVIOCRMFF, READ, sizeof(int)); | ||
| 161 | _(EVIOCSABS, READ, struct_input_absinfo_sz); // fixup | ||
| 162 | _(EVIOCSFF, READ, struct_ff_effect_sz); | ||
| 163 | _(EVIOCSKEYCODE, READ, sizeof(int) * 2); | ||
| 164 | _(EVIOCSREP, READ, sizeof(int) * 2); | ||
| 165 | _(FDCLRPRM, NONE, 0); | ||
| 166 | _(FDDEFPRM, READ, struct_floppy_struct_sz); | ||
| 167 | _(FDFLUSH, NONE, 0); | ||
| 168 | _(FDFMTBEG, NONE, 0); | ||
| 169 | _(FDFMTEND, NONE, 0); | ||
| 170 | _(FDFMTTRK, READ, struct_format_descr_sz); | ||
| 171 | _(FDGETDRVPRM, WRITE, struct_floppy_drive_params_sz); | ||
| 172 | _(FDGETDRVSTAT, WRITE, struct_floppy_drive_struct_sz); | ||
| 173 | _(FDGETDRVTYP, WRITE, 16); | ||
| 174 | _(FDGETFDCSTAT, WRITE, struct_floppy_fdc_state_sz); | ||
| 175 | _(FDGETMAXERRS, WRITE, struct_floppy_max_errors_sz); | ||
| 176 | _(FDGETPRM, WRITE, struct_floppy_struct_sz); | ||
| 177 | _(FDMSGOFF, NONE, 0); | ||
| 178 | _(FDMSGON, NONE, 0); | ||
| 179 | _(FDPOLLDRVSTAT, WRITE, struct_floppy_drive_struct_sz); | ||
| 180 | _(FDRAWCMD, WRITE, struct_floppy_raw_cmd_sz); | ||
| 181 | _(FDRESET, NONE, 0); | ||
| 182 | _(FDSETDRVPRM, READ, struct_floppy_drive_params_sz); | ||
| 183 | _(FDSETEMSGTRESH, NONE, 0); | ||
| 184 | _(FDSETMAXERRS, READ, struct_floppy_max_errors_sz); | ||
| 185 | _(FDSETPRM, READ, struct_floppy_struct_sz); | ||
| 186 | _(FDTWADDLE, NONE, 0); | ||
| 187 | _(FDWERRORCLR, NONE, 0); | ||
| 188 | _(FDWERRORGET, WRITE, struct_floppy_write_errors_sz); | ||
| 189 | _(HDIO_DRIVE_CMD, WRITE, sizeof(int)); | ||
| 190 | _(HDIO_GETGEO, WRITE, struct_hd_geometry_sz); | ||
| 191 | _(HDIO_GET_32BIT, WRITE, sizeof(int)); | ||
| 192 | _(HDIO_GET_DMA, WRITE, sizeof(int)); | ||
| 193 | _(HDIO_GET_IDENTITY, WRITE, struct_hd_driveid_sz); | ||
| 194 | _(HDIO_GET_KEEPSETTINGS, WRITE, sizeof(int)); | ||
| 195 | _(HDIO_GET_MULTCOUNT, WRITE, sizeof(int)); | ||
| 196 | _(HDIO_GET_NOWERR, WRITE, sizeof(int)); | ||
| 197 | _(HDIO_GET_UNMASKINTR, WRITE, sizeof(int)); | ||
| 198 | _(HDIO_SET_32BIT, NONE, 0); | ||
| 199 | _(HDIO_SET_DMA, NONE, 0); | ||
| 200 | _(HDIO_SET_KEEPSETTINGS, NONE, 0); | ||
| 201 | _(HDIO_SET_MULTCOUNT, NONE, 0); | ||
| 202 | _(HDIO_SET_NOWERR, NONE, 0); | ||
| 203 | _(HDIO_SET_UNMASKINTR, NONE, 0); | ||
| 204 | _(MTIOCGET, WRITE, struct_mtget_sz); | ||
| 205 | _(MTIOCPOS, WRITE, struct_mtpos_sz); | ||
| 206 | _(MTIOCTOP, READ, struct_mtop_sz); | ||
| 207 | _(PPPIOCGASYNCMAP, WRITE, sizeof(int)); | ||
| 208 | _(PPPIOCGDEBUG, WRITE, sizeof(int)); | ||
| 209 | _(PPPIOCGFLAGS, WRITE, sizeof(int)); | ||
| 210 | _(PPPIOCGUNIT, WRITE, sizeof(int)); | ||
| 211 | _(PPPIOCGXASYNCMAP, WRITE, sizeof(int) * 8); | ||
| 212 | _(PPPIOCSASYNCMAP, READ, sizeof(int)); | ||
| 213 | _(PPPIOCSDEBUG, READ, sizeof(int)); | ||
| 214 | _(PPPIOCSFLAGS, READ, sizeof(int)); | ||
| 215 | _(PPPIOCSMAXCID, READ, sizeof(int)); | ||
| 216 | _(PPPIOCSMRU, READ, sizeof(int)); | ||
| 217 | _(PPPIOCSXASYNCMAP, READ, sizeof(int) * 8); | ||
| 218 | _(SIOCADDRT, READ, struct_rtentry_sz); | ||
| 219 | _(SIOCDARP, READ, struct_arpreq_sz); | ||
| 220 | _(SIOCDELRT, READ, struct_rtentry_sz); | ||
| 221 | _(SIOCDRARP, READ, struct_arpreq_sz); | ||
| 222 | _(SIOCGARP, WRITE, struct_arpreq_sz); | ||
| 223 | _(SIOCGIFENCAP, WRITE, sizeof(int)); | ||
| 224 | _(SIOCGIFHWADDR, WRITE, struct_ifreq_sz); | ||
| 225 | _(SIOCGIFMAP, WRITE, struct_ifreq_sz); | ||
| 226 | _(SIOCGIFMEM, WRITE, struct_ifreq_sz); | ||
| 227 | _(SIOCGIFNAME, NONE, 0); | ||
| 228 | _(SIOCGIFSLAVE, NONE, 0); | ||
| 229 | _(SIOCGRARP, WRITE, struct_arpreq_sz); | ||
| 230 | _(SIOCGSTAMP, WRITE, timeval_sz); | ||
| 231 | _(SIOCSARP, READ, struct_arpreq_sz); | ||
| 232 | _(SIOCSIFENCAP, READ, sizeof(int)); | ||
| 233 | _(SIOCSIFHWADDR, READ, struct_ifreq_sz); | ||
| 234 | _(SIOCSIFLINK, NONE, 0); | ||
| 235 | _(SIOCSIFMAP, READ, struct_ifreq_sz); | ||
| 236 | _(SIOCSIFMEM, READ, struct_ifreq_sz); | ||
| 237 | _(SIOCSIFSLAVE, NONE, 0); | ||
| 238 | _(SIOCSRARP, READ, struct_arpreq_sz); | ||
| 239 | _(SNDCTL_COPR_HALT, WRITE, struct_copr_debug_buf_sz); | ||
| 240 | _(SNDCTL_COPR_LOAD, READ, struct_copr_buffer_sz); | ||
| 241 | _(SNDCTL_COPR_RCODE, WRITE, struct_copr_debug_buf_sz); | ||
| 242 | _(SNDCTL_COPR_RCVMSG, WRITE, struct_copr_msg_sz); | ||
| 243 | _(SNDCTL_COPR_RDATA, WRITE, struct_copr_debug_buf_sz); | ||
| 244 | _(SNDCTL_COPR_RESET, NONE, 0); | ||
| 245 | _(SNDCTL_COPR_RUN, WRITE, struct_copr_debug_buf_sz); | ||
| 246 | _(SNDCTL_COPR_SENDMSG, READ, struct_copr_msg_sz); | ||
| 247 | _(SNDCTL_COPR_WCODE, READ, struct_copr_debug_buf_sz); | ||
| 248 | _(SNDCTL_COPR_WDATA, READ, struct_copr_debug_buf_sz); | ||
| 249 | _(SNDCTL_DSP_GETBLKSIZE, WRITE, sizeof(int)); | ||
| 250 | _(SNDCTL_DSP_GETFMTS, WRITE, sizeof(int)); | ||
| 251 | _(SNDCTL_DSP_NONBLOCK, NONE, 0); | ||
| 252 | _(SNDCTL_DSP_POST, NONE, 0); | ||
| 253 | _(SNDCTL_DSP_RESET, NONE, 0); | ||
| 254 | _(SNDCTL_DSP_SETFMT, WRITE, sizeof(int)); | ||
| 255 | _(SNDCTL_DSP_SETFRAGMENT, WRITE, sizeof(int)); | ||
| 256 | _(SNDCTL_DSP_SPEED, WRITE, sizeof(int)); | ||
| 257 | _(SNDCTL_DSP_STEREO, WRITE, sizeof(int)); | ||
| 258 | _(SNDCTL_DSP_SUBDIVIDE, WRITE, sizeof(int)); | ||
| 259 | _(SNDCTL_DSP_SYNC, NONE, 0); | ||
| 260 | _(SNDCTL_FM_4OP_ENABLE, READ, sizeof(int)); | ||
| 261 | _(SNDCTL_FM_LOAD_INSTR, READ, struct_sbi_instrument_sz); | ||
| 262 | _(SNDCTL_MIDI_INFO, WRITE, struct_midi_info_sz); | ||
| 263 | _(SNDCTL_MIDI_PRETIME, WRITE, sizeof(int)); | ||
| 264 | _(SNDCTL_SEQ_CTRLRATE, WRITE, sizeof(int)); | ||
| 265 | _(SNDCTL_SEQ_GETINCOUNT, WRITE, sizeof(int)); | ||
| 266 | _(SNDCTL_SEQ_GETOUTCOUNT, WRITE, sizeof(int)); | ||
| 267 | _(SNDCTL_SEQ_NRMIDIS, WRITE, sizeof(int)); | ||
| 268 | _(SNDCTL_SEQ_NRSYNTHS, WRITE, sizeof(int)); | ||
| 269 | _(SNDCTL_SEQ_OUTOFBAND, READ, struct_seq_event_rec_sz); | ||
| 270 | _(SNDCTL_SEQ_PANIC, NONE, 0); | ||
| 271 | _(SNDCTL_SEQ_PERCMODE, NONE, 0); | ||
| 272 | _(SNDCTL_SEQ_RESET, NONE, 0); | ||
| 273 | _(SNDCTL_SEQ_RESETSAMPLES, READ, sizeof(int)); | ||
| 274 | _(SNDCTL_SEQ_SYNC, NONE, 0); | ||
| 275 | _(SNDCTL_SEQ_TESTMIDI, READ, sizeof(int)); | ||
| 276 | _(SNDCTL_SEQ_THRESHOLD, READ, sizeof(int)); | ||
| 277 | _(SNDCTL_SYNTH_INFO, WRITE, struct_synth_info_sz); | ||
| 278 | _(SNDCTL_SYNTH_MEMAVL, WRITE, sizeof(int)); | ||
| 279 | _(SNDCTL_TMR_METRONOME, READ, sizeof(int)); | ||
| 280 | _(SNDCTL_TMR_SELECT, WRITE, sizeof(int)); | ||
| 281 | _(SNDCTL_TMR_SOURCE, WRITE, sizeof(int)); | ||
| 282 | _(SNDCTL_TMR_TEMPO, WRITE, sizeof(int)); | ||
| 283 | _(SNDCTL_TMR_TIMEBASE, WRITE, sizeof(int)); | ||
| 284 | _(SOUND_MIXER_READ_ALTPCM, WRITE, sizeof(int)); | ||
| 285 | _(SOUND_MIXER_READ_BASS, WRITE, sizeof(int)); | ||
| 286 | _(SOUND_MIXER_READ_CAPS, WRITE, sizeof(int)); | ||
| 287 | _(SOUND_MIXER_READ_CD, WRITE, sizeof(int)); | ||
| 288 | _(SOUND_MIXER_READ_DEVMASK, WRITE, sizeof(int)); | ||
| 289 | _(SOUND_MIXER_READ_ENHANCE, WRITE, sizeof(int)); | ||
| 290 | _(SOUND_MIXER_READ_IGAIN, WRITE, sizeof(int)); | ||
| 291 | _(SOUND_MIXER_READ_IMIX, WRITE, sizeof(int)); | ||
| 292 | _(SOUND_MIXER_READ_LINE, WRITE, sizeof(int)); | ||
| 293 | _(SOUND_MIXER_READ_LINE1, WRITE, sizeof(int)); | ||
| 294 | _(SOUND_MIXER_READ_LINE2, WRITE, sizeof(int)); | ||
| 295 | _(SOUND_MIXER_READ_LINE3, WRITE, sizeof(int)); | ||
| 296 | _(SOUND_MIXER_READ_MIC, WRITE, sizeof(int)); | ||
| 297 | _(SOUND_MIXER_READ_OGAIN, WRITE, sizeof(int)); | ||
| 298 | _(SOUND_MIXER_READ_PCM, WRITE, sizeof(int)); | ||
| 299 | _(SOUND_MIXER_READ_RECLEV, WRITE, sizeof(int)); | ||
| 300 | _(SOUND_MIXER_READ_RECMASK, WRITE, sizeof(int)); | ||
| 301 | _(SOUND_MIXER_READ_RECSRC, WRITE, sizeof(int)); | ||
| 302 | _(SOUND_MIXER_READ_SPEAKER, WRITE, sizeof(int)); | ||
| 303 | _(SOUND_MIXER_READ_STEREODEVS, WRITE, sizeof(int)); | ||
| 304 | _(SOUND_MIXER_READ_SYNTH, WRITE, sizeof(int)); | ||
| 305 | _(SOUND_MIXER_READ_TREBLE, WRITE, sizeof(int)); | ||
| 306 | _(SOUND_MIXER_READ_VOLUME, WRITE, sizeof(int)); | ||
| 307 | _(SOUND_MIXER_WRITE_ALTPCM, WRITE, sizeof(int)); | ||
| 308 | _(SOUND_MIXER_WRITE_BASS, WRITE, sizeof(int)); | ||
| 309 | _(SOUND_MIXER_WRITE_CD, WRITE, sizeof(int)); | ||
| 310 | _(SOUND_MIXER_WRITE_ENHANCE, WRITE, sizeof(int)); | ||
| 311 | _(SOUND_MIXER_WRITE_IGAIN, WRITE, sizeof(int)); | ||
| 312 | _(SOUND_MIXER_WRITE_IMIX, WRITE, sizeof(int)); | ||
| 313 | _(SOUND_MIXER_WRITE_LINE, WRITE, sizeof(int)); | ||
| 314 | _(SOUND_MIXER_WRITE_LINE1, WRITE, sizeof(int)); | ||
| 315 | _(SOUND_MIXER_WRITE_LINE2, WRITE, sizeof(int)); | ||
| 316 | _(SOUND_MIXER_WRITE_LINE3, WRITE, sizeof(int)); | ||
| 317 | _(SOUND_MIXER_WRITE_MIC, WRITE, sizeof(int)); | ||
| 318 | _(SOUND_MIXER_WRITE_OGAIN, WRITE, sizeof(int)); | ||
| 319 | _(SOUND_MIXER_WRITE_PCM, WRITE, sizeof(int)); | ||
| 320 | _(SOUND_MIXER_WRITE_RECLEV, WRITE, sizeof(int)); | ||
| 321 | _(SOUND_MIXER_WRITE_RECSRC, WRITE, sizeof(int)); | ||
| 322 | _(SOUND_MIXER_WRITE_SPEAKER, WRITE, sizeof(int)); | ||
| 323 | _(SOUND_MIXER_WRITE_SYNTH, WRITE, sizeof(int)); | ||
| 324 | _(SOUND_MIXER_WRITE_TREBLE, WRITE, sizeof(int)); | ||
| 325 | _(SOUND_MIXER_WRITE_VOLUME, WRITE, sizeof(int)); | ||
| 326 | _(SOUND_PCM_READ_BITS, WRITE, sizeof(int)); | ||
| 327 | _(SOUND_PCM_READ_CHANNELS, WRITE, sizeof(int)); | ||
| 328 | _(SOUND_PCM_READ_FILTER, WRITE, sizeof(int)); | ||
| 329 | _(SOUND_PCM_READ_RATE, WRITE, sizeof(int)); | ||
| 330 | _(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int)); | ||
| 331 | _(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int)); | ||
| 332 | _(TCFLSH, NONE, 0); | ||
| 333 | _(TCGETA, WRITE, struct_termio_sz); | ||
| 334 | _(TCGETS, WRITE, struct_termios_sz); | ||
| 335 | _(TCSBRK, NONE, 0); | ||
| 336 | _(TCSBRKP, NONE, 0); | ||
| 337 | _(TCSETA, READ, struct_termio_sz); | ||
| 338 | _(TCSETAF, READ, struct_termio_sz); | ||
| 339 | _(TCSETAW, READ, struct_termio_sz); | ||
| 340 | _(TCSETS, READ, struct_termios_sz); | ||
| 341 | _(TCSETSF, READ, struct_termios_sz); | ||
| 342 | _(TCSETSW, READ, struct_termios_sz); | ||
| 343 | _(TCXONC, NONE, 0); | ||
| 344 | _(TIOCGLCKTRMIOS, WRITE, struct_termios_sz); | ||
| 345 | _(TIOCGSOFTCAR, WRITE, sizeof(int)); | ||
| 346 | _(TIOCINQ, WRITE, sizeof(int)); | ||
| 347 | _(TIOCLINUX, READ, sizeof(char)); | ||
| 348 | _(TIOCSERCONFIG, NONE, 0); | ||
| 349 | _(TIOCSERGETLSR, WRITE, sizeof(int)); | ||
| 350 | _(TIOCSERGWILD, WRITE, sizeof(int)); | ||
| 351 | _(TIOCSERSWILD, READ, sizeof(int)); | ||
| 352 | _(TIOCSLCKTRMIOS, READ, struct_termios_sz); | ||
| 353 | _(TIOCSSOFTCAR, READ, sizeof(int)); | ||
| 354 | _(VT_ACTIVATE, NONE, 0); | ||
| 355 | _(VT_DISALLOCATE, NONE, 0); | ||
| 356 | _(VT_GETMODE, WRITE, struct_vt_mode_sz); | ||
| 357 | _(VT_GETSTATE, WRITE, struct_vt_stat_sz); | ||
| 358 | _(VT_OPENQRY, WRITE, sizeof(int)); | ||
| 359 | _(VT_RELDISP, NONE, 0); | ||
| 360 | _(VT_RESIZE, READ, struct_vt_sizes_sz); | ||
| 361 | _(VT_RESIZEX, READ, struct_vt_consize_sz); | ||
| 362 | _(VT_SENDSIG, NONE, 0); | ||
| 363 | _(VT_SETMODE, READ, struct_vt_mode_sz); | ||
| 364 | _(VT_WAITACTIVE, NONE, 0); | ||
| 365 | #endif | ||
| 366 | |||
| 367 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 368 | // _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE | ||
| 369 | _(CYGETDEFTHRESH, WRITE, sizeof(int)); | ||
| 370 | _(CYGETDEFTIMEOUT, WRITE, sizeof(int)); | ||
| 371 | _(CYGETMON, WRITE, struct_cyclades_monitor_sz); | ||
| 372 | _(CYGETTHRESH, WRITE, sizeof(int)); | ||
| 373 | _(CYGETTIMEOUT, WRITE, sizeof(int)); | ||
| 374 | _(CYSETDEFTHRESH, NONE, 0); | ||
| 375 | _(CYSETDEFTIMEOUT, NONE, 0); | ||
| 376 | _(CYSETTHRESH, NONE, 0); | ||
| 377 | _(CYSETTIMEOUT, NONE, 0); | ||
| 378 | _(EQL_EMANCIPATE, WRITE, struct_ifreq_sz); | ||
| 379 | _(EQL_ENSLAVE, WRITE, struct_ifreq_sz); | ||
| 380 | _(EQL_GETMASTRCFG, WRITE, struct_ifreq_sz); | ||
| 381 | _(EQL_GETSLAVECFG, WRITE, struct_ifreq_sz); | ||
| 382 | _(EQL_SETMASTRCFG, WRITE, struct_ifreq_sz); | ||
| 383 | _(EQL_SETSLAVECFG, WRITE, struct_ifreq_sz); | ||
| 384 | _(EVIOCGKEYCODE_V2, WRITE, struct_input_keymap_entry_sz); | ||
| 385 | _(EVIOCGPROP, WRITE, 0); | ||
| 386 | _(EVIOCSKEYCODE_V2, READ, struct_input_keymap_entry_sz); | ||
| 387 | _(FS_IOC_GETFLAGS, WRITE, sizeof(int)); | ||
| 388 | _(FS_IOC_GETVERSION, WRITE, sizeof(int)); | ||
| 389 | _(FS_IOC_SETFLAGS, READ, sizeof(int)); | ||
| 390 | _(FS_IOC_SETVERSION, READ, sizeof(int)); | ||
| 391 | _(GIO_CMAP, WRITE, 48); | ||
| 392 | _(GIO_FONT, WRITE, 8192); | ||
| 393 | _(GIO_SCRNMAP, WRITE, e_tabsz); | ||
| 394 | _(GIO_UNIMAP, WRITE, struct_unimapdesc_sz); | ||
| 395 | _(GIO_UNISCRNMAP, WRITE, sizeof(short) * e_tabsz); | ||
| 396 | _(KDADDIO, NONE, 0); | ||
| 397 | _(KDDELIO, NONE, 0); | ||
| 398 | _(KDDISABIO, NONE, 0); | ||
| 399 | _(KDENABIO, NONE, 0); | ||
| 400 | _(KDGETKEYCODE, WRITE, struct_kbkeycode_sz); | ||
| 401 | _(KDGETLED, WRITE, 1); | ||
| 402 | _(KDGETMODE, WRITE, sizeof(int)); | ||
| 403 | _(KDGKBDIACR, WRITE, struct_kbdiacrs_sz); | ||
| 404 | _(KDGKBENT, WRITE, struct_kbentry_sz); | ||
| 405 | _(KDGKBLED, WRITE, sizeof(int)); | ||
| 406 | _(KDGKBMETA, WRITE, sizeof(int)); | ||
| 407 | _(KDGKBMODE, WRITE, sizeof(int)); | ||
| 408 | _(KDGKBSENT, WRITE, struct_kbsentry_sz); | ||
| 409 | _(KDGKBTYPE, WRITE, 1); | ||
| 410 | _(KDMAPDISP, NONE, 0); | ||
| 411 | _(KDMKTONE, NONE, 0); | ||
| 412 | _(KDSETKEYCODE, READ, struct_kbkeycode_sz); | ||
| 413 | _(KDSETLED, NONE, 0); | ||
| 414 | _(KDSETMODE, NONE, 0); | ||
| 415 | _(KDSIGACCEPT, NONE, 0); | ||
| 416 | _(KDSKBDIACR, READ, struct_kbdiacrs_sz); | ||
| 417 | _(KDSKBENT, READ, struct_kbentry_sz); | ||
| 418 | _(KDSKBLED, NONE, 0); | ||
| 419 | _(KDSKBMETA, NONE, 0); | ||
| 420 | _(KDSKBMODE, NONE, 0); | ||
| 421 | _(KDSKBSENT, READ, struct_kbsentry_sz); | ||
| 422 | _(KDUNMAPDISP, NONE, 0); | ||
| 423 | _(KIOCSOUND, NONE, 0); | ||
| 424 | _(LPABORT, NONE, 0); | ||
| 425 | _(LPABORTOPEN, NONE, 0); | ||
| 426 | _(LPCAREFUL, NONE, 0); | ||
| 427 | _(LPCHAR, NONE, 0); | ||
| 428 | _(LPGETIRQ, WRITE, sizeof(int)); | ||
| 429 | _(LPGETSTATUS, WRITE, sizeof(int)); | ||
| 430 | _(LPRESET, NONE, 0); | ||
| 431 | _(LPSETIRQ, NONE, 0); | ||
| 432 | _(LPTIME, NONE, 0); | ||
| 433 | _(LPWAIT, NONE, 0); | ||
| 434 | _(MTIOCGETCONFIG, WRITE, struct_mtconfiginfo_sz); | ||
| 435 | _(MTIOCSETCONFIG, READ, struct_mtconfiginfo_sz); | ||
| 436 | _(PIO_CMAP, NONE, 0); | ||
| 437 | _(PIO_FONT, READ, 8192); | ||
| 438 | _(PIO_SCRNMAP, READ, e_tabsz); | ||
| 439 | _(PIO_UNIMAP, READ, struct_unimapdesc_sz); | ||
| 440 | _(PIO_UNIMAPCLR, READ, struct_unimapinit_sz); | ||
| 441 | _(PIO_UNISCRNMAP, READ, sizeof(short) * e_tabsz); | ||
| 442 | _(SCSI_IOCTL_PROBE_HOST, READ, sizeof(int)); | ||
| 443 | _(SCSI_IOCTL_TAGGED_DISABLE, NONE, 0); | ||
| 444 | _(SCSI_IOCTL_TAGGED_ENABLE, NONE, 0); | ||
| 445 | _(SNDCTL_DSP_GETISPACE, WRITE, struct_audio_buf_info_sz); | ||
| 446 | _(SNDCTL_DSP_GETOSPACE, WRITE, struct_audio_buf_info_sz); | ||
| 447 | _(TIOCGSERIAL, WRITE, struct_serial_struct_sz); | ||
| 448 | _(TIOCSERGETMULTI, WRITE, struct_serial_multiport_struct_sz); | ||
| 449 | _(TIOCSERSETMULTI, READ, struct_serial_multiport_struct_sz); | ||
| 450 | _(TIOCSSERIAL, READ, struct_serial_struct_sz); | ||
| 451 | |||
| 452 | // The following ioctl requests are shared between AX25, IPX, netrom and | ||
| 453 | // mrouted. | ||
| 454 | // _(SIOCAIPXITFCRT, READ, sizeof(char)); | ||
| 455 | // _(SIOCAX25GETUID, READ, struct_sockaddr_ax25_sz); | ||
| 456 | // _(SIOCNRGETPARMS, WRITE, struct_nr_parms_struct_sz); | ||
| 457 | // _(SIOCAIPXPRISLT, READ, sizeof(char)); | ||
| 458 | // _(SIOCNRSETPARMS, READ, struct_nr_parms_struct_sz); | ||
| 459 | // _(SIOCAX25ADDUID, READ, struct_sockaddr_ax25_sz); | ||
| 460 | // _(SIOCNRDECOBS, NONE, 0); | ||
| 461 | // _(SIOCAX25DELUID, READ, struct_sockaddr_ax25_sz); | ||
| 462 | // _(SIOCIPXCFGDATA, WRITE, struct_ipx_config_data_sz); | ||
| 463 | // _(SIOCAX25NOUID, READ, sizeof(int)); | ||
| 464 | // _(SIOCNRRTCTL, READ, sizeof(int)); | ||
| 465 | // _(SIOCAX25DIGCTL, READ, sizeof(int)); | ||
| 466 | // _(SIOCAX25GETPARMS, WRITE, struct_ax25_parms_struct_sz); | ||
| 467 | // _(SIOCAX25SETPARMS, READ, struct_ax25_parms_struct_sz); | ||
| 468 | #endif | ||
| 469 | #undef _ | ||
| 470 | } | ||
| 471 | |||
| 472 | static bool ioctl_initialized = false; | ||
| 473 | |||
| 474 | struct ioctl_desc_compare { | ||
| 475 | bool operator()(const ioctl_desc& left, const ioctl_desc& right) const { | ||
| 476 | return left.req < right.req; | ||
| 477 | } | ||
| 478 | }; | ||
| 479 | |||
| 480 | static void ioctl_init() { | ||
| 481 | ioctl_table_fill(); | ||
| 482 | Sort(ioctl_table, ioctl_table_size, ioctl_desc_compare()); | ||
| 483 | |||
| 484 | bool bad = false; | ||
| 485 | for (unsigned i = 0; i < ioctl_table_size - 1; ++i) { | ||
| 486 | if (ioctl_table[i].req >= ioctl_table[i + 1].req) { | ||
| 487 | Printf("Duplicate or unsorted ioctl request id %x >= %x (%s vs %s)\n", | ||
| 488 | ioctl_table[i].req, ioctl_table[i + 1].req, ioctl_table[i].name, | ||
| 489 | ioctl_table[i + 1].name); | ||
| 490 | bad = true; | ||
| 491 | } | ||
| 492 | } | ||
| 493 | |||
| 494 | if (bad) Die(); | ||
| 495 | |||
| 496 | ioctl_initialized = true; | ||
| 497 | } | ||
| 498 | |||
| 499 | // Handle the most evil ioctls that encode argument value as part of request id. | ||
| 500 | static unsigned ioctl_request_fixup(unsigned req) { | ||
| 501 | #if SANITIZER_LINUX | ||
| 502 | // Strip size and event number. | ||
| 503 | const unsigned kEviocgbitMask = | ||
| 504 | (IOC_SIZEMASK << IOC_SIZESHIFT) | EVIOC_EV_MAX; | ||
| 505 | if ((req & ~kEviocgbitMask) == IOCTL_EVIOCGBIT) | ||
| 506 | return IOCTL_EVIOCGBIT; | ||
| 507 | // Strip absolute axis number. | ||
| 508 | if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCGABS) | ||
| 509 | return IOCTL_EVIOCGABS; | ||
| 510 | if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCSABS) | ||
| 511 | return IOCTL_EVIOCSABS; | ||
| 512 | #endif | ||
| 513 | return req; | ||
| 514 | } | ||
| 515 | |||
| 516 | static const ioctl_desc *ioctl_table_lookup(unsigned req) { | ||
| 517 | int left = 0; | ||
| 518 | int right = ioctl_table_size; | ||
| 519 | while (left < right) { | ||
| 520 | int mid = (left + right) / 2; | ||
| 521 | if (ioctl_table[mid].req < req) | ||
| 522 | left = mid + 1; | ||
| 523 | else | ||
| 524 | right = mid; | ||
| 525 | } | ||
| 526 | if (left == right && ioctl_table[left].req == req) | ||
| 527 | return ioctl_table + left; | ||
| 528 | else | ||
| 529 | return nullptr; | ||
| 530 | } | ||
| 531 | |||
| 532 | static bool ioctl_decode(unsigned req, ioctl_desc *desc) { | ||
| 533 | CHECK(desc); | ||
| 534 | desc->req = req; | ||
| 535 | desc->name = "<DECODED_IOCTL>"; | ||
| 536 | desc->size = IOC_SIZE(req); | ||
| 537 | // Sanity check. | ||
| 538 | if (desc->size > 0xFFFF) return false; | ||
| 539 | unsigned dir = IOC_DIR(req); | ||
| 540 | switch (dir) { | ||
| 541 | case IOC_NONE: | ||
| 542 | desc->type = ioctl_desc::NONE; | ||
| 543 | break; | ||
| 544 | case IOC_READ | IOC_WRITE: | ||
| 545 | desc->type = ioctl_desc::READWRITE; | ||
| 546 | break; | ||
| 547 | case IOC_READ: | ||
| 548 | desc->type = ioctl_desc::WRITE; | ||
| 549 | break; | ||
| 550 | case IOC_WRITE: | ||
| 551 | desc->type = ioctl_desc::READ; | ||
| 552 | break; | ||
| 553 | default: | ||
| 554 | return false; | ||
| 555 | } | ||
| 556 | // Size can be 0 iff type is NONE. | ||
| 557 | if ((desc->type == IOC_NONE) != (desc->size == 0)) return false; | ||
| 558 | // Sanity check. | ||
| 559 | if (IOC_TYPE(req) == 0) return false; | ||
| 560 | return true; | ||
| 561 | } | ||
| 562 | |||
| 563 | static const ioctl_desc *ioctl_lookup(unsigned req) { | ||
| 564 | req = ioctl_request_fixup(req); | ||
| 565 | const ioctl_desc *desc = ioctl_table_lookup(req); | ||
| 566 | if (desc) return desc; | ||
| 567 | |||
| 568 | // Try stripping access size from the request id. | ||
| 569 | desc = ioctl_table_lookup(req & ~(IOC_SIZEMASK << IOC_SIZESHIFT)); | ||
| 570 | // Sanity check: requests that encode access size are either read or write and | ||
| 571 | // have size of 0 in the table. | ||
| 572 | if (desc && desc->size == 0 && | ||
| 573 | (desc->type == ioctl_desc::READWRITE || desc->type == ioctl_desc::WRITE || | ||
| 574 | desc->type == ioctl_desc::READ)) | ||
| 575 | return desc; | ||
| 576 | return nullptr; | ||
| 577 | } | ||
| 578 | |||
| 579 | static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d, | ||
| 580 | unsigned request, void *arg) { | ||
| 581 | if (desc->type == ioctl_desc::READ || desc->type == ioctl_desc::READWRITE) { | ||
| 582 | unsigned size = desc->size ? desc->size : IOC_SIZE(request); | ||
| 583 | COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size); | ||
| 584 | } | ||
| 585 | if (desc->type != ioctl_desc::CUSTOM) | ||
| 586 | return; | ||
| 587 | if (request == IOCTL_SIOCGIFCONF) { | ||
| 588 | struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg; | ||
| 589 | COMMON_INTERCEPTOR_READ_RANGE(ctx, (char*)&ifc->ifc_len, | ||
| 590 | sizeof(ifc->ifc_len)); | ||
| 591 | } | ||
| 592 | } | ||
| 593 | |||
| 594 | static void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d, | ||
| 595 | unsigned request, void *arg) { | ||
| 596 | if (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READWRITE) { | ||
| 597 | // FIXME: add verbose output | ||
| 598 | unsigned size = desc->size ? desc->size : IOC_SIZE(request); | ||
| 599 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size); | ||
| 600 | } | ||
| 601 | if (desc->type != ioctl_desc::CUSTOM) | ||
| 602 | return; | ||
| 603 | if (request == IOCTL_SIOCGIFCONF) { | ||
| 604 | struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg; | ||
| 605 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifc->ifc_ifcu.ifcu_req, ifc->ifc_len); | ||
| 606 | } | ||
| 607 | } | ||
| 608 | |||
| 609 | #endif | ||
lib/tsan/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc created+128| ... | @@ -0,0 +1,128 @@ | ||
| 1 | //===-- sanitizer_common_interceptors_netbsd_compat.inc ---------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Common function interceptors for tools like AddressSanitizer, | ||
| 10 | // ThreadSanitizer, MemorySanitizer, etc. | ||
| 11 | // | ||
| 12 | // Interceptors for NetBSD old function calls that have been versioned. | ||
| 13 | // | ||
| 14 | // NetBSD minimal version supported 9.0. | ||
| 15 | // NetBSD current version supported 9.99.26. | ||
| 16 | // | ||
| 17 | //===----------------------------------------------------------------------===// | ||
| 18 | |||
| 19 | #if SANITIZER_NETBSD | ||
| 20 | |||
| 21 | // First undef all mangled symbols. | ||
| 22 | // Next, define compat interceptors. | ||
| 23 | // Finally, undef INIT_ and redefine it. | ||
| 24 | // This allows to avoid preprocessor issues. | ||
| 25 | |||
| 26 | #undef fstatvfs | ||
| 27 | #undef fstatvfs1 | ||
| 28 | #undef getmntinfo | ||
| 29 | #undef getvfsstat | ||
| 30 | #undef statvfs | ||
| 31 | #undef statvfs1 | ||
| 32 | |||
| 33 | INTERCEPTOR(int, statvfs, char *path, void *buf) { | ||
| 34 | void *ctx; | ||
| 35 | COMMON_INTERCEPTOR_ENTER(ctx, statvfs, path, buf); | ||
| 36 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 37 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 38 | // its metadata. See | ||
| 39 | // https://github.com/google/sanitizers/issues/321. | ||
| 40 | int res = REAL(statvfs)(path, buf); | ||
| 41 | if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz); | ||
| 42 | return res; | ||
| 43 | } | ||
| 44 | |||
| 45 | INTERCEPTOR(int, fstatvfs, int fd, void *buf) { | ||
| 46 | void *ctx; | ||
| 47 | COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf); | ||
| 48 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 49 | // FIXME: under ASan the call below may write to freed memory and corrupt | ||
| 50 | // its metadata. See | ||
| 51 | // https://github.com/google/sanitizers/issues/321. | ||
| 52 | int res = REAL(fstatvfs)(fd, buf); | ||
| 53 | if (!res) { | ||
| 54 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz); | ||
| 55 | if (fd >= 0) | ||
| 56 | COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 57 | } | ||
| 58 | return res; | ||
| 59 | } | ||
| 60 | |||
| 61 | #undef INIT_STATVFS | ||
| 62 | #define INIT_STATVFS \ | ||
| 63 | COMMON_INTERCEPT_FUNCTION(statvfs); \ | ||
| 64 | COMMON_INTERCEPT_FUNCTION(fstatvfs); \ | ||
| 65 | COMMON_INTERCEPT_FUNCTION(__statvfs90); \ | ||
| 66 | COMMON_INTERCEPT_FUNCTION(__fstatvfs90) | ||
| 67 | |||
| 68 | INTERCEPTOR(int, __getmntinfo13, void **mntbufp, int flags) { | ||
| 69 | void *ctx; | ||
| 70 | COMMON_INTERCEPTOR_ENTER(ctx, __getmntinfo13, mntbufp, flags); | ||
| 71 | int cnt = REAL(__getmntinfo13)(mntbufp, flags); | ||
| 72 | if (cnt > 0 && mntbufp) { | ||
| 73 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mntbufp, sizeof(void *)); | ||
| 74 | if (*mntbufp) | ||
| 75 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *mntbufp, cnt * struct_statvfs90_sz); | ||
| 76 | } | ||
| 77 | return cnt; | ||
| 78 | } | ||
| 79 | |||
| 80 | #undef INIT_GETMNTINFO | ||
| 81 | #define INIT_GETMNTINFO \ | ||
| 82 | COMMON_INTERCEPT_FUNCTION(__getmntinfo13); \ | ||
| 83 | COMMON_INTERCEPT_FUNCTION(__getmntinfo90) | ||
| 84 | |||
| 85 | INTERCEPTOR(int, getvfsstat, void *buf, SIZE_T bufsize, int flags) { | ||
| 86 | void *ctx; | ||
| 87 | COMMON_INTERCEPTOR_ENTER(ctx, getvfsstat, buf, bufsize, flags); | ||
| 88 | int ret = REAL(getvfsstat)(buf, bufsize, flags); | ||
| 89 | if (buf && ret > 0) | ||
| 90 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, ret * struct_statvfs90_sz); | ||
| 91 | return ret; | ||
| 92 | } | ||
| 93 | |||
| 94 | #undef INIT_GETVFSSTAT | ||
| 95 | #define INIT_GETVFSSTAT \ | ||
| 96 | COMMON_INTERCEPT_FUNCTION(getvfsstat); \ | ||
| 97 | COMMON_INTERCEPT_FUNCTION(__getvfsstat90) | ||
| 98 | |||
| 99 | INTERCEPTOR(int, statvfs1, const char *path, void *buf, int flags) { | ||
| 100 | void *ctx; | ||
| 101 | COMMON_INTERCEPTOR_ENTER(ctx, statvfs1, path, buf, flags); | ||
| 102 | if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); | ||
| 103 | int res = REAL(statvfs1)(path, buf, flags); | ||
| 104 | if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz); | ||
| 105 | return res; | ||
| 106 | } | ||
| 107 | |||
| 108 | INTERCEPTOR(int, fstatvfs1, int fd, void *buf, int flags) { | ||
| 109 | void *ctx; | ||
| 110 | COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs1, fd, buf, flags); | ||
| 111 | COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); | ||
| 112 | int res = REAL(fstatvfs1)(fd, buf, flags); | ||
| 113 | if (!res) { | ||
| 114 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz); | ||
| 115 | if (fd >= 0) | ||
| 116 | COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); | ||
| 117 | } | ||
| 118 | return res; | ||
| 119 | } | ||
| 120 | |||
| 121 | #undef INIT_STATVFS1 | ||
| 122 | #define INIT_STATVFS1 \ | ||
| 123 | COMMON_INTERCEPT_FUNCTION(statvfs1); \ | ||
| 124 | COMMON_INTERCEPT_FUNCTION(fstatvfs1); \ | ||
| 125 | COMMON_INTERCEPT_FUNCTION(__statvfs190); \ | ||
| 126 | COMMON_INTERCEPT_FUNCTION(__fstatvfs190) | ||
| 127 | |||
| 128 | #endif | ||
lib/tsan/sanitizer_common/sanitizer_common_interface.inc created+41| ... | @@ -0,0 +1,41 @@ | ||
| 1 | //===-- sanitizer_common_interface.inc ------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // Sanitizer Common interface list. | ||
| 9 | //===----------------------------------------------------------------------===// | ||
| 10 | INTERFACE_FUNCTION(__sanitizer_acquire_crash_state) | ||
| 11 | INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container) | ||
| 12 | INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address) | ||
| 13 | INTERFACE_FUNCTION(__sanitizer_set_death_callback) | ||
| 14 | INTERFACE_FUNCTION(__sanitizer_set_report_path) | ||
| 15 | INTERFACE_FUNCTION(__sanitizer_set_report_fd) | ||
| 16 | INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container) | ||
| 17 | INTERFACE_WEAK_FUNCTION(__sanitizer_on_print) | ||
| 18 | INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary) | ||
| 19 | INTERFACE_WEAK_FUNCTION(__sanitizer_sandbox_on_notify) | ||
| 20 | // Sanitizer weak hooks | ||
| 21 | INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_memcmp) | ||
| 22 | INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_strcmp) | ||
| 23 | INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_strncmp) | ||
| 24 | INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_strstr) | ||
| 25 | // Stacktrace interface. | ||
| 26 | INTERFACE_FUNCTION(__sanitizer_get_module_and_offset_for_pc) | ||
| 27 | INTERFACE_FUNCTION(__sanitizer_symbolize_global) | ||
| 28 | INTERFACE_FUNCTION(__sanitizer_symbolize_pc) | ||
| 29 | // Allocator interface. | ||
| 30 | INTERFACE_FUNCTION(__sanitizer_get_allocated_size) | ||
| 31 | INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes) | ||
| 32 | INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size) | ||
| 33 | INTERFACE_FUNCTION(__sanitizer_get_free_bytes) | ||
| 34 | INTERFACE_FUNCTION(__sanitizer_get_heap_size) | ||
| 35 | INTERFACE_FUNCTION(__sanitizer_get_ownership) | ||
| 36 | INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes) | ||
| 37 | INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks) | ||
| 38 | INTERFACE_FUNCTION(__sanitizer_purge_allocator) | ||
| 39 | INTERFACE_FUNCTION(__sanitizer_print_memory_profile) | ||
| 40 | INTERFACE_WEAK_FUNCTION(__sanitizer_free_hook) | ||
| 41 | INTERFACE_WEAK_FUNCTION(__sanitizer_malloc_hook) | ||
lib/tsan/sanitizer_common/sanitizer_common_interface_posix.inc created+13| ... | @@ -0,0 +1,13 @@ | ||
| 1 | //===-- sanitizer_common_interface_posix.inc ------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // Sanitizer Common interface list only available for Posix systems. | ||
| 9 | //===----------------------------------------------------------------------===// | ||
| 10 | INTERFACE_WEAK_FUNCTION(__sanitizer_symbolize_code) | ||
| 11 | INTERFACE_WEAK_FUNCTION(__sanitizer_symbolize_data) | ||
| 12 | INTERFACE_WEAK_FUNCTION(__sanitizer_symbolize_demangle) | ||
| 13 | INTERFACE_WEAK_FUNCTION(__sanitizer_symbolize_flush) | ||
lib/tsan/sanitizer_common/sanitizer_common_syscalls.inc created+2914| ... | @@ -0,0 +1,2914 @@ | ||
| 1 | //===-- sanitizer_common_syscalls.inc ---------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Common syscalls handlers for tools like AddressSanitizer, | ||
| 10 | // ThreadSanitizer, MemorySanitizer, etc. | ||
| 11 | // | ||
| 12 | // This file should be included into the tool's interceptor file, | ||
| 13 | // which has to define it's own macros: | ||
| 14 | // COMMON_SYSCALL_PRE_READ_RANGE | ||
| 15 | // Called in prehook for regions that will be read by the kernel and | ||
| 16 | // must be initialized. | ||
| 17 | // COMMON_SYSCALL_PRE_WRITE_RANGE | ||
| 18 | // Called in prehook for regions that will be written to by the kernel | ||
| 19 | // and must be addressable. The actual write range may be smaller than | ||
| 20 | // reported in the prehook. See POST_WRITE_RANGE. | ||
| 21 | // COMMON_SYSCALL_POST_READ_RANGE | ||
| 22 | // Called in posthook for regions that were read by the kernel. Does | ||
| 23 | // not make much sense. | ||
| 24 | // COMMON_SYSCALL_POST_WRITE_RANGE | ||
| 25 | // Called in posthook for regions that were written to by the kernel | ||
| 26 | // and are now initialized. | ||
| 27 | // COMMON_SYSCALL_ACQUIRE(addr) | ||
| 28 | // Acquire memory visibility from addr. | ||
| 29 | // COMMON_SYSCALL_RELEASE(addr) | ||
| 30 | // Release memory visibility to addr. | ||
| 31 | // COMMON_SYSCALL_FD_CLOSE(fd) | ||
| 32 | // Called before closing file descriptor fd. | ||
| 33 | // COMMON_SYSCALL_FD_ACQUIRE(fd) | ||
| 34 | // Acquire memory visibility from fd. | ||
| 35 | // COMMON_SYSCALL_FD_RELEASE(fd) | ||
| 36 | // Release memory visibility to fd. | ||
| 37 | // COMMON_SYSCALL_PRE_FORK() | ||
| 38 | // Called before fork syscall. | ||
| 39 | // COMMON_SYSCALL_POST_FORK(long res) | ||
| 40 | // Called after fork syscall. | ||
| 41 | //===----------------------------------------------------------------------===// | ||
| 42 | |||
| 43 | #include "sanitizer_platform.h" | ||
| 44 | #if SANITIZER_LINUX | ||
| 45 | |||
| 46 | #include "sanitizer_libc.h" | ||
| 47 | |||
| 48 | #define PRE_SYSCALL(name) \ | ||
| 49 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name | ||
| 50 | #define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s) | ||
| 51 | #define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) | ||
| 52 | |||
| 53 | #define POST_SYSCALL(name) \ | ||
| 54 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_impl_##name | ||
| 55 | #define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s) | ||
| 56 | #define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s) | ||
| 57 | |||
| 58 | #ifndef COMMON_SYSCALL_ACQUIRE | ||
| 59 | # define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr)) | ||
| 60 | #endif | ||
| 61 | |||
| 62 | #ifndef COMMON_SYSCALL_RELEASE | ||
| 63 | # define COMMON_SYSCALL_RELEASE(addr) ((void)(addr)) | ||
| 64 | #endif | ||
| 65 | |||
| 66 | #ifndef COMMON_SYSCALL_FD_CLOSE | ||
| 67 | # define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd)) | ||
| 68 | #endif | ||
| 69 | |||
| 70 | #ifndef COMMON_SYSCALL_FD_ACQUIRE | ||
| 71 | # define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd)) | ||
| 72 | #endif | ||
| 73 | |||
| 74 | #ifndef COMMON_SYSCALL_FD_RELEASE | ||
| 75 | # define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd)) | ||
| 76 | #endif | ||
| 77 | |||
| 78 | #ifndef COMMON_SYSCALL_PRE_FORK | ||
| 79 | # define COMMON_SYSCALL_PRE_FORK() {} | ||
| 80 | #endif | ||
| 81 | |||
| 82 | #ifndef COMMON_SYSCALL_POST_FORK | ||
| 83 | # define COMMON_SYSCALL_POST_FORK(res) {} | ||
| 84 | #endif | ||
| 85 | |||
| 86 | // FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such). | ||
| 87 | |||
| 88 | extern "C" { | ||
| 89 | struct sanitizer_kernel_iovec { | ||
| 90 | void *iov_base; | ||
| 91 | unsigned long iov_len; | ||
| 92 | }; | ||
| 93 | |||
| 94 | struct sanitizer_kernel_msghdr { | ||
| 95 | void *msg_name; | ||
| 96 | int msg_namelen; | ||
| 97 | struct sanitizer_kernel_iovec *msg_iov; | ||
| 98 | unsigned long msg_iovlen; | ||
| 99 | void *msg_control; | ||
| 100 | unsigned long msg_controllen; | ||
| 101 | unsigned msg_flags; | ||
| 102 | }; | ||
| 103 | |||
| 104 | struct sanitizer_kernel_mmsghdr { | ||
| 105 | struct sanitizer_kernel_msghdr msg_hdr; | ||
| 106 | unsigned msg_len; | ||
| 107 | }; | ||
| 108 | |||
| 109 | struct sanitizer_kernel_timespec { | ||
| 110 | long tv_sec; | ||
| 111 | long tv_nsec; | ||
| 112 | }; | ||
| 113 | |||
| 114 | struct sanitizer_kernel_timeval { | ||
| 115 | long tv_sec; | ||
| 116 | long tv_usec; | ||
| 117 | }; | ||
| 118 | |||
| 119 | struct sanitizer_kernel_rusage { | ||
| 120 | struct sanitizer_kernel_timeval ru_timeval[2]; | ||
| 121 | long ru_long[14]; | ||
| 122 | }; | ||
| 123 | |||
| 124 | struct sanitizer_kernel_sockaddr { | ||
| 125 | unsigned short sa_family; | ||
| 126 | char sa_data[14]; | ||
| 127 | }; | ||
| 128 | |||
| 129 | // Real sigset size is always passed as a syscall argument. | ||
| 130 | // Declare it "void" to catch sizeof(kernel_sigset_t). | ||
| 131 | typedef void kernel_sigset_t; | ||
| 132 | |||
| 133 | static void kernel_write_iovec(const __sanitizer_iovec *iovec, | ||
| 134 | SIZE_T iovlen, SIZE_T maxlen) { | ||
| 135 | for (SIZE_T i = 0; i < iovlen && maxlen; ++i) { | ||
| 136 | SSIZE_T sz = Min(iovec[i].iov_len, maxlen); | ||
| 137 | POST_WRITE(iovec[i].iov_base, sz); | ||
| 138 | maxlen -= sz; | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | // This functions uses POST_READ, because it needs to run after syscall to know | ||
| 143 | // the real read range. | ||
| 144 | static void kernel_read_iovec(const __sanitizer_iovec *iovec, | ||
| 145 | SIZE_T iovlen, SIZE_T maxlen) { | ||
| 146 | POST_READ(iovec, sizeof(*iovec) * iovlen); | ||
| 147 | for (SIZE_T i = 0; i < iovlen && maxlen; ++i) { | ||
| 148 | SSIZE_T sz = Min(iovec[i].iov_len, maxlen); | ||
| 149 | POST_READ(iovec[i].iov_base, sz); | ||
| 150 | maxlen -= sz; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | PRE_SYSCALL(recvmsg)(long sockfd, sanitizer_kernel_msghdr *msg, long flags) { | ||
| 155 | PRE_READ(msg, sizeof(*msg)); | ||
| 156 | } | ||
| 157 | |||
| 158 | POST_SYSCALL(recvmsg)(long res, long sockfd, sanitizer_kernel_msghdr *msg, | ||
| 159 | long flags) { | ||
| 160 | if (res >= 0) { | ||
| 161 | if (msg) { | ||
| 162 | for (unsigned long i = 0; i < msg->msg_iovlen; ++i) { | ||
| 163 | POST_WRITE(msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); | ||
| 164 | } | ||
| 165 | POST_WRITE(msg->msg_control, msg->msg_controllen); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | PRE_SYSCALL(recvmmsg)(long fd, sanitizer_kernel_mmsghdr *msg, long vlen, | ||
| 171 | long flags, void *timeout) { | ||
| 172 | PRE_READ(msg, vlen * sizeof(*msg)); | ||
| 173 | } | ||
| 174 | |||
| 175 | POST_SYSCALL(recvmmsg)(long res, long fd, sanitizer_kernel_mmsghdr *msg, | ||
| 176 | long vlen, long flags, void *timeout) { | ||
| 177 | if (res >= 0) { | ||
| 178 | if (msg) { | ||
| 179 | for (unsigned long i = 0; i < msg->msg_hdr.msg_iovlen; ++i) { | ||
| 180 | POST_WRITE(msg->msg_hdr.msg_iov[i].iov_base, | ||
| 181 | msg->msg_hdr.msg_iov[i].iov_len); | ||
| 182 | } | ||
| 183 | POST_WRITE(msg->msg_hdr.msg_control, msg->msg_hdr.msg_controllen); | ||
| 184 | POST_WRITE(&msg->msg_len, sizeof(msg->msg_len)); | ||
| 185 | } | ||
| 186 | if (timeout) POST_WRITE(timeout, struct_timespec_sz); | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | PRE_SYSCALL(read)(long fd, void *buf, uptr count) { | ||
| 191 | if (buf) { | ||
| 192 | PRE_WRITE(buf, count); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | POST_SYSCALL(read)(long res, long fd, void *buf, uptr count) { | ||
| 197 | if (res > 0 && buf) { | ||
| 198 | POST_WRITE(buf, res); | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | PRE_SYSCALL(time)(void *tloc) {} | ||
| 203 | |||
| 204 | POST_SYSCALL(time)(long res, void *tloc) { | ||
| 205 | if (res >= 0) { | ||
| 206 | if (tloc) POST_WRITE(tloc, sizeof(long)); | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | PRE_SYSCALL(stime)(void *tptr) {} | ||
| 211 | |||
| 212 | POST_SYSCALL(stime)(long res, void *tptr) { | ||
| 213 | if (res >= 0) { | ||
| 214 | if (tptr) POST_WRITE(tptr, sizeof(long)); | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | PRE_SYSCALL(gettimeofday)(void *tv, void *tz) {} | ||
| 219 | |||
| 220 | POST_SYSCALL(gettimeofday)(long res, void *tv, void *tz) { | ||
| 221 | if (res >= 0) { | ||
| 222 | if (tv) POST_WRITE(tv, timeval_sz); | ||
| 223 | if (tz) POST_WRITE(tz, struct_timezone_sz); | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | PRE_SYSCALL(settimeofday)(void *tv, void *tz) {} | ||
| 228 | |||
| 229 | POST_SYSCALL(settimeofday)(long res, void *tv, void *tz) { | ||
| 230 | if (res >= 0) { | ||
| 231 | if (tv) POST_WRITE(tv, timeval_sz); | ||
| 232 | if (tz) POST_WRITE(tz, struct_timezone_sz); | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | #if !SANITIZER_ANDROID | ||
| 237 | PRE_SYSCALL(adjtimex)(void *txc_p) {} | ||
| 238 | |||
| 239 | POST_SYSCALL(adjtimex)(long res, void *txc_p) { | ||
| 240 | if (res >= 0) { | ||
| 241 | if (txc_p) POST_WRITE(txc_p, struct_timex_sz); | ||
| 242 | } | ||
| 243 | } | ||
| 244 | #endif | ||
| 245 | |||
| 246 | PRE_SYSCALL(times)(void *tbuf) {} | ||
| 247 | |||
| 248 | POST_SYSCALL(times)(long res, void *tbuf) { | ||
| 249 | if (res >= 0) { | ||
| 250 | if (tbuf) POST_WRITE(tbuf, struct_tms_sz); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | PRE_SYSCALL(gettid)() {} | ||
| 255 | |||
| 256 | POST_SYSCALL(gettid)(long res) {} | ||
| 257 | |||
| 258 | PRE_SYSCALL(nanosleep)(void *rqtp, void *rmtp) {} | ||
| 259 | |||
| 260 | POST_SYSCALL(nanosleep)(long res, void *rqtp, void *rmtp) { | ||
| 261 | if (res >= 0) { | ||
| 262 | if (rqtp) POST_WRITE(rqtp, struct_timespec_sz); | ||
| 263 | if (rmtp) POST_WRITE(rmtp, struct_timespec_sz); | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | PRE_SYSCALL(alarm)(long seconds) {} | ||
| 268 | |||
| 269 | POST_SYSCALL(alarm)(long res, long seconds) {} | ||
| 270 | |||
| 271 | PRE_SYSCALL(getpid)() {} | ||
| 272 | |||
| 273 | POST_SYSCALL(getpid)(long res) {} | ||
| 274 | |||
| 275 | PRE_SYSCALL(getppid)() {} | ||
| 276 | |||
| 277 | POST_SYSCALL(getppid)(long res) {} | ||
| 278 | |||
| 279 | PRE_SYSCALL(getuid)() {} | ||
| 280 | |||
| 281 | POST_SYSCALL(getuid)(long res) {} | ||
| 282 | |||
| 283 | PRE_SYSCALL(geteuid)() {} | ||
| 284 | |||
| 285 | POST_SYSCALL(geteuid)(long res) {} | ||
| 286 | |||
| 287 | PRE_SYSCALL(getgid)() {} | ||
| 288 | |||
| 289 | POST_SYSCALL(getgid)(long res) {} | ||
| 290 | |||
| 291 | PRE_SYSCALL(getegid)() {} | ||
| 292 | |||
| 293 | POST_SYSCALL(getegid)(long res) {} | ||
| 294 | |||
| 295 | PRE_SYSCALL(getresuid)(void *ruid, void *euid, void *suid) {} | ||
| 296 | |||
| 297 | POST_SYSCALL(getresuid)(long res, void *ruid, void *euid, void *suid) { | ||
| 298 | if (res >= 0) { | ||
| 299 | if (ruid) POST_WRITE(ruid, sizeof(unsigned)); | ||
| 300 | if (euid) POST_WRITE(euid, sizeof(unsigned)); | ||
| 301 | if (suid) POST_WRITE(suid, sizeof(unsigned)); | ||
| 302 | } | ||
| 303 | } | ||
| 304 | |||
| 305 | PRE_SYSCALL(getresgid)(void *rgid, void *egid, void *sgid) {} | ||
| 306 | |||
| 307 | POST_SYSCALL(getresgid)(long res, void *rgid, void *egid, void *sgid) { | ||
| 308 | if (res >= 0) { | ||
| 309 | if (rgid) POST_WRITE(rgid, sizeof(unsigned)); | ||
| 310 | if (egid) POST_WRITE(egid, sizeof(unsigned)); | ||
| 311 | if (sgid) POST_WRITE(sgid, sizeof(unsigned)); | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 315 | PRE_SYSCALL(getpgid)(long pid) {} | ||
| 316 | |||
| 317 | POST_SYSCALL(getpgid)(long res, long pid) {} | ||
| 318 | |||
| 319 | PRE_SYSCALL(getpgrp)() {} | ||
| 320 | |||
| 321 | POST_SYSCALL(getpgrp)(long res) {} | ||
| 322 | |||
| 323 | PRE_SYSCALL(getsid)(long pid) {} | ||
| 324 | |||
| 325 | POST_SYSCALL(getsid)(long res, long pid) {} | ||
| 326 | |||
| 327 | PRE_SYSCALL(getgroups)(long gidsetsize, void *grouplist) {} | ||
| 328 | |||
| 329 | POST_SYSCALL(getgroups)(long res, long gidsetsize, | ||
| 330 | __sanitizer___kernel_gid_t *grouplist) { | ||
| 331 | if (res >= 0) { | ||
| 332 | if (grouplist) POST_WRITE(grouplist, res * sizeof(*grouplist)); | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | PRE_SYSCALL(setregid)(long rgid, long egid) {} | ||
| 337 | |||
| 338 | POST_SYSCALL(setregid)(long res, long rgid, long egid) {} | ||
| 339 | |||
| 340 | PRE_SYSCALL(setgid)(long gid) {} | ||
| 341 | |||
| 342 | POST_SYSCALL(setgid)(long res, long gid) {} | ||
| 343 | |||
| 344 | PRE_SYSCALL(setreuid)(long ruid, long euid) {} | ||
| 345 | |||
| 346 | POST_SYSCALL(setreuid)(long res, long ruid, long euid) {} | ||
| 347 | |||
| 348 | PRE_SYSCALL(setuid)(long uid) {} | ||
| 349 | |||
| 350 | POST_SYSCALL(setuid)(long res, long uid) {} | ||
| 351 | |||
| 352 | PRE_SYSCALL(setresuid)(long ruid, long euid, long suid) {} | ||
| 353 | |||
| 354 | POST_SYSCALL(setresuid)(long res, long ruid, long euid, long suid) {} | ||
| 355 | |||
| 356 | PRE_SYSCALL(setresgid)(long rgid, long egid, long sgid) {} | ||
| 357 | |||
| 358 | POST_SYSCALL(setresgid)(long res, long rgid, long egid, long sgid) {} | ||
| 359 | |||
| 360 | PRE_SYSCALL(setfsuid)(long uid) {} | ||
| 361 | |||
| 362 | POST_SYSCALL(setfsuid)(long res, long uid) {} | ||
| 363 | |||
| 364 | PRE_SYSCALL(setfsgid)(long gid) {} | ||
| 365 | |||
| 366 | POST_SYSCALL(setfsgid)(long res, long gid) {} | ||
| 367 | |||
| 368 | PRE_SYSCALL(setpgid)(long pid, long pgid) {} | ||
| 369 | |||
| 370 | POST_SYSCALL(setpgid)(long res, long pid, long pgid) {} | ||
| 371 | |||
| 372 | PRE_SYSCALL(setsid)() {} | ||
| 373 | |||
| 374 | POST_SYSCALL(setsid)(long res) {} | ||
| 375 | |||
| 376 | PRE_SYSCALL(setgroups)(long gidsetsize, __sanitizer___kernel_gid_t *grouplist) { | ||
| 377 | if (grouplist) POST_WRITE(grouplist, gidsetsize * sizeof(*grouplist)); | ||
| 378 | } | ||
| 379 | |||
| 380 | POST_SYSCALL(setgroups)(long res, long gidsetsize, | ||
| 381 | __sanitizer___kernel_gid_t *grouplist) {} | ||
| 382 | |||
| 383 | PRE_SYSCALL(acct)(const void *name) { | ||
| 384 | if (name) | ||
| 385 | PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 386 | } | ||
| 387 | |||
| 388 | POST_SYSCALL(acct)(long res, const void *name) {} | ||
| 389 | |||
| 390 | PRE_SYSCALL(capget)(void *header, void *dataptr) { | ||
| 391 | if (header) PRE_READ(header, __user_cap_header_struct_sz); | ||
| 392 | } | ||
| 393 | |||
| 394 | POST_SYSCALL(capget)(long res, void *header, void *dataptr) { | ||
| 395 | if (res >= 0) | ||
| 396 | if (dataptr) POST_WRITE(dataptr, __user_cap_data_struct_sz); | ||
| 397 | } | ||
| 398 | |||
| 399 | PRE_SYSCALL(capset)(void *header, const void *data) { | ||
| 400 | if (header) PRE_READ(header, __user_cap_header_struct_sz); | ||
| 401 | if (data) PRE_READ(data, __user_cap_data_struct_sz); | ||
| 402 | } | ||
| 403 | |||
| 404 | POST_SYSCALL(capset)(long res, void *header, const void *data) {} | ||
| 405 | |||
| 406 | PRE_SYSCALL(personality)(long personality) {} | ||
| 407 | |||
| 408 | POST_SYSCALL(personality)(long res, long personality) {} | ||
| 409 | |||
| 410 | PRE_SYSCALL(sigpending)(void *set) {} | ||
| 411 | |||
| 412 | POST_SYSCALL(sigpending)(long res, void *set) { | ||
| 413 | if (res >= 0) { | ||
| 414 | if (set) POST_WRITE(set, old_sigset_t_sz); | ||
| 415 | } | ||
| 416 | } | ||
| 417 | |||
| 418 | PRE_SYSCALL(sigprocmask)(long how, void *set, void *oset) {} | ||
| 419 | |||
| 420 | POST_SYSCALL(sigprocmask)(long res, long how, void *set, void *oset) { | ||
| 421 | if (res >= 0) { | ||
| 422 | if (set) POST_WRITE(set, old_sigset_t_sz); | ||
| 423 | if (oset) POST_WRITE(oset, old_sigset_t_sz); | ||
| 424 | } | ||
| 425 | } | ||
| 426 | |||
| 427 | PRE_SYSCALL(getitimer)(long which, void *value) {} | ||
| 428 | |||
| 429 | POST_SYSCALL(getitimer)(long res, long which, void *value) { | ||
| 430 | if (res >= 0) { | ||
| 431 | if (value) POST_WRITE(value, struct_itimerval_sz); | ||
| 432 | } | ||
| 433 | } | ||
| 434 | |||
| 435 | PRE_SYSCALL(setitimer)(long which, void *value, void *ovalue) {} | ||
| 436 | |||
| 437 | POST_SYSCALL(setitimer)(long res, long which, void *value, void *ovalue) { | ||
| 438 | if (res >= 0) { | ||
| 439 | if (value) POST_WRITE(value, struct_itimerval_sz); | ||
| 440 | if (ovalue) POST_WRITE(ovalue, struct_itimerval_sz); | ||
| 441 | } | ||
| 442 | } | ||
| 443 | |||
| 444 | PRE_SYSCALL(timer_create)(long which_clock, void *timer_event_spec, | ||
| 445 | void *created_timer_id) {} | ||
| 446 | |||
| 447 | POST_SYSCALL(timer_create)(long res, long which_clock, void *timer_event_spec, | ||
| 448 | void *created_timer_id) { | ||
| 449 | if (res >= 0) { | ||
| 450 | if (timer_event_spec) POST_WRITE(timer_event_spec, struct_sigevent_sz); | ||
| 451 | if (created_timer_id) POST_WRITE(created_timer_id, sizeof(long)); | ||
| 452 | } | ||
| 453 | } | ||
| 454 | |||
| 455 | PRE_SYSCALL(timer_gettime)(long timer_id, void *setting) {} | ||
| 456 | |||
| 457 | POST_SYSCALL(timer_gettime)(long res, long timer_id, void *setting) { | ||
| 458 | if (res >= 0) { | ||
| 459 | if (setting) POST_WRITE(setting, struct_itimerspec_sz); | ||
| 460 | } | ||
| 461 | } | ||
| 462 | |||
| 463 | PRE_SYSCALL(timer_getoverrun)(long timer_id) {} | ||
| 464 | |||
| 465 | POST_SYSCALL(timer_getoverrun)(long res, long timer_id) {} | ||
| 466 | |||
| 467 | PRE_SYSCALL(timer_settime)(long timer_id, long flags, const void *new_setting, | ||
| 468 | void *old_setting) { | ||
| 469 | if (new_setting) PRE_READ(new_setting, struct_itimerspec_sz); | ||
| 470 | } | ||
| 471 | |||
| 472 | POST_SYSCALL(timer_settime)(long res, long timer_id, long flags, | ||
| 473 | const void *new_setting, void *old_setting) { | ||
| 474 | if (res >= 0) { | ||
| 475 | if (old_setting) POST_WRITE(old_setting, struct_itimerspec_sz); | ||
| 476 | } | ||
| 477 | } | ||
| 478 | |||
| 479 | PRE_SYSCALL(timer_delete)(long timer_id) {} | ||
| 480 | |||
| 481 | POST_SYSCALL(timer_delete)(long res, long timer_id) {} | ||
| 482 | |||
| 483 | PRE_SYSCALL(clock_settime)(long which_clock, const void *tp) { | ||
| 484 | if (tp) PRE_READ(tp, struct_timespec_sz); | ||
| 485 | } | ||
| 486 | |||
| 487 | POST_SYSCALL(clock_settime)(long res, long which_clock, const void *tp) {} | ||
| 488 | |||
| 489 | PRE_SYSCALL(clock_gettime)(long which_clock, void *tp) {} | ||
| 490 | |||
| 491 | POST_SYSCALL(clock_gettime)(long res, long which_clock, void *tp) { | ||
| 492 | if (res >= 0) { | ||
| 493 | if (tp) POST_WRITE(tp, struct_timespec_sz); | ||
| 494 | } | ||
| 495 | } | ||
| 496 | |||
| 497 | #if !SANITIZER_ANDROID | ||
| 498 | PRE_SYSCALL(clock_adjtime)(long which_clock, void *tx) {} | ||
| 499 | |||
| 500 | POST_SYSCALL(clock_adjtime)(long res, long which_clock, void *tx) { | ||
| 501 | if (res >= 0) { | ||
| 502 | if (tx) POST_WRITE(tx, struct_timex_sz); | ||
| 503 | } | ||
| 504 | } | ||
| 505 | #endif | ||
| 506 | |||
| 507 | PRE_SYSCALL(clock_getres)(long which_clock, void *tp) {} | ||
| 508 | |||
| 509 | POST_SYSCALL(clock_getres)(long res, long which_clock, void *tp) { | ||
| 510 | if (res >= 0) { | ||
| 511 | if (tp) POST_WRITE(tp, struct_timespec_sz); | ||
| 512 | } | ||
| 513 | } | ||
| 514 | |||
| 515 | PRE_SYSCALL(clock_nanosleep)(long which_clock, long flags, const void *rqtp, | ||
| 516 | void *rmtp) { | ||
| 517 | if (rqtp) PRE_READ(rqtp, struct_timespec_sz); | ||
| 518 | } | ||
| 519 | |||
| 520 | POST_SYSCALL(clock_nanosleep)(long res, long which_clock, long flags, | ||
| 521 | const void *rqtp, void *rmtp) { | ||
| 522 | if (res >= 0) { | ||
| 523 | if (rmtp) POST_WRITE(rmtp, struct_timespec_sz); | ||
| 524 | } | ||
| 525 | } | ||
| 526 | |||
| 527 | PRE_SYSCALL(nice)(long increment) {} | ||
| 528 | |||
| 529 | POST_SYSCALL(nice)(long res, long increment) {} | ||
| 530 | |||
| 531 | PRE_SYSCALL(sched_setscheduler)(long pid, long policy, void *param) {} | ||
| 532 | |||
| 533 | POST_SYSCALL(sched_setscheduler)(long res, long pid, long policy, void *param) { | ||
| 534 | if (res >= 0) { | ||
| 535 | if (param) POST_WRITE(param, struct_sched_param_sz); | ||
| 536 | } | ||
| 537 | } | ||
| 538 | |||
| 539 | PRE_SYSCALL(sched_setparam)(long pid, void *param) { | ||
| 540 | if (param) PRE_READ(param, struct_sched_param_sz); | ||
| 541 | } | ||
| 542 | |||
| 543 | POST_SYSCALL(sched_setparam)(long res, long pid, void *param) {} | ||
| 544 | |||
| 545 | PRE_SYSCALL(sched_getscheduler)(long pid) {} | ||
| 546 | |||
| 547 | POST_SYSCALL(sched_getscheduler)(long res, long pid) {} | ||
| 548 | |||
| 549 | PRE_SYSCALL(sched_getparam)(long pid, void *param) {} | ||
| 550 | |||
| 551 | POST_SYSCALL(sched_getparam)(long res, long pid, void *param) { | ||
| 552 | if (res >= 0) { | ||
| 553 | if (param) POST_WRITE(param, struct_sched_param_sz); | ||
| 554 | } | ||
| 555 | } | ||
| 556 | |||
| 557 | PRE_SYSCALL(sched_setaffinity)(long pid, long len, void *user_mask_ptr) { | ||
| 558 | if (user_mask_ptr) PRE_READ(user_mask_ptr, len); | ||
| 559 | } | ||
| 560 | |||
| 561 | POST_SYSCALL(sched_setaffinity)(long res, long pid, long len, | ||
| 562 | void *user_mask_ptr) {} | ||
| 563 | |||
| 564 | PRE_SYSCALL(sched_getaffinity)(long pid, long len, void *user_mask_ptr) {} | ||
| 565 | |||
| 566 | POST_SYSCALL(sched_getaffinity)(long res, long pid, long len, | ||
| 567 | void *user_mask_ptr) { | ||
| 568 | if (res >= 0) { | ||
| 569 | if (user_mask_ptr) POST_WRITE(user_mask_ptr, len); | ||
| 570 | } | ||
| 571 | } | ||
| 572 | |||
| 573 | PRE_SYSCALL(sched_yield)() {} | ||
| 574 | |||
| 575 | POST_SYSCALL(sched_yield)(long res) {} | ||
| 576 | |||
| 577 | PRE_SYSCALL(sched_get_priority_max)(long policy) {} | ||
| 578 | |||
| 579 | POST_SYSCALL(sched_get_priority_max)(long res, long policy) {} | ||
| 580 | |||
| 581 | PRE_SYSCALL(sched_get_priority_min)(long policy) {} | ||
| 582 | |||
| 583 | POST_SYSCALL(sched_get_priority_min)(long res, long policy) {} | ||
| 584 | |||
| 585 | PRE_SYSCALL(sched_rr_get_interval)(long pid, void *interval) {} | ||
| 586 | |||
| 587 | POST_SYSCALL(sched_rr_get_interval)(long res, long pid, void *interval) { | ||
| 588 | if (res >= 0) { | ||
| 589 | if (interval) POST_WRITE(interval, struct_timespec_sz); | ||
| 590 | } | ||
| 591 | } | ||
| 592 | |||
| 593 | PRE_SYSCALL(setpriority)(long which, long who, long niceval) {} | ||
| 594 | |||
| 595 | POST_SYSCALL(setpriority)(long res, long which, long who, long niceval) {} | ||
| 596 | |||
| 597 | PRE_SYSCALL(getpriority)(long which, long who) {} | ||
| 598 | |||
| 599 | POST_SYSCALL(getpriority)(long res, long which, long who) {} | ||
| 600 | |||
| 601 | PRE_SYSCALL(shutdown)(long arg0, long arg1) {} | ||
| 602 | |||
| 603 | POST_SYSCALL(shutdown)(long res, long arg0, long arg1) {} | ||
| 604 | |||
| 605 | PRE_SYSCALL(reboot)(long magic1, long magic2, long cmd, void *arg) {} | ||
| 606 | |||
| 607 | POST_SYSCALL(reboot)(long res, long magic1, long magic2, long cmd, void *arg) {} | ||
| 608 | |||
| 609 | PRE_SYSCALL(restart_syscall)() {} | ||
| 610 | |||
| 611 | POST_SYSCALL(restart_syscall)(long res) {} | ||
| 612 | |||
| 613 | PRE_SYSCALL(kexec_load)(long entry, long nr_segments, void *segments, | ||
| 614 | long flags) {} | ||
| 615 | |||
| 616 | POST_SYSCALL(kexec_load)(long res, long entry, long nr_segments, void *segments, | ||
| 617 | long flags) { | ||
| 618 | if (res >= 0) { | ||
| 619 | if (segments) POST_WRITE(segments, struct_kexec_segment_sz); | ||
| 620 | } | ||
| 621 | } | ||
| 622 | |||
| 623 | PRE_SYSCALL(exit)(long error_code) {} | ||
| 624 | |||
| 625 | POST_SYSCALL(exit)(long res, long error_code) {} | ||
| 626 | |||
| 627 | PRE_SYSCALL(exit_group)(long error_code) {} | ||
| 628 | |||
| 629 | POST_SYSCALL(exit_group)(long res, long error_code) {} | ||
| 630 | |||
| 631 | PRE_SYSCALL(wait4)(long pid, void *stat_addr, long options, void *ru) {} | ||
| 632 | |||
| 633 | POST_SYSCALL(wait4)(long res, long pid, void *stat_addr, long options, | ||
| 634 | void *ru) { | ||
| 635 | if (res >= 0) { | ||
| 636 | if (stat_addr) POST_WRITE(stat_addr, sizeof(int)); | ||
| 637 | if (ru) POST_WRITE(ru, struct_rusage_sz); | ||
| 638 | } | ||
| 639 | } | ||
| 640 | |||
| 641 | PRE_SYSCALL(waitid)(long which, long pid, void *infop, long options, void *ru) { | ||
| 642 | } | ||
| 643 | |||
| 644 | POST_SYSCALL(waitid)(long res, long which, long pid, void *infop, long options, | ||
| 645 | void *ru) { | ||
| 646 | if (res >= 0) { | ||
| 647 | if (infop) POST_WRITE(infop, siginfo_t_sz); | ||
| 648 | if (ru) POST_WRITE(ru, struct_rusage_sz); | ||
| 649 | } | ||
| 650 | } | ||
| 651 | |||
| 652 | PRE_SYSCALL(waitpid)(long pid, void *stat_addr, long options) {} | ||
| 653 | |||
| 654 | POST_SYSCALL(waitpid)(long res, long pid, void *stat_addr, long options) { | ||
| 655 | if (res >= 0) { | ||
| 656 | if (stat_addr) POST_WRITE(stat_addr, sizeof(int)); | ||
| 657 | } | ||
| 658 | } | ||
| 659 | |||
| 660 | PRE_SYSCALL(set_tid_address)(void *tidptr) {} | ||
| 661 | |||
| 662 | POST_SYSCALL(set_tid_address)(long res, void *tidptr) { | ||
| 663 | if (res >= 0) { | ||
| 664 | if (tidptr) POST_WRITE(tidptr, sizeof(int)); | ||
| 665 | } | ||
| 666 | } | ||
| 667 | |||
| 668 | PRE_SYSCALL(init_module)(void *umod, long len, const void *uargs) { | ||
| 669 | if (uargs) | ||
| 670 | PRE_READ(uargs, __sanitizer::internal_strlen((const char *)uargs) + 1); | ||
| 671 | } | ||
| 672 | |||
| 673 | POST_SYSCALL(init_module)(long res, void *umod, long len, const void *uargs) {} | ||
| 674 | |||
| 675 | PRE_SYSCALL(delete_module)(const void *name_user, long flags) { | ||
| 676 | if (name_user) | ||
| 677 | PRE_READ(name_user, | ||
| 678 | __sanitizer::internal_strlen((const char *)name_user) + 1); | ||
| 679 | } | ||
| 680 | |||
| 681 | POST_SYSCALL(delete_module)(long res, const void *name_user, long flags) {} | ||
| 682 | |||
| 683 | PRE_SYSCALL(rt_sigprocmask)(long how, void *set, void *oset, long sigsetsize) {} | ||
| 684 | |||
| 685 | POST_SYSCALL(rt_sigprocmask)(long res, long how, kernel_sigset_t *set, | ||
| 686 | kernel_sigset_t *oset, long sigsetsize) { | ||
| 687 | if (res >= 0) { | ||
| 688 | if (set) POST_WRITE(set, sigsetsize); | ||
| 689 | if (oset) POST_WRITE(oset, sigsetsize); | ||
| 690 | } | ||
| 691 | } | ||
| 692 | |||
| 693 | PRE_SYSCALL(rt_sigpending)(void *set, long sigsetsize) {} | ||
| 694 | |||
| 695 | POST_SYSCALL(rt_sigpending)(long res, kernel_sigset_t *set, long sigsetsize) { | ||
| 696 | if (res >= 0) { | ||
| 697 | if (set) POST_WRITE(set, sigsetsize); | ||
| 698 | } | ||
| 699 | } | ||
| 700 | |||
| 701 | PRE_SYSCALL(rt_sigtimedwait)(const kernel_sigset_t *uthese, void *uinfo, | ||
| 702 | const void *uts, long sigsetsize) { | ||
| 703 | if (uthese) PRE_READ(uthese, sigsetsize); | ||
| 704 | if (uts) PRE_READ(uts, struct_timespec_sz); | ||
| 705 | } | ||
| 706 | |||
| 707 | POST_SYSCALL(rt_sigtimedwait)(long res, const void *uthese, void *uinfo, | ||
| 708 | const void *uts, long sigsetsize) { | ||
| 709 | if (res >= 0) { | ||
| 710 | if (uinfo) POST_WRITE(uinfo, siginfo_t_sz); | ||
| 711 | } | ||
| 712 | } | ||
| 713 | |||
| 714 | PRE_SYSCALL(rt_tgsigqueueinfo)(long tgid, long pid, long sig, void *uinfo) {} | ||
| 715 | |||
| 716 | POST_SYSCALL(rt_tgsigqueueinfo)(long res, long tgid, long pid, long sig, | ||
| 717 | void *uinfo) { | ||
| 718 | if (res >= 0) { | ||
| 719 | if (uinfo) POST_WRITE(uinfo, siginfo_t_sz); | ||
| 720 | } | ||
| 721 | } | ||
| 722 | |||
| 723 | PRE_SYSCALL(kill)(long pid, long sig) {} | ||
| 724 | |||
| 725 | POST_SYSCALL(kill)(long res, long pid, long sig) {} | ||
| 726 | |||
| 727 | PRE_SYSCALL(tgkill)(long tgid, long pid, long sig) {} | ||
| 728 | |||
| 729 | POST_SYSCALL(tgkill)(long res, long tgid, long pid, long sig) {} | ||
| 730 | |||
| 731 | PRE_SYSCALL(tkill)(long pid, long sig) {} | ||
| 732 | |||
| 733 | POST_SYSCALL(tkill)(long res, long pid, long sig) {} | ||
| 734 | |||
| 735 | PRE_SYSCALL(rt_sigqueueinfo)(long pid, long sig, void *uinfo) {} | ||
| 736 | |||
| 737 | POST_SYSCALL(rt_sigqueueinfo)(long res, long pid, long sig, void *uinfo) { | ||
| 738 | if (res >= 0) { | ||
| 739 | if (uinfo) POST_WRITE(uinfo, siginfo_t_sz); | ||
| 740 | } | ||
| 741 | } | ||
| 742 | |||
| 743 | PRE_SYSCALL(sgetmask)() {} | ||
| 744 | |||
| 745 | POST_SYSCALL(sgetmask)(long res) {} | ||
| 746 | |||
| 747 | PRE_SYSCALL(ssetmask)(long newmask) {} | ||
| 748 | |||
| 749 | POST_SYSCALL(ssetmask)(long res, long newmask) {} | ||
| 750 | |||
| 751 | PRE_SYSCALL(signal)(long sig, long handler) {} | ||
| 752 | |||
| 753 | POST_SYSCALL(signal)(long res, long sig, long handler) {} | ||
| 754 | |||
| 755 | PRE_SYSCALL(pause)() {} | ||
| 756 | |||
| 757 | POST_SYSCALL(pause)(long res) {} | ||
| 758 | |||
| 759 | PRE_SYSCALL(sync)() {} | ||
| 760 | |||
| 761 | POST_SYSCALL(sync)(long res) {} | ||
| 762 | |||
| 763 | PRE_SYSCALL(fsync)(long fd) {} | ||
| 764 | |||
| 765 | POST_SYSCALL(fsync)(long res, long fd) {} | ||
| 766 | |||
| 767 | PRE_SYSCALL(fdatasync)(long fd) {} | ||
| 768 | |||
| 769 | POST_SYSCALL(fdatasync)(long res, long fd) {} | ||
| 770 | |||
| 771 | PRE_SYSCALL(bdflush)(long func, long data) {} | ||
| 772 | |||
| 773 | POST_SYSCALL(bdflush)(long res, long func, long data) {} | ||
| 774 | |||
| 775 | PRE_SYSCALL(mount)(void *dev_name, void *dir_name, void *type, long flags, | ||
| 776 | void *data) {} | ||
| 777 | |||
| 778 | POST_SYSCALL(mount)(long res, void *dev_name, void *dir_name, void *type, | ||
| 779 | long flags, void *data) { | ||
| 780 | if (res >= 0) { | ||
| 781 | if (dev_name) | ||
| 782 | POST_WRITE(dev_name, | ||
| 783 | __sanitizer::internal_strlen((const char *)dev_name) + 1); | ||
| 784 | if (dir_name) | ||
| 785 | POST_WRITE(dir_name, | ||
| 786 | __sanitizer::internal_strlen((const char *)dir_name) + 1); | ||
| 787 | if (type) | ||
| 788 | POST_WRITE(type, __sanitizer::internal_strlen((const char *)type) + 1); | ||
| 789 | } | ||
| 790 | } | ||
| 791 | |||
| 792 | PRE_SYSCALL(umount)(void *name, long flags) {} | ||
| 793 | |||
| 794 | POST_SYSCALL(umount)(long res, void *name, long flags) { | ||
| 795 | if (res >= 0) { | ||
| 796 | if (name) | ||
| 797 | POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 798 | } | ||
| 799 | } | ||
| 800 | |||
| 801 | PRE_SYSCALL(oldumount)(void *name) {} | ||
| 802 | |||
| 803 | POST_SYSCALL(oldumount)(long res, void *name) { | ||
| 804 | if (res >= 0) { | ||
| 805 | if (name) | ||
| 806 | POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 807 | } | ||
| 808 | } | ||
| 809 | |||
| 810 | PRE_SYSCALL(truncate)(const void *path, long length) { | ||
| 811 | if (path) | ||
| 812 | PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); | ||
| 813 | } | ||
| 814 | |||
| 815 | POST_SYSCALL(truncate)(long res, const void *path, long length) {} | ||
| 816 | |||
| 817 | PRE_SYSCALL(ftruncate)(long fd, long length) {} | ||
| 818 | |||
| 819 | POST_SYSCALL(ftruncate)(long res, long fd, long length) {} | ||
| 820 | |||
| 821 | PRE_SYSCALL(stat)(const void *filename, void *statbuf) { | ||
| 822 | if (filename) | ||
| 823 | PRE_READ(filename, | ||
| 824 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 825 | } | ||
| 826 | |||
| 827 | POST_SYSCALL(stat)(long res, const void *filename, void *statbuf) { | ||
| 828 | if (res >= 0) { | ||
| 829 | if (statbuf) POST_WRITE(statbuf, struct___old_kernel_stat_sz); | ||
| 830 | } | ||
| 831 | } | ||
| 832 | |||
| 833 | #if !SANITIZER_ANDROID | ||
| 834 | PRE_SYSCALL(statfs)(const void *path, void *buf) { | ||
| 835 | if (path) | ||
| 836 | PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); | ||
| 837 | } | ||
| 838 | |||
| 839 | POST_SYSCALL(statfs)(long res, const void *path, void *buf) { | ||
| 840 | if (res >= 0) { | ||
| 841 | if (buf) POST_WRITE(buf, struct_statfs_sz); | ||
| 842 | } | ||
| 843 | } | ||
| 844 | |||
| 845 | PRE_SYSCALL(statfs64)(const void *path, long sz, void *buf) { | ||
| 846 | if (path) | ||
| 847 | PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); | ||
| 848 | } | ||
| 849 | |||
| 850 | POST_SYSCALL(statfs64)(long res, const void *path, long sz, void *buf) { | ||
| 851 | if (res >= 0) { | ||
| 852 | if (buf) POST_WRITE(buf, struct_statfs64_sz); | ||
| 853 | } | ||
| 854 | } | ||
| 855 | |||
| 856 | PRE_SYSCALL(fstatfs)(long fd, void *buf) {} | ||
| 857 | |||
| 858 | POST_SYSCALL(fstatfs)(long res, long fd, void *buf) { | ||
| 859 | if (res >= 0) { | ||
| 860 | if (buf) POST_WRITE(buf, struct_statfs_sz); | ||
| 861 | } | ||
| 862 | } | ||
| 863 | |||
| 864 | PRE_SYSCALL(fstatfs64)(long fd, long sz, void *buf) {} | ||
| 865 | |||
| 866 | POST_SYSCALL(fstatfs64)(long res, long fd, long sz, void *buf) { | ||
| 867 | if (res >= 0) { | ||
| 868 | if (buf) POST_WRITE(buf, struct_statfs64_sz); | ||
| 869 | } | ||
| 870 | } | ||
| 871 | #endif // !SANITIZER_ANDROID | ||
| 872 | |||
| 873 | PRE_SYSCALL(lstat)(const void *filename, void *statbuf) { | ||
| 874 | if (filename) | ||
| 875 | PRE_READ(filename, | ||
| 876 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 877 | } | ||
| 878 | |||
| 879 | POST_SYSCALL(lstat)(long res, const void *filename, void *statbuf) { | ||
| 880 | if (res >= 0) { | ||
| 881 | if (statbuf) POST_WRITE(statbuf, struct___old_kernel_stat_sz); | ||
| 882 | } | ||
| 883 | } | ||
| 884 | |||
| 885 | PRE_SYSCALL(fstat)(long fd, void *statbuf) {} | ||
| 886 | |||
| 887 | POST_SYSCALL(fstat)(long res, long fd, void *statbuf) { | ||
| 888 | if (res >= 0) { | ||
| 889 | if (statbuf) POST_WRITE(statbuf, struct___old_kernel_stat_sz); | ||
| 890 | } | ||
| 891 | } | ||
| 892 | |||
| 893 | PRE_SYSCALL(newstat)(const void *filename, void *statbuf) { | ||
| 894 | if (filename) | ||
| 895 | PRE_READ(filename, | ||
| 896 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 897 | } | ||
| 898 | |||
| 899 | POST_SYSCALL(newstat)(long res, const void *filename, void *statbuf) { | ||
| 900 | if (res >= 0) { | ||
| 901 | if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz); | ||
| 902 | } | ||
| 903 | } | ||
| 904 | |||
| 905 | PRE_SYSCALL(newlstat)(const void *filename, void *statbuf) { | ||
| 906 | if (filename) | ||
| 907 | PRE_READ(filename, | ||
| 908 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 909 | } | ||
| 910 | |||
| 911 | POST_SYSCALL(newlstat)(long res, const void *filename, void *statbuf) { | ||
| 912 | if (res >= 0) { | ||
| 913 | if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz); | ||
| 914 | } | ||
| 915 | } | ||
| 916 | |||
| 917 | PRE_SYSCALL(newfstat)(long fd, void *statbuf) {} | ||
| 918 | |||
| 919 | POST_SYSCALL(newfstat)(long res, long fd, void *statbuf) { | ||
| 920 | if (res >= 0) { | ||
| 921 | if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz); | ||
| 922 | } | ||
| 923 | } | ||
| 924 | |||
| 925 | #if !SANITIZER_ANDROID | ||
| 926 | PRE_SYSCALL(ustat)(long dev, void *ubuf) {} | ||
| 927 | |||
| 928 | POST_SYSCALL(ustat)(long res, long dev, void *ubuf) { | ||
| 929 | if (res >= 0) { | ||
| 930 | if (ubuf) POST_WRITE(ubuf, struct_ustat_sz); | ||
| 931 | } | ||
| 932 | } | ||
| 933 | #endif // !SANITIZER_ANDROID | ||
| 934 | |||
| 935 | PRE_SYSCALL(stat64)(const void *filename, void *statbuf) { | ||
| 936 | if (filename) | ||
| 937 | PRE_READ(filename, | ||
| 938 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 939 | } | ||
| 940 | |||
| 941 | POST_SYSCALL(stat64)(long res, const void *filename, void *statbuf) { | ||
| 942 | if (res >= 0) { | ||
| 943 | if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz); | ||
| 944 | } | ||
| 945 | } | ||
| 946 | |||
| 947 | PRE_SYSCALL(fstat64)(long fd, void *statbuf) {} | ||
| 948 | |||
| 949 | POST_SYSCALL(fstat64)(long res, long fd, void *statbuf) { | ||
| 950 | if (res >= 0) { | ||
| 951 | if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz); | ||
| 952 | } | ||
| 953 | } | ||
| 954 | |||
| 955 | PRE_SYSCALL(lstat64)(const void *filename, void *statbuf) { | ||
| 956 | if (filename) | ||
| 957 | PRE_READ(filename, | ||
| 958 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 959 | } | ||
| 960 | |||
| 961 | POST_SYSCALL(lstat64)(long res, const void *filename, void *statbuf) { | ||
| 962 | if (res >= 0) { | ||
| 963 | if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz); | ||
| 964 | } | ||
| 965 | } | ||
| 966 | |||
| 967 | PRE_SYSCALL(setxattr)(const void *path, const void *name, const void *value, | ||
| 968 | long size, long flags) { | ||
| 969 | if (path) | ||
| 970 | PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); | ||
| 971 | if (name) | ||
| 972 | PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 973 | if (value) PRE_READ(value, size); | ||
| 974 | } | ||
| 975 | |||
| 976 | POST_SYSCALL(setxattr)(long res, const void *path, const void *name, | ||
| 977 | const void *value, long size, long flags) {} | ||
| 978 | |||
| 979 | PRE_SYSCALL(lsetxattr)(const void *path, const void *name, const void *value, | ||
| 980 | long size, long flags) { | ||
| 981 | if (path) | ||
| 982 | PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); | ||
| 983 | if (name) | ||
| 984 | PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 985 | if (value) PRE_READ(value, size); | ||
| 986 | } | ||
| 987 | |||
| 988 | POST_SYSCALL(lsetxattr)(long res, const void *path, const void *name, | ||
| 989 | const void *value, long size, long flags) {} | ||
| 990 | |||
| 991 | PRE_SYSCALL(fsetxattr)(long fd, const void *name, const void *value, long size, | ||
| 992 | long flags) { | ||
| 993 | if (name) | ||
| 994 | PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 995 | if (value) PRE_READ(value, size); | ||
| 996 | } | ||
| 997 | |||
| 998 | POST_SYSCALL(fsetxattr)(long res, long fd, const void *name, const void *value, | ||
| 999 | long size, long flags) {} | ||
| 1000 | |||
| 1001 | PRE_SYSCALL(getxattr)(const void *path, const void *name, void *value, | ||
| 1002 | long size) { | ||
| 1003 | if (path) | ||
| 1004 | PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); | ||
| 1005 | if (name) | ||
| 1006 | PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | POST_SYSCALL(getxattr)(long res, const void *path, const void *name, | ||
| 1010 | void *value, long size) { | ||
| 1011 | if (size && res > 0) { | ||
| 1012 | if (value) POST_WRITE(value, res); | ||
| 1013 | } | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | PRE_SYSCALL(lgetxattr)(const void *path, const void *name, void *value, | ||
| 1017 | long size) { | ||
| 1018 | if (path) | ||
| 1019 | PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); | ||
| 1020 | if (name) | ||
| 1021 | PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | POST_SYSCALL(lgetxattr)(long res, const void *path, const void *name, | ||
| 1025 | void *value, long size) { | ||
| 1026 | if (size && res > 0) { | ||
| 1027 | if (value) POST_WRITE(value, res); | ||
| 1028 | } | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | PRE_SYSCALL(fgetxattr)(long fd, const void *name, void *value, long size) { | ||
| 1032 | if (name) | ||
| 1033 | PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | POST_SYSCALL(fgetxattr)(long res, long fd, const void *name, void *value, | ||
| 1037 | long size) { | ||
| 1038 | if (size && res > 0) { | ||
| 1039 | if (value) POST_WRITE(value, res); | ||
| 1040 | } | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | PRE_SYSCALL(listxattr)(const void *path, void *list, long size) { | ||
| 1044 | if (path) | ||
| 1045 | PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | POST_SYSCALL(listxattr)(long res, const void *path, void *list, long size) { | ||
| 1049 | if (size && res > 0) { | ||
| 1050 | if (list) POST_WRITE(list, res); | ||
| 1051 | } | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | PRE_SYSCALL(llistxattr)(const void *path, void *list, long size) { | ||
| 1055 | if (path) | ||
| 1056 | PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | POST_SYSCALL(llistxattr)(long res, const void *path, void *list, long size) { | ||
| 1060 | if (size && res > 0) { | ||
| 1061 | if (list) POST_WRITE(list, res); | ||
| 1062 | } | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | PRE_SYSCALL(flistxattr)(long fd, void *list, long size) {} | ||
| 1066 | |||
| 1067 | POST_SYSCALL(flistxattr)(long res, long fd, void *list, long size) { | ||
| 1068 | if (size && res > 0) { | ||
| 1069 | if (list) POST_WRITE(list, res); | ||
| 1070 | } | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | PRE_SYSCALL(removexattr)(const void *path, const void *name) { | ||
| 1074 | if (path) | ||
| 1075 | PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); | ||
| 1076 | if (name) | ||
| 1077 | PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | POST_SYSCALL(removexattr)(long res, const void *path, const void *name) {} | ||
| 1081 | |||
| 1082 | PRE_SYSCALL(lremovexattr)(const void *path, const void *name) { | ||
| 1083 | if (path) | ||
| 1084 | PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); | ||
| 1085 | if (name) | ||
| 1086 | PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | POST_SYSCALL(lremovexattr)(long res, const void *path, const void *name) {} | ||
| 1090 | |||
| 1091 | PRE_SYSCALL(fremovexattr)(long fd, const void *name) { | ||
| 1092 | if (name) | ||
| 1093 | PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | POST_SYSCALL(fremovexattr)(long res, long fd, const void *name) {} | ||
| 1097 | |||
| 1098 | PRE_SYSCALL(brk)(long brk) {} | ||
| 1099 | |||
| 1100 | POST_SYSCALL(brk)(long res, long brk) {} | ||
| 1101 | |||
| 1102 | PRE_SYSCALL(mprotect)(long start, long len, long prot) {} | ||
| 1103 | |||
| 1104 | POST_SYSCALL(mprotect)(long res, long start, long len, long prot) {} | ||
| 1105 | |||
| 1106 | PRE_SYSCALL(mremap)(long addr, long old_len, long new_len, long flags, | ||
| 1107 | long new_addr) {} | ||
| 1108 | |||
| 1109 | POST_SYSCALL(mremap)(long res, long addr, long old_len, long new_len, | ||
| 1110 | long flags, long new_addr) {} | ||
| 1111 | |||
| 1112 | PRE_SYSCALL(remap_file_pages)(long start, long size, long prot, long pgoff, | ||
| 1113 | long flags) {} | ||
| 1114 | |||
| 1115 | POST_SYSCALL(remap_file_pages)(long res, long start, long size, long prot, | ||
| 1116 | long pgoff, long flags) {} | ||
| 1117 | |||
| 1118 | PRE_SYSCALL(msync)(long start, long len, long flags) {} | ||
| 1119 | |||
| 1120 | POST_SYSCALL(msync)(long res, long start, long len, long flags) {} | ||
| 1121 | |||
| 1122 | PRE_SYSCALL(munmap)(long addr, long len) {} | ||
| 1123 | |||
| 1124 | POST_SYSCALL(munmap)(long res, long addr, long len) {} | ||
| 1125 | |||
| 1126 | PRE_SYSCALL(mlock)(long start, long len) {} | ||
| 1127 | |||
| 1128 | POST_SYSCALL(mlock)(long res, long start, long len) {} | ||
| 1129 | |||
| 1130 | PRE_SYSCALL(munlock)(long start, long len) {} | ||
| 1131 | |||
| 1132 | POST_SYSCALL(munlock)(long res, long start, long len) {} | ||
| 1133 | |||
| 1134 | PRE_SYSCALL(mlockall)(long flags) {} | ||
| 1135 | |||
| 1136 | POST_SYSCALL(mlockall)(long res, long flags) {} | ||
| 1137 | |||
| 1138 | PRE_SYSCALL(munlockall)() {} | ||
| 1139 | |||
| 1140 | POST_SYSCALL(munlockall)(long res) {} | ||
| 1141 | |||
| 1142 | PRE_SYSCALL(madvise)(long start, long len, long behavior) {} | ||
| 1143 | |||
| 1144 | POST_SYSCALL(madvise)(long res, long start, long len, long behavior) {} | ||
| 1145 | |||
| 1146 | PRE_SYSCALL(mincore)(long start, long len, void *vec) {} | ||
| 1147 | |||
| 1148 | POST_SYSCALL(mincore)(long res, long start, long len, void *vec) { | ||
| 1149 | if (res >= 0) { | ||
| 1150 | if (vec) { | ||
| 1151 | POST_WRITE(vec, (len + GetPageSizeCached() - 1) / GetPageSizeCached()); | ||
| 1152 | } | ||
| 1153 | } | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | PRE_SYSCALL(pivot_root)(const void *new_root, const void *put_old) { | ||
| 1157 | if (new_root) | ||
| 1158 | PRE_READ(new_root, | ||
| 1159 | __sanitizer::internal_strlen((const char *)new_root) + 1); | ||
| 1160 | if (put_old) | ||
| 1161 | PRE_READ(put_old, __sanitizer::internal_strlen((const char *)put_old) + 1); | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | POST_SYSCALL(pivot_root)(long res, const void *new_root, const void *put_old) {} | ||
| 1165 | |||
| 1166 | PRE_SYSCALL(chroot)(const void *filename) { | ||
| 1167 | if (filename) | ||
| 1168 | PRE_READ(filename, | ||
| 1169 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 1170 | } | ||
| 1171 | |||
| 1172 | POST_SYSCALL(chroot)(long res, const void *filename) {} | ||
| 1173 | |||
| 1174 | PRE_SYSCALL(mknod)(const void *filename, long mode, long dev) { | ||
| 1175 | if (filename) | ||
| 1176 | PRE_READ(filename, | ||
| 1177 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | POST_SYSCALL(mknod)(long res, const void *filename, long mode, long dev) {} | ||
| 1181 | |||
| 1182 | PRE_SYSCALL(link)(const void *oldname, const void *newname) { | ||
| 1183 | if (oldname) | ||
| 1184 | PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1); | ||
| 1185 | if (newname) | ||
| 1186 | PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1); | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | POST_SYSCALL(link)(long res, const void *oldname, const void *newname) {} | ||
| 1190 | |||
| 1191 | PRE_SYSCALL(symlink)(const void *old, const void *new_) { | ||
| 1192 | if (old) PRE_READ(old, __sanitizer::internal_strlen((const char *)old) + 1); | ||
| 1193 | if (new_) | ||
| 1194 | PRE_READ(new_, __sanitizer::internal_strlen((const char *)new_) + 1); | ||
| 1195 | } | ||
| 1196 | |||
| 1197 | POST_SYSCALL(symlink)(long res, const void *old, const void *new_) {} | ||
| 1198 | |||
| 1199 | PRE_SYSCALL(unlink)(const void *pathname) { | ||
| 1200 | if (pathname) | ||
| 1201 | PRE_READ(pathname, | ||
| 1202 | __sanitizer::internal_strlen((const char *)pathname) + 1); | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | POST_SYSCALL(unlink)(long res, const void *pathname) {} | ||
| 1206 | |||
| 1207 | PRE_SYSCALL(rename)(const void *oldname, const void *newname) { | ||
| 1208 | if (oldname) | ||
| 1209 | PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1); | ||
| 1210 | if (newname) | ||
| 1211 | PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1); | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | POST_SYSCALL(rename)(long res, const void *oldname, const void *newname) {} | ||
| 1215 | |||
| 1216 | PRE_SYSCALL(chmod)(const void *filename, long mode) { | ||
| 1217 | if (filename) | ||
| 1218 | PRE_READ(filename, | ||
| 1219 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | POST_SYSCALL(chmod)(long res, const void *filename, long mode) {} | ||
| 1223 | |||
| 1224 | PRE_SYSCALL(fchmod)(long fd, long mode) {} | ||
| 1225 | |||
| 1226 | POST_SYSCALL(fchmod)(long res, long fd, long mode) {} | ||
| 1227 | |||
| 1228 | PRE_SYSCALL(fcntl)(long fd, long cmd, long arg) {} | ||
| 1229 | |||
| 1230 | POST_SYSCALL(fcntl)(long res, long fd, long cmd, long arg) {} | ||
| 1231 | |||
| 1232 | PRE_SYSCALL(fcntl64)(long fd, long cmd, long arg) {} | ||
| 1233 | |||
| 1234 | POST_SYSCALL(fcntl64)(long res, long fd, long cmd, long arg) {} | ||
| 1235 | |||
| 1236 | PRE_SYSCALL(pipe)(void *fildes) {} | ||
| 1237 | |||
| 1238 | POST_SYSCALL(pipe)(long res, void *fildes) { | ||
| 1239 | if (res >= 0) | ||
| 1240 | if (fildes) POST_WRITE(fildes, sizeof(int) * 2); | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | PRE_SYSCALL(pipe2)(void *fildes, long flags) {} | ||
| 1244 | |||
| 1245 | POST_SYSCALL(pipe2)(long res, void *fildes, long flags) { | ||
| 1246 | if (res >= 0) | ||
| 1247 | if (fildes) POST_WRITE(fildes, sizeof(int) * 2); | ||
| 1248 | } | ||
| 1249 | |||
| 1250 | PRE_SYSCALL(dup)(long fildes) {} | ||
| 1251 | |||
| 1252 | POST_SYSCALL(dup)(long res, long fildes) {} | ||
| 1253 | |||
| 1254 | PRE_SYSCALL(dup2)(long oldfd, long newfd) {} | ||
| 1255 | |||
| 1256 | POST_SYSCALL(dup2)(long res, long oldfd, long newfd) {} | ||
| 1257 | |||
| 1258 | PRE_SYSCALL(dup3)(long oldfd, long newfd, long flags) {} | ||
| 1259 | |||
| 1260 | POST_SYSCALL(dup3)(long res, long oldfd, long newfd, long flags) {} | ||
| 1261 | |||
| 1262 | PRE_SYSCALL(ioperm)(long from, long num, long on) {} | ||
| 1263 | |||
| 1264 | POST_SYSCALL(ioperm)(long res, long from, long num, long on) {} | ||
| 1265 | |||
| 1266 | PRE_SYSCALL(ioctl)(long fd, long cmd, long arg) {} | ||
| 1267 | |||
| 1268 | POST_SYSCALL(ioctl)(long res, long fd, long cmd, long arg) {} | ||
| 1269 | |||
| 1270 | PRE_SYSCALL(flock)(long fd, long cmd) {} | ||
| 1271 | |||
| 1272 | POST_SYSCALL(flock)(long res, long fd, long cmd) {} | ||
| 1273 | |||
| 1274 | PRE_SYSCALL(io_setup)(long nr_reqs, void **ctx) { | ||
| 1275 | if (ctx) PRE_WRITE(ctx, sizeof(*ctx)); | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | POST_SYSCALL(io_setup)(long res, long nr_reqs, void **ctx) { | ||
| 1279 | if (res >= 0) { | ||
| 1280 | if (ctx) POST_WRITE(ctx, sizeof(*ctx)); | ||
| 1281 | // (*ctx) is actually a pointer to a kernel mapped page, and there are | ||
| 1282 | // people out there who are crazy enough to peek into that page's 32-byte | ||
| 1283 | // header. | ||
| 1284 | if (*ctx) POST_WRITE(*ctx, 32); | ||
| 1285 | } | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | PRE_SYSCALL(io_destroy)(long ctx) {} | ||
| 1289 | |||
| 1290 | POST_SYSCALL(io_destroy)(long res, long ctx) {} | ||
| 1291 | |||
| 1292 | PRE_SYSCALL(io_getevents)(long ctx_id, long min_nr, long nr, | ||
| 1293 | __sanitizer_io_event *ioevpp, void *timeout) { | ||
| 1294 | if (timeout) PRE_READ(timeout, struct_timespec_sz); | ||
| 1295 | } | ||
| 1296 | |||
| 1297 | POST_SYSCALL(io_getevents)(long res, long ctx_id, long min_nr, long nr, | ||
| 1298 | __sanitizer_io_event *ioevpp, void *timeout) { | ||
| 1299 | if (res >= 0) { | ||
| 1300 | if (ioevpp) POST_WRITE(ioevpp, res * sizeof(*ioevpp)); | ||
| 1301 | if (timeout) POST_WRITE(timeout, struct_timespec_sz); | ||
| 1302 | } | ||
| 1303 | for (long i = 0; i < res; i++) { | ||
| 1304 | // We synchronize io_submit -> io_getevents/io_cancel using the | ||
| 1305 | // user-provided data context. Data is not necessary a pointer, it can be | ||
| 1306 | // an int, 0 or whatever; acquire/release will correctly handle this. | ||
| 1307 | // This scheme can lead to false negatives, e.g. when all operations | ||
| 1308 | // synchronize on 0. But there does not seem to be a better solution | ||
| 1309 | // (except wrapping all operations in own context, which is unreliable). | ||
| 1310 | // We can not reliably extract fildes in io_getevents. | ||
| 1311 | COMMON_SYSCALL_ACQUIRE((void*)ioevpp[i].data); | ||
| 1312 | } | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | PRE_SYSCALL(io_submit)(long ctx_id, long nr, __sanitizer_iocb **iocbpp) { | ||
| 1316 | for (long i = 0; i < nr; ++i) { | ||
| 1317 | uptr op = iocbpp[i]->aio_lio_opcode; | ||
| 1318 | void *data = (void*)iocbpp[i]->aio_data; | ||
| 1319 | void *buf = (void*)iocbpp[i]->aio_buf; | ||
| 1320 | uptr len = (uptr)iocbpp[i]->aio_nbytes; | ||
| 1321 | if (op == iocb_cmd_pwrite && buf && len) { | ||
| 1322 | PRE_READ(buf, len); | ||
| 1323 | } else if (op == iocb_cmd_pread && buf && len) { | ||
| 1324 | POST_WRITE(buf, len); | ||
| 1325 | } else if (op == iocb_cmd_pwritev) { | ||
| 1326 | __sanitizer_iovec *iovec = (__sanitizer_iovec*)buf; | ||
| 1327 | for (uptr v = 0; v < len; v++) | ||
| 1328 | PRE_READ(iovec[v].iov_base, iovec[v].iov_len); | ||
| 1329 | } else if (op == iocb_cmd_preadv) { | ||
| 1330 | __sanitizer_iovec *iovec = (__sanitizer_iovec*)buf; | ||
| 1331 | for (uptr v = 0; v < len; v++) | ||
| 1332 | POST_WRITE(iovec[v].iov_base, iovec[v].iov_len); | ||
| 1333 | } | ||
| 1334 | // See comment in io_getevents. | ||
| 1335 | COMMON_SYSCALL_RELEASE(data); | ||
| 1336 | } | ||
| 1337 | } | ||
| 1338 | |||
| 1339 | POST_SYSCALL(io_submit)(long res, long ctx_id, long nr, | ||
| 1340 | __sanitizer_iocb **iocbpp) {} | ||
| 1341 | |||
| 1342 | PRE_SYSCALL(io_cancel)(long ctx_id, __sanitizer_iocb *iocb, | ||
| 1343 | __sanitizer_io_event *result) { | ||
| 1344 | } | ||
| 1345 | |||
| 1346 | POST_SYSCALL(io_cancel)(long res, long ctx_id, __sanitizer_iocb *iocb, | ||
| 1347 | __sanitizer_io_event *result) { | ||
| 1348 | if (res == 0) { | ||
| 1349 | if (result) { | ||
| 1350 | // See comment in io_getevents. | ||
| 1351 | COMMON_SYSCALL_ACQUIRE((void*)result->data); | ||
| 1352 | POST_WRITE(result, sizeof(*result)); | ||
| 1353 | } | ||
| 1354 | if (iocb) | ||
| 1355 | POST_WRITE(iocb, sizeof(*iocb)); | ||
| 1356 | } | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | PRE_SYSCALL(sendfile)(long out_fd, long in_fd, void *offset, long count) {} | ||
| 1360 | |||
| 1361 | POST_SYSCALL(sendfile)(long res, long out_fd, long in_fd, | ||
| 1362 | __sanitizer___kernel_off_t *offset, long count) { | ||
| 1363 | if (res >= 0) { | ||
| 1364 | if (offset) POST_WRITE(offset, sizeof(*offset)); | ||
| 1365 | } | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | PRE_SYSCALL(sendfile64)(long out_fd, long in_fd, void *offset, long count) {} | ||
| 1369 | |||
| 1370 | POST_SYSCALL(sendfile64)(long res, long out_fd, long in_fd, | ||
| 1371 | __sanitizer___kernel_loff_t *offset, long count) { | ||
| 1372 | if (res >= 0) { | ||
| 1373 | if (offset) POST_WRITE(offset, sizeof(*offset)); | ||
| 1374 | } | ||
| 1375 | } | ||
| 1376 | |||
| 1377 | PRE_SYSCALL(readlink)(const void *path, void *buf, long bufsiz) { | ||
| 1378 | if (path) | ||
| 1379 | PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); | ||
| 1380 | } | ||
| 1381 | |||
| 1382 | POST_SYSCALL(readlink)(long res, const void *path, void *buf, long bufsiz) { | ||
| 1383 | if (res >= 0) { | ||
| 1384 | if (buf) | ||
| 1385 | POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1); | ||
| 1386 | } | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | PRE_SYSCALL(creat)(const void *pathname, long mode) { | ||
| 1390 | if (pathname) | ||
| 1391 | PRE_READ(pathname, | ||
| 1392 | __sanitizer::internal_strlen((const char *)pathname) + 1); | ||
| 1393 | } | ||
| 1394 | |||
| 1395 | POST_SYSCALL(creat)(long res, const void *pathname, long mode) {} | ||
| 1396 | |||
| 1397 | PRE_SYSCALL(open)(const void *filename, long flags, long mode) { | ||
| 1398 | if (filename) | ||
| 1399 | PRE_READ(filename, | ||
| 1400 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 1401 | } | ||
| 1402 | |||
| 1403 | POST_SYSCALL(open)(long res, const void *filename, long flags, long mode) {} | ||
| 1404 | |||
| 1405 | PRE_SYSCALL(close)(long fd) { | ||
| 1406 | COMMON_SYSCALL_FD_CLOSE((int)fd); | ||
| 1407 | } | ||
| 1408 | |||
| 1409 | POST_SYSCALL(close)(long res, long fd) {} | ||
| 1410 | |||
| 1411 | PRE_SYSCALL(access)(const void *filename, long mode) { | ||
| 1412 | if (filename) | ||
| 1413 | PRE_READ(filename, | ||
| 1414 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 1415 | } | ||
| 1416 | |||
| 1417 | POST_SYSCALL(access)(long res, const void *filename, long mode) {} | ||
| 1418 | |||
| 1419 | PRE_SYSCALL(vhangup)() {} | ||
| 1420 | |||
| 1421 | POST_SYSCALL(vhangup)(long res) {} | ||
| 1422 | |||
| 1423 | PRE_SYSCALL(chown)(const void *filename, long user, long group) { | ||
| 1424 | if (filename) | ||
| 1425 | PRE_READ(filename, | ||
| 1426 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 1427 | } | ||
| 1428 | |||
| 1429 | POST_SYSCALL(chown)(long res, const void *filename, long user, long group) {} | ||
| 1430 | |||
| 1431 | PRE_SYSCALL(lchown)(const void *filename, long user, long group) { | ||
| 1432 | if (filename) | ||
| 1433 | PRE_READ(filename, | ||
| 1434 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 1435 | } | ||
| 1436 | |||
| 1437 | POST_SYSCALL(lchown)(long res, const void *filename, long user, long group) {} | ||
| 1438 | |||
| 1439 | PRE_SYSCALL(fchown)(long fd, long user, long group) {} | ||
| 1440 | |||
| 1441 | POST_SYSCALL(fchown)(long res, long fd, long user, long group) {} | ||
| 1442 | |||
| 1443 | #if SANITIZER_USES_UID16_SYSCALLS | ||
| 1444 | PRE_SYSCALL(chown16)(const void *filename, long user, long group) { | ||
| 1445 | if (filename) | ||
| 1446 | PRE_READ(filename, | ||
| 1447 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 1448 | } | ||
| 1449 | |||
| 1450 | POST_SYSCALL(chown16)(long res, const void *filename, long user, long group) {} | ||
| 1451 | |||
| 1452 | PRE_SYSCALL(lchown16)(const void *filename, long user, long group) { | ||
| 1453 | if (filename) | ||
| 1454 | PRE_READ(filename, | ||
| 1455 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 1456 | } | ||
| 1457 | |||
| 1458 | POST_SYSCALL(lchown16)(long res, const void *filename, long user, long group) {} | ||
| 1459 | |||
| 1460 | PRE_SYSCALL(fchown16)(long fd, long user, long group) {} | ||
| 1461 | |||
| 1462 | POST_SYSCALL(fchown16)(long res, long fd, long user, long group) {} | ||
| 1463 | |||
| 1464 | PRE_SYSCALL(setregid16)(long rgid, long egid) {} | ||
| 1465 | |||
| 1466 | POST_SYSCALL(setregid16)(long res, long rgid, long egid) {} | ||
| 1467 | |||
| 1468 | PRE_SYSCALL(setgid16)(long gid) {} | ||
| 1469 | |||
| 1470 | POST_SYSCALL(setgid16)(long res, long gid) {} | ||
| 1471 | |||
| 1472 | PRE_SYSCALL(setreuid16)(long ruid, long euid) {} | ||
| 1473 | |||
| 1474 | POST_SYSCALL(setreuid16)(long res, long ruid, long euid) {} | ||
| 1475 | |||
| 1476 | PRE_SYSCALL(setuid16)(long uid) {} | ||
| 1477 | |||
| 1478 | POST_SYSCALL(setuid16)(long res, long uid) {} | ||
| 1479 | |||
| 1480 | PRE_SYSCALL(setresuid16)(long ruid, long euid, long suid) {} | ||
| 1481 | |||
| 1482 | POST_SYSCALL(setresuid16)(long res, long ruid, long euid, long suid) {} | ||
| 1483 | |||
| 1484 | PRE_SYSCALL(getresuid16)(void *ruid, void *euid, void *suid) {} | ||
| 1485 | |||
| 1486 | POST_SYSCALL(getresuid16)(long res, __sanitizer___kernel_old_uid_t *ruid, | ||
| 1487 | __sanitizer___kernel_old_uid_t *euid, | ||
| 1488 | __sanitizer___kernel_old_uid_t *suid) { | ||
| 1489 | if (res >= 0) { | ||
| 1490 | if (ruid) POST_WRITE(ruid, sizeof(*ruid)); | ||
| 1491 | if (euid) POST_WRITE(euid, sizeof(*euid)); | ||
| 1492 | if (suid) POST_WRITE(suid, sizeof(*suid)); | ||
| 1493 | } | ||
| 1494 | } | ||
| 1495 | |||
| 1496 | PRE_SYSCALL(setresgid16)(long rgid, long egid, long sgid) {} | ||
| 1497 | |||
| 1498 | POST_SYSCALL(setresgid16)(long res, long rgid, long egid, long sgid) {} | ||
| 1499 | |||
| 1500 | PRE_SYSCALL(getresgid16)(void *rgid, void *egid, void *sgid) {} | ||
| 1501 | |||
| 1502 | POST_SYSCALL(getresgid16)(long res, __sanitizer___kernel_old_gid_t *rgid, | ||
| 1503 | __sanitizer___kernel_old_gid_t *egid, | ||
| 1504 | __sanitizer___kernel_old_gid_t *sgid) { | ||
| 1505 | if (res >= 0) { | ||
| 1506 | if (rgid) POST_WRITE(rgid, sizeof(*rgid)); | ||
| 1507 | if (egid) POST_WRITE(egid, sizeof(*egid)); | ||
| 1508 | if (sgid) POST_WRITE(sgid, sizeof(*sgid)); | ||
| 1509 | } | ||
| 1510 | } | ||
| 1511 | |||
| 1512 | PRE_SYSCALL(setfsuid16)(long uid) {} | ||
| 1513 | |||
| 1514 | POST_SYSCALL(setfsuid16)(long res, long uid) {} | ||
| 1515 | |||
| 1516 | PRE_SYSCALL(setfsgid16)(long gid) {} | ||
| 1517 | |||
| 1518 | POST_SYSCALL(setfsgid16)(long res, long gid) {} | ||
| 1519 | |||
| 1520 | PRE_SYSCALL(getgroups16)(long gidsetsize, | ||
| 1521 | __sanitizer___kernel_old_gid_t *grouplist) {} | ||
| 1522 | |||
| 1523 | POST_SYSCALL(getgroups16)(long res, long gidsetsize, | ||
| 1524 | __sanitizer___kernel_old_gid_t *grouplist) { | ||
| 1525 | if (res >= 0) { | ||
| 1526 | if (grouplist) POST_WRITE(grouplist, res * sizeof(*grouplist)); | ||
| 1527 | } | ||
| 1528 | } | ||
| 1529 | |||
| 1530 | PRE_SYSCALL(setgroups16)(long gidsetsize, | ||
| 1531 | __sanitizer___kernel_old_gid_t *grouplist) { | ||
| 1532 | if (grouplist) POST_WRITE(grouplist, gidsetsize * sizeof(*grouplist)); | ||
| 1533 | } | ||
| 1534 | |||
| 1535 | POST_SYSCALL(setgroups16)(long res, long gidsetsize, | ||
| 1536 | __sanitizer___kernel_old_gid_t *grouplist) {} | ||
| 1537 | |||
| 1538 | PRE_SYSCALL(getuid16)() {} | ||
| 1539 | |||
| 1540 | POST_SYSCALL(getuid16)(long res) {} | ||
| 1541 | |||
| 1542 | PRE_SYSCALL(geteuid16)() {} | ||
| 1543 | |||
| 1544 | POST_SYSCALL(geteuid16)(long res) {} | ||
| 1545 | |||
| 1546 | PRE_SYSCALL(getgid16)() {} | ||
| 1547 | |||
| 1548 | POST_SYSCALL(getgid16)(long res) {} | ||
| 1549 | |||
| 1550 | PRE_SYSCALL(getegid16)() {} | ||
| 1551 | |||
| 1552 | POST_SYSCALL(getegid16)(long res) {} | ||
| 1553 | #endif // SANITIZER_USES_UID16_SYSCALLS | ||
| 1554 | |||
| 1555 | PRE_SYSCALL(utime)(void *filename, void *times) {} | ||
| 1556 | |||
| 1557 | POST_SYSCALL(utime)(long res, void *filename, void *times) { | ||
| 1558 | if (res >= 0) { | ||
| 1559 | if (filename) | ||
| 1560 | POST_WRITE(filename, | ||
| 1561 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 1562 | if (times) POST_WRITE(times, struct_utimbuf_sz); | ||
| 1563 | } | ||
| 1564 | } | ||
| 1565 | |||
| 1566 | PRE_SYSCALL(utimes)(void *filename, void *utimes) {} | ||
| 1567 | |||
| 1568 | POST_SYSCALL(utimes)(long res, void *filename, void *utimes) { | ||
| 1569 | if (res >= 0) { | ||
| 1570 | if (filename) | ||
| 1571 | POST_WRITE(filename, | ||
| 1572 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 1573 | if (utimes) POST_WRITE(utimes, timeval_sz); | ||
| 1574 | } | ||
| 1575 | } | ||
| 1576 | |||
| 1577 | PRE_SYSCALL(lseek)(long fd, long offset, long origin) {} | ||
| 1578 | |||
| 1579 | POST_SYSCALL(lseek)(long res, long fd, long offset, long origin) {} | ||
| 1580 | |||
| 1581 | PRE_SYSCALL(llseek)(long fd, long offset_high, long offset_low, void *result, | ||
| 1582 | long origin) {} | ||
| 1583 | |||
| 1584 | POST_SYSCALL(llseek)(long res, long fd, long offset_high, long offset_low, | ||
| 1585 | void *result, long origin) { | ||
| 1586 | if (res >= 0) { | ||
| 1587 | if (result) POST_WRITE(result, sizeof(long long)); | ||
| 1588 | } | ||
| 1589 | } | ||
| 1590 | |||
| 1591 | PRE_SYSCALL(readv)(long fd, const __sanitizer_iovec *vec, long vlen) {} | ||
| 1592 | |||
| 1593 | POST_SYSCALL(readv)(long res, long fd, const __sanitizer_iovec *vec, | ||
| 1594 | long vlen) { | ||
| 1595 | if (res >= 0) { | ||
| 1596 | if (vec) kernel_write_iovec(vec, vlen, res); | ||
| 1597 | } | ||
| 1598 | } | ||
| 1599 | |||
| 1600 | PRE_SYSCALL(write)(long fd, const void *buf, long count) { | ||
| 1601 | if (buf) PRE_READ(buf, count); | ||
| 1602 | } | ||
| 1603 | |||
| 1604 | POST_SYSCALL(write)(long res, long fd, const void *buf, long count) {} | ||
| 1605 | |||
| 1606 | PRE_SYSCALL(writev)(long fd, const __sanitizer_iovec *vec, long vlen) {} | ||
| 1607 | |||
| 1608 | POST_SYSCALL(writev)(long res, long fd, const __sanitizer_iovec *vec, | ||
| 1609 | long vlen) { | ||
| 1610 | if (res >= 0) { | ||
| 1611 | if (vec) kernel_read_iovec(vec, vlen, res); | ||
| 1612 | } | ||
| 1613 | } | ||
| 1614 | |||
| 1615 | #ifdef _LP64 | ||
| 1616 | PRE_SYSCALL(pread64)(long fd, void *buf, long count, long pos) {} | ||
| 1617 | |||
| 1618 | POST_SYSCALL(pread64)(long res, long fd, void *buf, long count, long pos) { | ||
| 1619 | if (res >= 0) { | ||
| 1620 | if (buf) POST_WRITE(buf, res); | ||
| 1621 | } | ||
| 1622 | } | ||
| 1623 | |||
| 1624 | PRE_SYSCALL(pwrite64)(long fd, const void *buf, long count, long pos) { | ||
| 1625 | if (buf) PRE_READ(buf, count); | ||
| 1626 | } | ||
| 1627 | |||
| 1628 | POST_SYSCALL(pwrite64)(long res, long fd, const void *buf, long count, | ||
| 1629 | long pos) {} | ||
| 1630 | #else | ||
| 1631 | PRE_SYSCALL(pread64)(long fd, void *buf, long count, long pos0, long pos1) {} | ||
| 1632 | |||
| 1633 | POST_SYSCALL(pread64)(long res, long fd, void *buf, long count, long pos0, | ||
| 1634 | long pos1) { | ||
| 1635 | if (res >= 0) { | ||
| 1636 | if (buf) POST_WRITE(buf, res); | ||
| 1637 | } | ||
| 1638 | } | ||
| 1639 | |||
| 1640 | PRE_SYSCALL(pwrite64)(long fd, const void *buf, long count, long pos0, | ||
| 1641 | long pos1) { | ||
| 1642 | if (buf) PRE_READ(buf, count); | ||
| 1643 | } | ||
| 1644 | |||
| 1645 | POST_SYSCALL(pwrite64)(long res, long fd, const void *buf, long count, | ||
| 1646 | long pos0, long pos1) {} | ||
| 1647 | #endif | ||
| 1648 | |||
| 1649 | PRE_SYSCALL(preadv)(long fd, const __sanitizer_iovec *vec, long vlen, | ||
| 1650 | long pos_l, long pos_h) {} | ||
| 1651 | |||
| 1652 | POST_SYSCALL(preadv)(long res, long fd, const __sanitizer_iovec *vec, long vlen, | ||
| 1653 | long pos_l, long pos_h) { | ||
| 1654 | if (res >= 0) { | ||
| 1655 | if (vec) kernel_write_iovec(vec, vlen, res); | ||
| 1656 | } | ||
| 1657 | } | ||
| 1658 | |||
| 1659 | PRE_SYSCALL(pwritev)(long fd, const __sanitizer_iovec *vec, long vlen, | ||
| 1660 | long pos_l, long pos_h) {} | ||
| 1661 | |||
| 1662 | POST_SYSCALL(pwritev)(long res, long fd, const __sanitizer_iovec *vec, | ||
| 1663 | long vlen, long pos_l, long pos_h) { | ||
| 1664 | if (res >= 0) { | ||
| 1665 | if (vec) kernel_read_iovec(vec, vlen, res); | ||
| 1666 | } | ||
| 1667 | } | ||
| 1668 | |||
| 1669 | PRE_SYSCALL(getcwd)(void *buf, long size) {} | ||
| 1670 | |||
| 1671 | POST_SYSCALL(getcwd)(long res, void *buf, long size) { | ||
| 1672 | if (res >= 0) { | ||
| 1673 | if (buf) | ||
| 1674 | POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1); | ||
| 1675 | } | ||
| 1676 | } | ||
| 1677 | |||
| 1678 | PRE_SYSCALL(mkdir)(const void *pathname, long mode) { | ||
| 1679 | if (pathname) | ||
| 1680 | PRE_READ(pathname, | ||
| 1681 | __sanitizer::internal_strlen((const char *)pathname) + 1); | ||
| 1682 | } | ||
| 1683 | |||
| 1684 | POST_SYSCALL(mkdir)(long res, const void *pathname, long mode) {} | ||
| 1685 | |||
| 1686 | PRE_SYSCALL(chdir)(const void *filename) { | ||
| 1687 | if (filename) | ||
| 1688 | PRE_READ(filename, | ||
| 1689 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 1690 | } | ||
| 1691 | |||
| 1692 | POST_SYSCALL(chdir)(long res, const void *filename) {} | ||
| 1693 | |||
| 1694 | PRE_SYSCALL(fchdir)(long fd) {} | ||
| 1695 | |||
| 1696 | POST_SYSCALL(fchdir)(long res, long fd) {} | ||
| 1697 | |||
| 1698 | PRE_SYSCALL(rmdir)(const void *pathname) { | ||
| 1699 | if (pathname) | ||
| 1700 | PRE_READ(pathname, | ||
| 1701 | __sanitizer::internal_strlen((const char *)pathname) + 1); | ||
| 1702 | } | ||
| 1703 | |||
| 1704 | POST_SYSCALL(rmdir)(long res, const void *pathname) {} | ||
| 1705 | |||
| 1706 | PRE_SYSCALL(lookup_dcookie)(u64 cookie64, void *buf, long len) {} | ||
| 1707 | |||
| 1708 | POST_SYSCALL(lookup_dcookie)(long res, u64 cookie64, void *buf, long len) { | ||
| 1709 | if (res >= 0) { | ||
| 1710 | if (buf) | ||
| 1711 | POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1); | ||
| 1712 | } | ||
| 1713 | } | ||
| 1714 | |||
| 1715 | PRE_SYSCALL(quotactl)(long cmd, const void *special, long id, void *addr) { | ||
| 1716 | if (special) | ||
| 1717 | PRE_READ(special, __sanitizer::internal_strlen((const char *)special) + 1); | ||
| 1718 | } | ||
| 1719 | |||
| 1720 | POST_SYSCALL(quotactl)(long res, long cmd, const void *special, long id, | ||
| 1721 | void *addr) {} | ||
| 1722 | |||
| 1723 | PRE_SYSCALL(getdents)(long fd, void *dirent, long count) {} | ||
| 1724 | |||
| 1725 | POST_SYSCALL(getdents)(long res, long fd, void *dirent, long count) { | ||
| 1726 | if (res >= 0) { | ||
| 1727 | if (dirent) POST_WRITE(dirent, res); | ||
| 1728 | } | ||
| 1729 | } | ||
| 1730 | |||
| 1731 | PRE_SYSCALL(getdents64)(long fd, void *dirent, long count) {} | ||
| 1732 | |||
| 1733 | POST_SYSCALL(getdents64)(long res, long fd, void *dirent, long count) { | ||
| 1734 | if (res >= 0) { | ||
| 1735 | if (dirent) POST_WRITE(dirent, res); | ||
| 1736 | } | ||
| 1737 | } | ||
| 1738 | |||
| 1739 | PRE_SYSCALL(setsockopt)(long fd, long level, long optname, void *optval, | ||
| 1740 | long optlen) {} | ||
| 1741 | |||
| 1742 | POST_SYSCALL(setsockopt)(long res, long fd, long level, long optname, | ||
| 1743 | void *optval, long optlen) { | ||
| 1744 | if (res >= 0) { | ||
| 1745 | if (optval) | ||
| 1746 | POST_WRITE(optval, | ||
| 1747 | __sanitizer::internal_strlen((const char *)optval) + 1); | ||
| 1748 | } | ||
| 1749 | } | ||
| 1750 | |||
| 1751 | PRE_SYSCALL(getsockopt)(long fd, long level, long optname, void *optval, | ||
| 1752 | void *optlen) {} | ||
| 1753 | |||
| 1754 | POST_SYSCALL(getsockopt)(long res, long fd, long level, long optname, | ||
| 1755 | void *optval, void *optlen) { | ||
| 1756 | if (res >= 0) { | ||
| 1757 | if (optval) | ||
| 1758 | POST_WRITE(optval, | ||
| 1759 | __sanitizer::internal_strlen((const char *)optval) + 1); | ||
| 1760 | if (optlen) POST_WRITE(optlen, sizeof(int)); | ||
| 1761 | } | ||
| 1762 | } | ||
| 1763 | |||
| 1764 | PRE_SYSCALL(bind)(long arg0, sanitizer_kernel_sockaddr *arg1, long arg2) {} | ||
| 1765 | |||
| 1766 | POST_SYSCALL(bind)(long res, long arg0, sanitizer_kernel_sockaddr *arg1, | ||
| 1767 | long arg2) { | ||
| 1768 | if (res >= 0) { | ||
| 1769 | if (arg1) POST_WRITE(arg1, sizeof(*arg1)); | ||
| 1770 | } | ||
| 1771 | } | ||
| 1772 | |||
| 1773 | PRE_SYSCALL(connect)(long arg0, sanitizer_kernel_sockaddr *arg1, long arg2) {} | ||
| 1774 | |||
| 1775 | POST_SYSCALL(connect)(long res, long arg0, sanitizer_kernel_sockaddr *arg1, | ||
| 1776 | long arg2) { | ||
| 1777 | if (res >= 0) { | ||
| 1778 | if (arg1) POST_WRITE(arg1, sizeof(*arg1)); | ||
| 1779 | } | ||
| 1780 | } | ||
| 1781 | |||
| 1782 | PRE_SYSCALL(accept)(long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2) {} | ||
| 1783 | |||
| 1784 | POST_SYSCALL(accept)(long res, long arg0, sanitizer_kernel_sockaddr *arg1, | ||
| 1785 | void *arg2) { | ||
| 1786 | if (res >= 0) { | ||
| 1787 | if (arg1) POST_WRITE(arg1, sizeof(*arg1)); | ||
| 1788 | if (arg2) POST_WRITE(arg2, sizeof(unsigned)); | ||
| 1789 | } | ||
| 1790 | } | ||
| 1791 | |||
| 1792 | PRE_SYSCALL(accept4)(long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2, | ||
| 1793 | long arg3) {} | ||
| 1794 | |||
| 1795 | POST_SYSCALL(accept4)(long res, long arg0, sanitizer_kernel_sockaddr *arg1, | ||
| 1796 | void *arg2, long arg3) { | ||
| 1797 | if (res >= 0) { | ||
| 1798 | if (arg1) POST_WRITE(arg1, sizeof(*arg1)); | ||
| 1799 | if (arg2) POST_WRITE(arg2, sizeof(unsigned)); | ||
| 1800 | } | ||
| 1801 | } | ||
| 1802 | |||
| 1803 | PRE_SYSCALL(getsockname)(long arg0, sanitizer_kernel_sockaddr *arg1, | ||
| 1804 | void *arg2) {} | ||
| 1805 | |||
| 1806 | POST_SYSCALL(getsockname)(long res, long arg0, sanitizer_kernel_sockaddr *arg1, | ||
| 1807 | void *arg2) { | ||
| 1808 | if (res >= 0) { | ||
| 1809 | if (arg1) POST_WRITE(arg1, sizeof(*arg1)); | ||
| 1810 | if (arg2) POST_WRITE(arg2, sizeof(unsigned)); | ||
| 1811 | } | ||
| 1812 | } | ||
| 1813 | |||
| 1814 | PRE_SYSCALL(getpeername)(long arg0, sanitizer_kernel_sockaddr *arg1, | ||
| 1815 | void *arg2) {} | ||
| 1816 | |||
| 1817 | POST_SYSCALL(getpeername)(long res, long arg0, sanitizer_kernel_sockaddr *arg1, | ||
| 1818 | void *arg2) { | ||
| 1819 | if (res >= 0) { | ||
| 1820 | if (arg1) POST_WRITE(arg1, sizeof(*arg1)); | ||
| 1821 | if (arg2) POST_WRITE(arg2, sizeof(unsigned)); | ||
| 1822 | } | ||
| 1823 | } | ||
| 1824 | |||
| 1825 | PRE_SYSCALL(send)(long arg0, void *arg1, long arg2, long arg3) {} | ||
| 1826 | |||
| 1827 | POST_SYSCALL(send)(long res, long arg0, void *arg1, long arg2, long arg3) { | ||
| 1828 | if (res) { | ||
| 1829 | if (arg1) POST_READ(arg1, res); | ||
| 1830 | } | ||
| 1831 | } | ||
| 1832 | |||
| 1833 | PRE_SYSCALL(sendto)(long arg0, void *arg1, long arg2, long arg3, | ||
| 1834 | sanitizer_kernel_sockaddr *arg4, long arg5) {} | ||
| 1835 | |||
| 1836 | POST_SYSCALL(sendto)(long res, long arg0, void *arg1, long arg2, long arg3, | ||
| 1837 | sanitizer_kernel_sockaddr *arg4, long arg5) { | ||
| 1838 | if (res >= 0) { | ||
| 1839 | if (arg1) POST_READ(arg1, res); | ||
| 1840 | if (arg4) POST_WRITE(arg4, sizeof(*arg4)); | ||
| 1841 | } | ||
| 1842 | } | ||
| 1843 | |||
| 1844 | PRE_SYSCALL(sendmsg)(long fd, void *msg, long flags) {} | ||
| 1845 | |||
| 1846 | POST_SYSCALL(sendmsg)(long res, long fd, void *msg, long flags) { | ||
| 1847 | // FIXME: POST_READ | ||
| 1848 | } | ||
| 1849 | |||
| 1850 | PRE_SYSCALL(sendmmsg)(long fd, void *msg, long vlen, long flags) {} | ||
| 1851 | |||
| 1852 | POST_SYSCALL(sendmmsg)(long res, long fd, void *msg, long vlen, long flags) { | ||
| 1853 | // FIXME: POST_READ | ||
| 1854 | } | ||
| 1855 | |||
| 1856 | PRE_SYSCALL(recv)(long arg0, void *buf, long len, long flags) {} | ||
| 1857 | |||
| 1858 | POST_SYSCALL(recv)(long res, void *buf, long len, long flags) { | ||
| 1859 | if (res >= 0) { | ||
| 1860 | if (buf) POST_WRITE(buf, res); | ||
| 1861 | } | ||
| 1862 | } | ||
| 1863 | |||
| 1864 | PRE_SYSCALL(recvfrom)(long arg0, void *buf, long len, long flags, | ||
| 1865 | sanitizer_kernel_sockaddr *arg4, void *arg5) {} | ||
| 1866 | |||
| 1867 | POST_SYSCALL(recvfrom)(long res, long arg0, void *buf, long len, long flags, | ||
| 1868 | sanitizer_kernel_sockaddr *arg4, void *arg5) { | ||
| 1869 | if (res >= 0) { | ||
| 1870 | if (buf) POST_WRITE(buf, res); | ||
| 1871 | if (arg4) POST_WRITE(arg4, sizeof(*arg4)); | ||
| 1872 | if (arg5) POST_WRITE(arg5, sizeof(int)); | ||
| 1873 | } | ||
| 1874 | } | ||
| 1875 | |||
| 1876 | PRE_SYSCALL(socket)(long arg0, long arg1, long arg2) {} | ||
| 1877 | |||
| 1878 | POST_SYSCALL(socket)(long res, long arg0, long arg1, long arg2) {} | ||
| 1879 | |||
| 1880 | PRE_SYSCALL(socketpair)(long arg0, long arg1, long arg2, int *sv) {} | ||
| 1881 | |||
| 1882 | POST_SYSCALL(socketpair)(long res, long arg0, long arg1, long arg2, int *sv) { | ||
| 1883 | if (res >= 0) | ||
| 1884 | if (sv) POST_WRITE(sv, sizeof(int) * 2); | ||
| 1885 | } | ||
| 1886 | |||
| 1887 | PRE_SYSCALL(socketcall)(long call, void *args) {} | ||
| 1888 | |||
| 1889 | POST_SYSCALL(socketcall)(long res, long call, void *args) { | ||
| 1890 | if (res >= 0) { | ||
| 1891 | if (args) POST_WRITE(args, sizeof(long)); | ||
| 1892 | } | ||
| 1893 | } | ||
| 1894 | |||
| 1895 | PRE_SYSCALL(listen)(long arg0, long arg1) {} | ||
| 1896 | |||
| 1897 | POST_SYSCALL(listen)(long res, long arg0, long arg1) {} | ||
| 1898 | |||
| 1899 | PRE_SYSCALL(poll)(void *ufds, long nfds, long timeout) {} | ||
| 1900 | |||
| 1901 | POST_SYSCALL(poll)(long res, __sanitizer_pollfd *ufds, long nfds, | ||
| 1902 | long timeout) { | ||
| 1903 | if (res >= 0) { | ||
| 1904 | if (ufds) POST_WRITE(ufds, nfds * sizeof(*ufds)); | ||
| 1905 | } | ||
| 1906 | } | ||
| 1907 | |||
| 1908 | PRE_SYSCALL(select)(long n, __sanitizer___kernel_fd_set *inp, | ||
| 1909 | __sanitizer___kernel_fd_set *outp, | ||
| 1910 | __sanitizer___kernel_fd_set *exp, void *tvp) {} | ||
| 1911 | |||
| 1912 | POST_SYSCALL(select)(long res, long n, __sanitizer___kernel_fd_set *inp, | ||
| 1913 | __sanitizer___kernel_fd_set *outp, | ||
| 1914 | __sanitizer___kernel_fd_set *exp, void *tvp) { | ||
| 1915 | if (res >= 0) { | ||
| 1916 | if (inp) POST_WRITE(inp, sizeof(*inp)); | ||
| 1917 | if (outp) POST_WRITE(outp, sizeof(*outp)); | ||
| 1918 | if (exp) POST_WRITE(exp, sizeof(*exp)); | ||
| 1919 | if (tvp) POST_WRITE(tvp, timeval_sz); | ||
| 1920 | } | ||
| 1921 | } | ||
| 1922 | |||
| 1923 | PRE_SYSCALL(old_select)(void *arg) {} | ||
| 1924 | |||
| 1925 | POST_SYSCALL(old_select)(long res, void *arg) {} | ||
| 1926 | |||
| 1927 | PRE_SYSCALL(epoll_create)(long size) {} | ||
| 1928 | |||
| 1929 | POST_SYSCALL(epoll_create)(long res, long size) {} | ||
| 1930 | |||
| 1931 | PRE_SYSCALL(epoll_create1)(long flags) {} | ||
| 1932 | |||
| 1933 | POST_SYSCALL(epoll_create1)(long res, long flags) {} | ||
| 1934 | |||
| 1935 | PRE_SYSCALL(epoll_ctl)(long epfd, long op, long fd, void *event) {} | ||
| 1936 | |||
| 1937 | POST_SYSCALL(epoll_ctl)(long res, long epfd, long op, long fd, void *event) { | ||
| 1938 | if (res >= 0) { | ||
| 1939 | if (event) POST_WRITE(event, struct_epoll_event_sz); | ||
| 1940 | } | ||
| 1941 | } | ||
| 1942 | |||
| 1943 | PRE_SYSCALL(epoll_wait)(long epfd, void *events, long maxevents, long timeout) { | ||
| 1944 | } | ||
| 1945 | |||
| 1946 | POST_SYSCALL(epoll_wait)(long res, long epfd, void *events, long maxevents, | ||
| 1947 | long timeout) { | ||
| 1948 | if (res >= 0) { | ||
| 1949 | if (events) POST_WRITE(events, struct_epoll_event_sz); | ||
| 1950 | } | ||
| 1951 | } | ||
| 1952 | |||
| 1953 | PRE_SYSCALL(epoll_pwait)(long epfd, void *events, long maxevents, long timeout, | ||
| 1954 | const kernel_sigset_t *sigmask, long sigsetsize) { | ||
| 1955 | if (sigmask) PRE_READ(sigmask, sigsetsize); | ||
| 1956 | } | ||
| 1957 | |||
| 1958 | POST_SYSCALL(epoll_pwait)(long res, long epfd, void *events, long maxevents, | ||
| 1959 | long timeout, const void *sigmask, long sigsetsize) { | ||
| 1960 | if (res >= 0) { | ||
| 1961 | if (events) POST_WRITE(events, struct_epoll_event_sz); | ||
| 1962 | } | ||
| 1963 | } | ||
| 1964 | |||
| 1965 | PRE_SYSCALL(gethostname)(void *name, long len) {} | ||
| 1966 | |||
| 1967 | POST_SYSCALL(gethostname)(long res, void *name, long len) { | ||
| 1968 | if (res >= 0) { | ||
| 1969 | if (name) | ||
| 1970 | POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 1971 | } | ||
| 1972 | } | ||
| 1973 | |||
| 1974 | PRE_SYSCALL(sethostname)(void *name, long len) {} | ||
| 1975 | |||
| 1976 | POST_SYSCALL(sethostname)(long res, void *name, long len) { | ||
| 1977 | if (res >= 0) { | ||
| 1978 | if (name) | ||
| 1979 | POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 1980 | } | ||
| 1981 | } | ||
| 1982 | |||
| 1983 | PRE_SYSCALL(setdomainname)(void *name, long len) {} | ||
| 1984 | |||
| 1985 | POST_SYSCALL(setdomainname)(long res, void *name, long len) { | ||
| 1986 | if (res >= 0) { | ||
| 1987 | if (name) | ||
| 1988 | POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 1989 | } | ||
| 1990 | } | ||
| 1991 | |||
| 1992 | PRE_SYSCALL(newuname)(void *name) {} | ||
| 1993 | |||
| 1994 | POST_SYSCALL(newuname)(long res, void *name) { | ||
| 1995 | if (res >= 0) { | ||
| 1996 | if (name) POST_WRITE(name, struct_new_utsname_sz); | ||
| 1997 | } | ||
| 1998 | } | ||
| 1999 | |||
| 2000 | PRE_SYSCALL(uname)(void *arg0) {} | ||
| 2001 | |||
| 2002 | POST_SYSCALL(uname)(long res, void *arg0) { | ||
| 2003 | if (res >= 0) { | ||
| 2004 | if (arg0) POST_WRITE(arg0, struct_old_utsname_sz); | ||
| 2005 | } | ||
| 2006 | } | ||
| 2007 | |||
| 2008 | PRE_SYSCALL(olduname)(void *arg0) {} | ||
| 2009 | |||
| 2010 | POST_SYSCALL(olduname)(long res, void *arg0) { | ||
| 2011 | if (res >= 0) { | ||
| 2012 | if (arg0) POST_WRITE(arg0, struct_oldold_utsname_sz); | ||
| 2013 | } | ||
| 2014 | } | ||
| 2015 | |||
| 2016 | PRE_SYSCALL(getrlimit)(long resource, void *rlim) {} | ||
| 2017 | |||
| 2018 | POST_SYSCALL(getrlimit)(long res, long resource, void *rlim) { | ||
| 2019 | if (res >= 0) { | ||
| 2020 | if (rlim) POST_WRITE(rlim, struct_rlimit_sz); | ||
| 2021 | } | ||
| 2022 | } | ||
| 2023 | |||
| 2024 | PRE_SYSCALL(old_getrlimit)(long resource, void *rlim) {} | ||
| 2025 | |||
| 2026 | POST_SYSCALL(old_getrlimit)(long res, long resource, void *rlim) { | ||
| 2027 | if (res >= 0) { | ||
| 2028 | if (rlim) POST_WRITE(rlim, struct_rlimit_sz); | ||
| 2029 | } | ||
| 2030 | } | ||
| 2031 | |||
| 2032 | PRE_SYSCALL(setrlimit)(long resource, void *rlim) {} | ||
| 2033 | |||
| 2034 | POST_SYSCALL(setrlimit)(long res, long resource, void *rlim) { | ||
| 2035 | if (res >= 0) { | ||
| 2036 | if (rlim) POST_WRITE(rlim, struct_rlimit_sz); | ||
| 2037 | } | ||
| 2038 | } | ||
| 2039 | |||
| 2040 | #if !SANITIZER_ANDROID | ||
| 2041 | PRE_SYSCALL(prlimit64)(long pid, long resource, const void *new_rlim, | ||
| 2042 | void *old_rlim) { | ||
| 2043 | if (new_rlim) PRE_READ(new_rlim, struct_rlimit64_sz); | ||
| 2044 | } | ||
| 2045 | |||
| 2046 | POST_SYSCALL(prlimit64)(long res, long pid, long resource, const void *new_rlim, | ||
| 2047 | void *old_rlim) { | ||
| 2048 | if (res >= 0) { | ||
| 2049 | if (old_rlim) POST_WRITE(old_rlim, struct_rlimit64_sz); | ||
| 2050 | } | ||
| 2051 | } | ||
| 2052 | #endif | ||
| 2053 | |||
| 2054 | PRE_SYSCALL(getrusage)(long who, void *ru) {} | ||
| 2055 | |||
| 2056 | POST_SYSCALL(getrusage)(long res, long who, void *ru) { | ||
| 2057 | if (res >= 0) { | ||
| 2058 | if (ru) POST_WRITE(ru, struct_rusage_sz); | ||
| 2059 | } | ||
| 2060 | } | ||
| 2061 | |||
| 2062 | PRE_SYSCALL(umask)(long mask) {} | ||
| 2063 | |||
| 2064 | POST_SYSCALL(umask)(long res, long mask) {} | ||
| 2065 | |||
| 2066 | PRE_SYSCALL(msgget)(long key, long msgflg) {} | ||
| 2067 | |||
| 2068 | POST_SYSCALL(msgget)(long res, long key, long msgflg) {} | ||
| 2069 | |||
| 2070 | PRE_SYSCALL(msgsnd)(long msqid, void *msgp, long msgsz, long msgflg) { | ||
| 2071 | if (msgp) PRE_READ(msgp, msgsz); | ||
| 2072 | } | ||
| 2073 | |||
| 2074 | POST_SYSCALL(msgsnd)(long res, long msqid, void *msgp, long msgsz, | ||
| 2075 | long msgflg) {} | ||
| 2076 | |||
| 2077 | PRE_SYSCALL(msgrcv)(long msqid, void *msgp, long msgsz, long msgtyp, | ||
| 2078 | long msgflg) {} | ||
| 2079 | |||
| 2080 | POST_SYSCALL(msgrcv)(long res, long msqid, void *msgp, long msgsz, long msgtyp, | ||
| 2081 | long msgflg) { | ||
| 2082 | if (res >= 0) { | ||
| 2083 | if (msgp) POST_WRITE(msgp, res); | ||
| 2084 | } | ||
| 2085 | } | ||
| 2086 | |||
| 2087 | #if !SANITIZER_ANDROID | ||
| 2088 | PRE_SYSCALL(msgctl)(long msqid, long cmd, void *buf) {} | ||
| 2089 | |||
| 2090 | POST_SYSCALL(msgctl)(long res, long msqid, long cmd, void *buf) { | ||
| 2091 | if (res >= 0) { | ||
| 2092 | if (buf) POST_WRITE(buf, struct_msqid_ds_sz); | ||
| 2093 | } | ||
| 2094 | } | ||
| 2095 | #endif | ||
| 2096 | |||
| 2097 | PRE_SYSCALL(semget)(long key, long nsems, long semflg) {} | ||
| 2098 | |||
| 2099 | POST_SYSCALL(semget)(long res, long key, long nsems, long semflg) {} | ||
| 2100 | |||
| 2101 | PRE_SYSCALL(semop)(long semid, void *sops, long nsops) {} | ||
| 2102 | |||
| 2103 | POST_SYSCALL(semop)(long res, long semid, void *sops, long nsops) {} | ||
| 2104 | |||
| 2105 | PRE_SYSCALL(semctl)(long semid, long semnum, long cmd, void *arg) {} | ||
| 2106 | |||
| 2107 | POST_SYSCALL(semctl)(long res, long semid, long semnum, long cmd, void *arg) {} | ||
| 2108 | |||
| 2109 | PRE_SYSCALL(semtimedop)(long semid, void *sops, long nsops, | ||
| 2110 | const void *timeout) { | ||
| 2111 | if (timeout) PRE_READ(timeout, struct_timespec_sz); | ||
| 2112 | } | ||
| 2113 | |||
| 2114 | POST_SYSCALL(semtimedop)(long res, long semid, void *sops, long nsops, | ||
| 2115 | const void *timeout) {} | ||
| 2116 | |||
| 2117 | PRE_SYSCALL(shmat)(long shmid, void *shmaddr, long shmflg) {} | ||
| 2118 | |||
| 2119 | POST_SYSCALL(shmat)(long res, long shmid, void *shmaddr, long shmflg) { | ||
| 2120 | if (res >= 0) { | ||
| 2121 | if (shmaddr) | ||
| 2122 | POST_WRITE(shmaddr, | ||
| 2123 | __sanitizer::internal_strlen((const char *)shmaddr) + 1); | ||
| 2124 | } | ||
| 2125 | } | ||
| 2126 | |||
| 2127 | PRE_SYSCALL(shmget)(long key, long size, long flag) {} | ||
| 2128 | |||
| 2129 | POST_SYSCALL(shmget)(long res, long key, long size, long flag) {} | ||
| 2130 | |||
| 2131 | PRE_SYSCALL(shmdt)(void *shmaddr) {} | ||
| 2132 | |||
| 2133 | POST_SYSCALL(shmdt)(long res, void *shmaddr) { | ||
| 2134 | if (res >= 0) { | ||
| 2135 | if (shmaddr) | ||
| 2136 | POST_WRITE(shmaddr, | ||
| 2137 | __sanitizer::internal_strlen((const char *)shmaddr) + 1); | ||
| 2138 | } | ||
| 2139 | } | ||
| 2140 | |||
| 2141 | PRE_SYSCALL(ipc)(long call, long first, long second, long third, void *ptr, | ||
| 2142 | long fifth) {} | ||
| 2143 | |||
| 2144 | POST_SYSCALL(ipc)(long res, long call, long first, long second, long third, | ||
| 2145 | void *ptr, long fifth) {} | ||
| 2146 | |||
| 2147 | #if !SANITIZER_ANDROID | ||
| 2148 | PRE_SYSCALL(shmctl)(long shmid, long cmd, void *buf) {} | ||
| 2149 | |||
| 2150 | POST_SYSCALL(shmctl)(long res, long shmid, long cmd, void *buf) { | ||
| 2151 | if (res >= 0) { | ||
| 2152 | if (buf) POST_WRITE(buf, sizeof(__sanitizer_shmid_ds)); | ||
| 2153 | } | ||
| 2154 | } | ||
| 2155 | |||
| 2156 | PRE_SYSCALL(mq_open)(const void *name, long oflag, long mode, void *attr) { | ||
| 2157 | if (name) | ||
| 2158 | PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 2159 | } | ||
| 2160 | |||
| 2161 | POST_SYSCALL(mq_open)(long res, const void *name, long oflag, long mode, | ||
| 2162 | void *attr) { | ||
| 2163 | if (res >= 0) { | ||
| 2164 | if (attr) POST_WRITE(attr, struct_mq_attr_sz); | ||
| 2165 | } | ||
| 2166 | } | ||
| 2167 | |||
| 2168 | PRE_SYSCALL(mq_unlink)(const void *name) { | ||
| 2169 | if (name) | ||
| 2170 | PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 2171 | } | ||
| 2172 | |||
| 2173 | POST_SYSCALL(mq_unlink)(long res, const void *name) {} | ||
| 2174 | |||
| 2175 | PRE_SYSCALL(mq_timedsend)(long mqdes, const void *msg_ptr, long msg_len, | ||
| 2176 | long msg_prio, const void *abs_timeout) { | ||
| 2177 | if (msg_ptr) PRE_READ(msg_ptr, msg_len); | ||
| 2178 | if (abs_timeout) PRE_READ(abs_timeout, struct_timespec_sz); | ||
| 2179 | } | ||
| 2180 | |||
| 2181 | POST_SYSCALL(mq_timedsend)(long res, long mqdes, const void *msg_ptr, | ||
| 2182 | long msg_len, long msg_prio, | ||
| 2183 | const void *abs_timeout) {} | ||
| 2184 | |||
| 2185 | PRE_SYSCALL(mq_timedreceive)(long mqdes, void *msg_ptr, long msg_len, | ||
| 2186 | void *msg_prio, const void *abs_timeout) { | ||
| 2187 | if (abs_timeout) PRE_READ(abs_timeout, struct_timespec_sz); | ||
| 2188 | } | ||
| 2189 | |||
| 2190 | POST_SYSCALL(mq_timedreceive)(long res, long mqdes, void *msg_ptr, long msg_len, | ||
| 2191 | int *msg_prio, const void *abs_timeout) { | ||
| 2192 | if (res >= 0) { | ||
| 2193 | if (msg_ptr) POST_WRITE(msg_ptr, res); | ||
| 2194 | if (msg_prio) POST_WRITE(msg_prio, sizeof(*msg_prio)); | ||
| 2195 | } | ||
| 2196 | } | ||
| 2197 | |||
| 2198 | PRE_SYSCALL(mq_notify)(long mqdes, const void *notification) { | ||
| 2199 | if (notification) PRE_READ(notification, struct_sigevent_sz); | ||
| 2200 | } | ||
| 2201 | |||
| 2202 | POST_SYSCALL(mq_notify)(long res, long mqdes, const void *notification) {} | ||
| 2203 | |||
| 2204 | PRE_SYSCALL(mq_getsetattr)(long mqdes, const void *mqstat, void *omqstat) { | ||
| 2205 | if (mqstat) PRE_READ(mqstat, struct_mq_attr_sz); | ||
| 2206 | } | ||
| 2207 | |||
| 2208 | POST_SYSCALL(mq_getsetattr)(long res, long mqdes, const void *mqstat, | ||
| 2209 | void *omqstat) { | ||
| 2210 | if (res >= 0) { | ||
| 2211 | if (omqstat) POST_WRITE(omqstat, struct_mq_attr_sz); | ||
| 2212 | } | ||
| 2213 | } | ||
| 2214 | #endif // SANITIZER_ANDROID | ||
| 2215 | |||
| 2216 | PRE_SYSCALL(pciconfig_iobase)(long which, long bus, long devfn) {} | ||
| 2217 | |||
| 2218 | POST_SYSCALL(pciconfig_iobase)(long res, long which, long bus, long devfn) {} | ||
| 2219 | |||
| 2220 | PRE_SYSCALL(pciconfig_read)(long bus, long dfn, long off, long len, void *buf) { | ||
| 2221 | } | ||
| 2222 | |||
| 2223 | POST_SYSCALL(pciconfig_read)(long res, long bus, long dfn, long off, long len, | ||
| 2224 | void *buf) {} | ||
| 2225 | |||
| 2226 | PRE_SYSCALL(pciconfig_write)(long bus, long dfn, long off, long len, | ||
| 2227 | void *buf) {} | ||
| 2228 | |||
| 2229 | POST_SYSCALL(pciconfig_write)(long res, long bus, long dfn, long off, long len, | ||
| 2230 | void *buf) {} | ||
| 2231 | |||
| 2232 | PRE_SYSCALL(swapon)(const void *specialfile, long swap_flags) { | ||
| 2233 | if (specialfile) | ||
| 2234 | PRE_READ(specialfile, | ||
| 2235 | __sanitizer::internal_strlen((const char *)specialfile) + 1); | ||
| 2236 | } | ||
| 2237 | |||
| 2238 | POST_SYSCALL(swapon)(long res, const void *specialfile, long swap_flags) {} | ||
| 2239 | |||
| 2240 | PRE_SYSCALL(swapoff)(const void *specialfile) { | ||
| 2241 | if (specialfile) | ||
| 2242 | PRE_READ(specialfile, | ||
| 2243 | __sanitizer::internal_strlen((const char *)specialfile) + 1); | ||
| 2244 | } | ||
| 2245 | |||
| 2246 | POST_SYSCALL(swapoff)(long res, const void *specialfile) {} | ||
| 2247 | |||
| 2248 | PRE_SYSCALL(sysctl)(__sanitizer___sysctl_args *args) { | ||
| 2249 | if (args) { | ||
| 2250 | if (args->name) PRE_READ(args->name, args->nlen * sizeof(*args->name)); | ||
| 2251 | if (args->newval) PRE_READ(args->name, args->newlen); | ||
| 2252 | } | ||
| 2253 | } | ||
| 2254 | |||
| 2255 | POST_SYSCALL(sysctl)(long res, __sanitizer___sysctl_args *args) { | ||
| 2256 | if (res >= 0) { | ||
| 2257 | if (args && args->oldval && args->oldlenp) { | ||
| 2258 | POST_WRITE(args->oldlenp, sizeof(*args->oldlenp)); | ||
| 2259 | POST_WRITE(args->oldval, *args->oldlenp); | ||
| 2260 | } | ||
| 2261 | } | ||
| 2262 | } | ||
| 2263 | |||
| 2264 | PRE_SYSCALL(sysinfo)(void *info) {} | ||
| 2265 | |||
| 2266 | POST_SYSCALL(sysinfo)(long res, void *info) { | ||
| 2267 | if (res >= 0) { | ||
| 2268 | if (info) POST_WRITE(info, struct_sysinfo_sz); | ||
| 2269 | } | ||
| 2270 | } | ||
| 2271 | |||
| 2272 | PRE_SYSCALL(sysfs)(long option, long arg1, long arg2) {} | ||
| 2273 | |||
| 2274 | POST_SYSCALL(sysfs)(long res, long option, long arg1, long arg2) {} | ||
| 2275 | |||
| 2276 | PRE_SYSCALL(syslog)(long type, void *buf, long len) {} | ||
| 2277 | |||
| 2278 | POST_SYSCALL(syslog)(long res, long type, void *buf, long len) { | ||
| 2279 | if (res >= 0) { | ||
| 2280 | if (buf) | ||
| 2281 | POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1); | ||
| 2282 | } | ||
| 2283 | } | ||
| 2284 | |||
| 2285 | PRE_SYSCALL(uselib)(const void *library) { | ||
| 2286 | if (library) | ||
| 2287 | PRE_READ(library, __sanitizer::internal_strlen((const char *)library) + 1); | ||
| 2288 | } | ||
| 2289 | |||
| 2290 | POST_SYSCALL(uselib)(long res, const void *library) {} | ||
| 2291 | |||
| 2292 | PRE_SYSCALL(ni_syscall)() {} | ||
| 2293 | |||
| 2294 | POST_SYSCALL(ni_syscall)(long res) {} | ||
| 2295 | |||
| 2296 | PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) { | ||
| 2297 | #if !SANITIZER_ANDROID && \ | ||
| 2298 | (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ | ||
| 2299 | defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__)) | ||
| 2300 | if (data) { | ||
| 2301 | if (request == ptrace_setregs) { | ||
| 2302 | PRE_READ((void *)data, struct_user_regs_struct_sz); | ||
| 2303 | } else if (request == ptrace_setfpregs) { | ||
| 2304 | PRE_READ((void *)data, struct_user_fpregs_struct_sz); | ||
| 2305 | } else if (request == ptrace_setfpxregs) { | ||
| 2306 | PRE_READ((void *)data, struct_user_fpxregs_struct_sz); | ||
| 2307 | } else if (request == ptrace_setsiginfo) { | ||
| 2308 | PRE_READ((void *)data, siginfo_t_sz); | ||
| 2309 | } else if (request == ptrace_setregset) { | ||
| 2310 | __sanitizer_iovec *iov = (__sanitizer_iovec *)data; | ||
| 2311 | PRE_READ(iov->iov_base, iov->iov_len); | ||
| 2312 | } | ||
| 2313 | } | ||
| 2314 | #endif | ||
| 2315 | } | ||
| 2316 | |||
| 2317 | POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) { | ||
| 2318 | #if !SANITIZER_ANDROID && \ | ||
| 2319 | (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ | ||
| 2320 | defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__)) | ||
| 2321 | if (res >= 0 && data) { | ||
| 2322 | // Note that this is different from the interceptor in | ||
| 2323 | // sanitizer_common_interceptors.inc. | ||
| 2324 | // PEEK* requests return resulting values through data pointer. | ||
| 2325 | if (request == ptrace_getregs) { | ||
| 2326 | POST_WRITE((void *)data, struct_user_regs_struct_sz); | ||
| 2327 | } else if (request == ptrace_getfpregs) { | ||
| 2328 | POST_WRITE((void *)data, struct_user_fpregs_struct_sz); | ||
| 2329 | } else if (request == ptrace_getfpxregs) { | ||
| 2330 | POST_WRITE((void *)data, struct_user_fpxregs_struct_sz); | ||
| 2331 | } else if (request == ptrace_getsiginfo) { | ||
| 2332 | POST_WRITE((void *)data, siginfo_t_sz); | ||
| 2333 | } else if (request == ptrace_getregset) { | ||
| 2334 | __sanitizer_iovec *iov = (__sanitizer_iovec *)data; | ||
| 2335 | POST_WRITE(iov->iov_base, iov->iov_len); | ||
| 2336 | } else if (request == ptrace_peekdata || request == ptrace_peektext || | ||
| 2337 | request == ptrace_peekuser) { | ||
| 2338 | POST_WRITE((void *)data, sizeof(void *)); | ||
| 2339 | } | ||
| 2340 | } | ||
| 2341 | #endif | ||
| 2342 | } | ||
| 2343 | |||
| 2344 | PRE_SYSCALL(add_key)(const void *_type, const void *_description, | ||
| 2345 | const void *_payload, long plen, long destringid) { | ||
| 2346 | if (_type) | ||
| 2347 | PRE_READ(_type, __sanitizer::internal_strlen((const char *)_type) + 1); | ||
| 2348 | if (_description) | ||
| 2349 | PRE_READ(_description, | ||
| 2350 | __sanitizer::internal_strlen((const char *)_description) + 1); | ||
| 2351 | } | ||
| 2352 | |||
| 2353 | POST_SYSCALL(add_key)(long res, const void *_type, const void *_description, | ||
| 2354 | const void *_payload, long plen, long destringid) {} | ||
| 2355 | |||
| 2356 | PRE_SYSCALL(request_key)(const void *_type, const void *_description, | ||
| 2357 | const void *_callout_info, long destringid) { | ||
| 2358 | if (_type) | ||
| 2359 | PRE_READ(_type, __sanitizer::internal_strlen((const char *)_type) + 1); | ||
| 2360 | if (_description) | ||
| 2361 | PRE_READ(_description, | ||
| 2362 | __sanitizer::internal_strlen((const char *)_description) + 1); | ||
| 2363 | if (_callout_info) | ||
| 2364 | PRE_READ(_callout_info, | ||
| 2365 | __sanitizer::internal_strlen((const char *)_callout_info) + 1); | ||
| 2366 | } | ||
| 2367 | |||
| 2368 | POST_SYSCALL(request_key)(long res, const void *_type, const void *_description, | ||
| 2369 | const void *_callout_info, long destringid) {} | ||
| 2370 | |||
| 2371 | PRE_SYSCALL(keyctl)(long cmd, long arg2, long arg3, long arg4, long arg5) {} | ||
| 2372 | |||
| 2373 | POST_SYSCALL(keyctl)(long res, long cmd, long arg2, long arg3, long arg4, | ||
| 2374 | long arg5) {} | ||
| 2375 | |||
| 2376 | PRE_SYSCALL(ioprio_set)(long which, long who, long ioprio) {} | ||
| 2377 | |||
| 2378 | POST_SYSCALL(ioprio_set)(long res, long which, long who, long ioprio) {} | ||
| 2379 | |||
| 2380 | PRE_SYSCALL(ioprio_get)(long which, long who) {} | ||
| 2381 | |||
| 2382 | POST_SYSCALL(ioprio_get)(long res, long which, long who) {} | ||
| 2383 | |||
| 2384 | PRE_SYSCALL(set_mempolicy)(long mode, void *nmask, long maxnode) {} | ||
| 2385 | |||
| 2386 | POST_SYSCALL(set_mempolicy)(long res, long mode, void *nmask, long maxnode) { | ||
| 2387 | if (res >= 0) { | ||
| 2388 | if (nmask) POST_WRITE(nmask, sizeof(long)); | ||
| 2389 | } | ||
| 2390 | } | ||
| 2391 | |||
| 2392 | PRE_SYSCALL(migrate_pages)(long pid, long maxnode, const void *from, | ||
| 2393 | const void *to) { | ||
| 2394 | if (from) PRE_READ(from, sizeof(long)); | ||
| 2395 | if (to) PRE_READ(to, sizeof(long)); | ||
| 2396 | } | ||
| 2397 | |||
| 2398 | POST_SYSCALL(migrate_pages)(long res, long pid, long maxnode, const void *from, | ||
| 2399 | const void *to) {} | ||
| 2400 | |||
| 2401 | PRE_SYSCALL(move_pages)(long pid, long nr_pages, const void **pages, | ||
| 2402 | const int *nodes, int *status, long flags) { | ||
| 2403 | if (pages) PRE_READ(pages, nr_pages * sizeof(*pages)); | ||
| 2404 | if (nodes) PRE_READ(nodes, nr_pages * sizeof(*nodes)); | ||
| 2405 | } | ||
| 2406 | |||
| 2407 | POST_SYSCALL(move_pages)(long res, long pid, long nr_pages, const void **pages, | ||
| 2408 | const int *nodes, int *status, long flags) { | ||
| 2409 | if (res >= 0) { | ||
| 2410 | if (status) POST_WRITE(status, nr_pages * sizeof(*status)); | ||
| 2411 | } | ||
| 2412 | } | ||
| 2413 | |||
| 2414 | PRE_SYSCALL(mbind)(long start, long len, long mode, void *nmask, long maxnode, | ||
| 2415 | long flags) {} | ||
| 2416 | |||
| 2417 | POST_SYSCALL(mbind)(long res, long start, long len, long mode, void *nmask, | ||
| 2418 | long maxnode, long flags) { | ||
| 2419 | if (res >= 0) { | ||
| 2420 | if (nmask) POST_WRITE(nmask, sizeof(long)); | ||
| 2421 | } | ||
| 2422 | } | ||
| 2423 | |||
| 2424 | PRE_SYSCALL(get_mempolicy)(void *policy, void *nmask, long maxnode, long addr, | ||
| 2425 | long flags) {} | ||
| 2426 | |||
| 2427 | POST_SYSCALL(get_mempolicy)(long res, void *policy, void *nmask, long maxnode, | ||
| 2428 | long addr, long flags) { | ||
| 2429 | if (res >= 0) { | ||
| 2430 | if (policy) POST_WRITE(policy, sizeof(int)); | ||
| 2431 | if (nmask) POST_WRITE(nmask, sizeof(long)); | ||
| 2432 | } | ||
| 2433 | } | ||
| 2434 | |||
| 2435 | PRE_SYSCALL(inotify_init)() {} | ||
| 2436 | |||
| 2437 | POST_SYSCALL(inotify_init)(long res) {} | ||
| 2438 | |||
| 2439 | PRE_SYSCALL(inotify_init1)(long flags) {} | ||
| 2440 | |||
| 2441 | POST_SYSCALL(inotify_init1)(long res, long flags) {} | ||
| 2442 | |||
| 2443 | PRE_SYSCALL(inotify_add_watch)(long fd, const void *path, long mask) { | ||
| 2444 | if (path) | ||
| 2445 | PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); | ||
| 2446 | } | ||
| 2447 | |||
| 2448 | POST_SYSCALL(inotify_add_watch)(long res, long fd, const void *path, | ||
| 2449 | long mask) {} | ||
| 2450 | |||
| 2451 | PRE_SYSCALL(inotify_rm_watch)(long fd, long wd) {} | ||
| 2452 | |||
| 2453 | POST_SYSCALL(inotify_rm_watch)(long res, long fd, long wd) {} | ||
| 2454 | |||
| 2455 | PRE_SYSCALL(spu_run)(long fd, void *unpc, void *ustatus) {} | ||
| 2456 | |||
| 2457 | POST_SYSCALL(spu_run)(long res, long fd, unsigned *unpc, unsigned *ustatus) { | ||
| 2458 | if (res >= 0) { | ||
| 2459 | if (unpc) POST_WRITE(unpc, sizeof(*unpc)); | ||
| 2460 | if (ustatus) POST_WRITE(ustatus, sizeof(*ustatus)); | ||
| 2461 | } | ||
| 2462 | } | ||
| 2463 | |||
| 2464 | PRE_SYSCALL(spu_create)(const void *name, long flags, long mode, long fd) { | ||
| 2465 | if (name) | ||
| 2466 | PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); | ||
| 2467 | } | ||
| 2468 | |||
| 2469 | POST_SYSCALL(spu_create)(long res, const void *name, long flags, long mode, | ||
| 2470 | long fd) {} | ||
| 2471 | |||
| 2472 | PRE_SYSCALL(mknodat)(long dfd, const void *filename, long mode, long dev) { | ||
| 2473 | if (filename) | ||
| 2474 | PRE_READ(filename, | ||
| 2475 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 2476 | } | ||
| 2477 | |||
| 2478 | POST_SYSCALL(mknodat)(long res, long dfd, const void *filename, long mode, | ||
| 2479 | long dev) {} | ||
| 2480 | |||
| 2481 | PRE_SYSCALL(mkdirat)(long dfd, const void *pathname, long mode) { | ||
| 2482 | if (pathname) | ||
| 2483 | PRE_READ(pathname, | ||
| 2484 | __sanitizer::internal_strlen((const char *)pathname) + 1); | ||
| 2485 | } | ||
| 2486 | |||
| 2487 | POST_SYSCALL(mkdirat)(long res, long dfd, const void *pathname, long mode) {} | ||
| 2488 | |||
| 2489 | PRE_SYSCALL(unlinkat)(long dfd, const void *pathname, long flag) { | ||
| 2490 | if (pathname) | ||
| 2491 | PRE_READ(pathname, | ||
| 2492 | __sanitizer::internal_strlen((const char *)pathname) + 1); | ||
| 2493 | } | ||
| 2494 | |||
| 2495 | POST_SYSCALL(unlinkat)(long res, long dfd, const void *pathname, long flag) {} | ||
| 2496 | |||
| 2497 | PRE_SYSCALL(symlinkat)(const void *oldname, long newdfd, const void *newname) { | ||
| 2498 | if (oldname) | ||
| 2499 | PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1); | ||
| 2500 | if (newname) | ||
| 2501 | PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1); | ||
| 2502 | } | ||
| 2503 | |||
| 2504 | POST_SYSCALL(symlinkat)(long res, const void *oldname, long newdfd, | ||
| 2505 | const void *newname) {} | ||
| 2506 | |||
| 2507 | PRE_SYSCALL(linkat)(long olddfd, const void *oldname, long newdfd, | ||
| 2508 | const void *newname, long flags) { | ||
| 2509 | if (oldname) | ||
| 2510 | PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1); | ||
| 2511 | if (newname) | ||
| 2512 | PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1); | ||
| 2513 | } | ||
| 2514 | |||
| 2515 | POST_SYSCALL(linkat)(long res, long olddfd, const void *oldname, long newdfd, | ||
| 2516 | const void *newname, long flags) {} | ||
| 2517 | |||
| 2518 | PRE_SYSCALL(renameat)(long olddfd, const void *oldname, long newdfd, | ||
| 2519 | const void *newname) { | ||
| 2520 | if (oldname) | ||
| 2521 | PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1); | ||
| 2522 | if (newname) | ||
| 2523 | PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1); | ||
| 2524 | } | ||
| 2525 | |||
| 2526 | POST_SYSCALL(renameat)(long res, long olddfd, const void *oldname, long newdfd, | ||
| 2527 | const void *newname) {} | ||
| 2528 | |||
| 2529 | PRE_SYSCALL(futimesat)(long dfd, const void *filename, void *utimes) { | ||
| 2530 | if (filename) | ||
| 2531 | PRE_READ(filename, | ||
| 2532 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 2533 | } | ||
| 2534 | |||
| 2535 | POST_SYSCALL(futimesat)(long res, long dfd, const void *filename, | ||
| 2536 | void *utimes) { | ||
| 2537 | if (res >= 0) { | ||
| 2538 | if (utimes) POST_WRITE(utimes, timeval_sz); | ||
| 2539 | } | ||
| 2540 | } | ||
| 2541 | |||
| 2542 | PRE_SYSCALL(faccessat)(long dfd, const void *filename, long mode) { | ||
| 2543 | if (filename) | ||
| 2544 | PRE_READ(filename, | ||
| 2545 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 2546 | } | ||
| 2547 | |||
| 2548 | POST_SYSCALL(faccessat)(long res, long dfd, const void *filename, long mode) {} | ||
| 2549 | |||
| 2550 | PRE_SYSCALL(fchmodat)(long dfd, const void *filename, long mode) { | ||
| 2551 | if (filename) | ||
| 2552 | PRE_READ(filename, | ||
| 2553 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 2554 | } | ||
| 2555 | |||
| 2556 | POST_SYSCALL(fchmodat)(long res, long dfd, const void *filename, long mode) {} | ||
| 2557 | |||
| 2558 | PRE_SYSCALL(fchownat)(long dfd, const void *filename, long user, long group, | ||
| 2559 | long flag) { | ||
| 2560 | if (filename) | ||
| 2561 | PRE_READ(filename, | ||
| 2562 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 2563 | } | ||
| 2564 | |||
| 2565 | POST_SYSCALL(fchownat)(long res, long dfd, const void *filename, long user, | ||
| 2566 | long group, long flag) {} | ||
| 2567 | |||
| 2568 | PRE_SYSCALL(openat)(long dfd, const void *filename, long flags, long mode) { | ||
| 2569 | if (filename) | ||
| 2570 | PRE_READ(filename, | ||
| 2571 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 2572 | } | ||
| 2573 | |||
| 2574 | POST_SYSCALL(openat)(long res, long dfd, const void *filename, long flags, | ||
| 2575 | long mode) {} | ||
| 2576 | |||
| 2577 | PRE_SYSCALL(newfstatat)(long dfd, const void *filename, void *statbuf, | ||
| 2578 | long flag) { | ||
| 2579 | if (filename) | ||
| 2580 | PRE_READ(filename, | ||
| 2581 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 2582 | } | ||
| 2583 | |||
| 2584 | POST_SYSCALL(newfstatat)(long res, long dfd, const void *filename, | ||
| 2585 | void *statbuf, long flag) { | ||
| 2586 | if (res >= 0) { | ||
| 2587 | if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz); | ||
| 2588 | } | ||
| 2589 | } | ||
| 2590 | |||
| 2591 | PRE_SYSCALL(fstatat64)(long dfd, const void *filename, void *statbuf, | ||
| 2592 | long flag) { | ||
| 2593 | if (filename) | ||
| 2594 | PRE_READ(filename, | ||
| 2595 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 2596 | } | ||
| 2597 | |||
| 2598 | POST_SYSCALL(fstatat64)(long res, long dfd, const void *filename, void *statbuf, | ||
| 2599 | long flag) { | ||
| 2600 | if (res >= 0) { | ||
| 2601 | if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz); | ||
| 2602 | } | ||
| 2603 | } | ||
| 2604 | |||
| 2605 | PRE_SYSCALL(readlinkat)(long dfd, const void *path, void *buf, long bufsiz) { | ||
| 2606 | if (path) | ||
| 2607 | PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); | ||
| 2608 | } | ||
| 2609 | |||
| 2610 | POST_SYSCALL(readlinkat)(long res, long dfd, const void *path, void *buf, | ||
| 2611 | long bufsiz) { | ||
| 2612 | if (res >= 0) { | ||
| 2613 | if (buf) | ||
| 2614 | POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1); | ||
| 2615 | } | ||
| 2616 | } | ||
| 2617 | |||
| 2618 | PRE_SYSCALL(utimensat)(long dfd, const void *filename, void *utimes, | ||
| 2619 | long flags) { | ||
| 2620 | if (filename) | ||
| 2621 | PRE_READ(filename, | ||
| 2622 | __sanitizer::internal_strlen((const char *)filename) + 1); | ||
| 2623 | } | ||
| 2624 | |||
| 2625 | POST_SYSCALL(utimensat)(long res, long dfd, const void *filename, void *utimes, | ||
| 2626 | long flags) { | ||
| 2627 | if (res >= 0) { | ||
| 2628 | if (utimes) POST_WRITE(utimes, struct_timespec_sz); | ||
| 2629 | } | ||
| 2630 | } | ||
| 2631 | |||
| 2632 | PRE_SYSCALL(unshare)(long unshare_flags) {} | ||
| 2633 | |||
| 2634 | POST_SYSCALL(unshare)(long res, long unshare_flags) {} | ||
| 2635 | |||
| 2636 | PRE_SYSCALL(splice)(long fd_in, void *off_in, long fd_out, void *off_out, | ||
| 2637 | long len, long flags) {} | ||
| 2638 | |||
| 2639 | POST_SYSCALL(splice)(long res, long fd_in, void *off_in, long fd_out, | ||
| 2640 | void *off_out, long len, long flags) { | ||
| 2641 | if (res >= 0) { | ||
| 2642 | if (off_in) POST_WRITE(off_in, sizeof(long long)); | ||
| 2643 | if (off_out) POST_WRITE(off_out, sizeof(long long)); | ||
| 2644 | } | ||
| 2645 | } | ||
| 2646 | |||
| 2647 | PRE_SYSCALL(vmsplice)(long fd, const __sanitizer_iovec *iov, long nr_segs, | ||
| 2648 | long flags) {} | ||
| 2649 | |||
| 2650 | POST_SYSCALL(vmsplice)(long res, long fd, const __sanitizer_iovec *iov, | ||
| 2651 | long nr_segs, long flags) { | ||
| 2652 | if (res >= 0) { | ||
| 2653 | if (iov) kernel_read_iovec(iov, nr_segs, res); | ||
| 2654 | } | ||
| 2655 | } | ||
| 2656 | |||
| 2657 | PRE_SYSCALL(tee)(long fdin, long fdout, long len, long flags) {} | ||
| 2658 | |||
| 2659 | POST_SYSCALL(tee)(long res, long fdin, long fdout, long len, long flags) {} | ||
| 2660 | |||
| 2661 | PRE_SYSCALL(get_robust_list)(long pid, void *head_ptr, void *len_ptr) {} | ||
| 2662 | |||
| 2663 | POST_SYSCALL(get_robust_list)(long res, long pid, void *head_ptr, | ||
| 2664 | void *len_ptr) {} | ||
| 2665 | |||
| 2666 | PRE_SYSCALL(set_robust_list)(void *head, long len) {} | ||
| 2667 | |||
| 2668 | POST_SYSCALL(set_robust_list)(long res, void *head, long len) {} | ||
| 2669 | |||
| 2670 | PRE_SYSCALL(getcpu)(void *cpu, void *node, void *cache) {} | ||
| 2671 | |||
| 2672 | POST_SYSCALL(getcpu)(long res, void *cpu, void *node, void *cache) { | ||
| 2673 | if (res >= 0) { | ||
| 2674 | if (cpu) POST_WRITE(cpu, sizeof(unsigned)); | ||
| 2675 | if (node) POST_WRITE(node, sizeof(unsigned)); | ||
| 2676 | // The third argument to this system call is nowadays unused. | ||
| 2677 | } | ||
| 2678 | } | ||
| 2679 | |||
| 2680 | PRE_SYSCALL(signalfd)(long ufd, void *user_mask, long sizemask) {} | ||
| 2681 | |||
| 2682 | POST_SYSCALL(signalfd)(long res, long ufd, kernel_sigset_t *user_mask, | ||
| 2683 | long sizemask) { | ||
| 2684 | if (res >= 0) { | ||
| 2685 | if (user_mask) POST_WRITE(user_mask, sizemask); | ||
| 2686 | } | ||
| 2687 | } | ||
| 2688 | |||
| 2689 | PRE_SYSCALL(signalfd4)(long ufd, void *user_mask, long sizemask, long flags) {} | ||
| 2690 | |||
| 2691 | POST_SYSCALL(signalfd4)(long res, long ufd, kernel_sigset_t *user_mask, | ||
| 2692 | long sizemask, long flags) { | ||
| 2693 | if (res >= 0) { | ||
| 2694 | if (user_mask) POST_WRITE(user_mask, sizemask); | ||
| 2695 | } | ||
| 2696 | } | ||
| 2697 | |||
| 2698 | PRE_SYSCALL(timerfd_create)(long clockid, long flags) {} | ||
| 2699 | |||
| 2700 | POST_SYSCALL(timerfd_create)(long res, long clockid, long flags) {} | ||
| 2701 | |||
| 2702 | PRE_SYSCALL(timerfd_settime)(long ufd, long flags, const void *utmr, | ||
| 2703 | void *otmr) { | ||
| 2704 | if (utmr) PRE_READ(utmr, struct_itimerspec_sz); | ||
| 2705 | } | ||
| 2706 | |||
| 2707 | POST_SYSCALL(timerfd_settime)(long res, long ufd, long flags, const void *utmr, | ||
| 2708 | void *otmr) { | ||
| 2709 | if (res >= 0) { | ||
| 2710 | if (otmr) POST_WRITE(otmr, struct_itimerspec_sz); | ||
| 2711 | } | ||
| 2712 | } | ||
| 2713 | |||
| 2714 | PRE_SYSCALL(timerfd_gettime)(long ufd, void *otmr) {} | ||
| 2715 | |||
| 2716 | POST_SYSCALL(timerfd_gettime)(long res, long ufd, void *otmr) { | ||
| 2717 | if (res >= 0) { | ||
| 2718 | if (otmr) POST_WRITE(otmr, struct_itimerspec_sz); | ||
| 2719 | } | ||
| 2720 | } | ||
| 2721 | |||
| 2722 | PRE_SYSCALL(eventfd)(long count) {} | ||
| 2723 | |||
| 2724 | POST_SYSCALL(eventfd)(long res, long count) {} | ||
| 2725 | |||
| 2726 | PRE_SYSCALL(eventfd2)(long count, long flags) {} | ||
| 2727 | |||
| 2728 | POST_SYSCALL(eventfd2)(long res, long count, long flags) {} | ||
| 2729 | |||
| 2730 | PRE_SYSCALL(old_readdir)(long arg0, void *arg1, long arg2) {} | ||
| 2731 | |||
| 2732 | POST_SYSCALL(old_readdir)(long res, long arg0, void *arg1, long arg2) { | ||
| 2733 | // Missing definition of 'struct old_linux_dirent'. | ||
| 2734 | } | ||
| 2735 | |||
| 2736 | PRE_SYSCALL(pselect6)(long arg0, __sanitizer___kernel_fd_set *arg1, | ||
| 2737 | __sanitizer___kernel_fd_set *arg2, | ||
| 2738 | __sanitizer___kernel_fd_set *arg3, void *arg4, | ||
| 2739 | void *arg5) {} | ||
| 2740 | |||
| 2741 | POST_SYSCALL(pselect6)(long res, long arg0, __sanitizer___kernel_fd_set *arg1, | ||
| 2742 | __sanitizer___kernel_fd_set *arg2, | ||
| 2743 | __sanitizer___kernel_fd_set *arg3, void *arg4, | ||
| 2744 | void *arg5) { | ||
| 2745 | if (res >= 0) { | ||
| 2746 | if (arg1) POST_WRITE(arg1, sizeof(*arg1)); | ||
| 2747 | if (arg2) POST_WRITE(arg2, sizeof(*arg2)); | ||
| 2748 | if (arg3) POST_WRITE(arg3, sizeof(*arg3)); | ||
| 2749 | if (arg4) POST_WRITE(arg4, struct_timespec_sz); | ||
| 2750 | } | ||
| 2751 | } | ||
| 2752 | |||
| 2753 | PRE_SYSCALL(ppoll)(__sanitizer_pollfd *arg0, long arg1, void *arg2, | ||
| 2754 | const kernel_sigset_t *arg3, long arg4) { | ||
| 2755 | if (arg3) PRE_READ(arg3, arg4); | ||
| 2756 | } | ||
| 2757 | |||
| 2758 | POST_SYSCALL(ppoll)(long res, __sanitizer_pollfd *arg0, long arg1, void *arg2, | ||
| 2759 | const void *arg3, long arg4) { | ||
| 2760 | if (res >= 0) { | ||
| 2761 | if (arg0) POST_WRITE(arg0, sizeof(*arg0)); | ||
| 2762 | if (arg2) POST_WRITE(arg2, struct_timespec_sz); | ||
| 2763 | } | ||
| 2764 | } | ||
| 2765 | |||
| 2766 | PRE_SYSCALL(syncfs)(long fd) {} | ||
| 2767 | |||
| 2768 | POST_SYSCALL(syncfs)(long res, long fd) {} | ||
| 2769 | |||
| 2770 | PRE_SYSCALL(perf_event_open)(__sanitizer_perf_event_attr *attr_uptr, long pid, | ||
| 2771 | long cpu, long group_fd, long flags) { | ||
| 2772 | if (attr_uptr) PRE_READ(attr_uptr, attr_uptr->size); | ||
| 2773 | } | ||
| 2774 | |||
| 2775 | POST_SYSCALL(perf_event_open)(long res, __sanitizer_perf_event_attr *attr_uptr, | ||
| 2776 | long pid, long cpu, long group_fd, long flags) {} | ||
| 2777 | |||
| 2778 | PRE_SYSCALL(mmap_pgoff)(long addr, long len, long prot, long flags, long fd, | ||
| 2779 | long pgoff) {} | ||
| 2780 | |||
| 2781 | POST_SYSCALL(mmap_pgoff)(long res, long addr, long len, long prot, long flags, | ||
| 2782 | long fd, long pgoff) {} | ||
| 2783 | |||
| 2784 | PRE_SYSCALL(old_mmap)(void *arg) {} | ||
| 2785 | |||
| 2786 | POST_SYSCALL(old_mmap)(long res, void *arg) {} | ||
| 2787 | |||
| 2788 | PRE_SYSCALL(name_to_handle_at)(long dfd, const void *name, void *handle, | ||
| 2789 | void *mnt_id, long flag) {} | ||
| 2790 | |||
| 2791 | POST_SYSCALL(name_to_handle_at)(long res, long dfd, const void *name, | ||
| 2792 | void *handle, void *mnt_id, long flag) {} | ||
| 2793 | |||
| 2794 | PRE_SYSCALL(open_by_handle_at)(long mountdirfd, void *handle, long flags) {} | ||
| 2795 | |||
| 2796 | POST_SYSCALL(open_by_handle_at)(long res, long mountdirfd, void *handle, | ||
| 2797 | long flags) {} | ||
| 2798 | |||
| 2799 | PRE_SYSCALL(setns)(long fd, long nstype) {} | ||
| 2800 | |||
| 2801 | POST_SYSCALL(setns)(long res, long fd, long nstype) {} | ||
| 2802 | |||
| 2803 | PRE_SYSCALL(process_vm_readv)(long pid, const __sanitizer_iovec *lvec, | ||
| 2804 | long liovcnt, const void *rvec, long riovcnt, | ||
| 2805 | long flags) {} | ||
| 2806 | |||
| 2807 | POST_SYSCALL(process_vm_readv)(long res, long pid, | ||
| 2808 | const __sanitizer_iovec *lvec, long liovcnt, | ||
| 2809 | const void *rvec, long riovcnt, long flags) { | ||
| 2810 | if (res >= 0) { | ||
| 2811 | if (lvec) kernel_write_iovec(lvec, liovcnt, res); | ||
| 2812 | } | ||
| 2813 | } | ||
| 2814 | |||
| 2815 | PRE_SYSCALL(process_vm_writev)(long pid, const __sanitizer_iovec *lvec, | ||
| 2816 | long liovcnt, const void *rvec, long riovcnt, | ||
| 2817 | long flags) {} | ||
| 2818 | |||
| 2819 | POST_SYSCALL(process_vm_writev)(long res, long pid, | ||
| 2820 | const __sanitizer_iovec *lvec, long liovcnt, | ||
| 2821 | const void *rvec, long riovcnt, long flags) { | ||
| 2822 | if (res >= 0) { | ||
| 2823 | if (lvec) kernel_read_iovec(lvec, liovcnt, res); | ||
| 2824 | } | ||
| 2825 | } | ||
| 2826 | |||
| 2827 | PRE_SYSCALL(fork)() { | ||
| 2828 | COMMON_SYSCALL_PRE_FORK(); | ||
| 2829 | } | ||
| 2830 | |||
| 2831 | POST_SYSCALL(fork)(long res) { | ||
| 2832 | COMMON_SYSCALL_POST_FORK(res); | ||
| 2833 | } | ||
| 2834 | |||
| 2835 | PRE_SYSCALL(vfork)() { | ||
| 2836 | COMMON_SYSCALL_PRE_FORK(); | ||
| 2837 | } | ||
| 2838 | |||
| 2839 | POST_SYSCALL(vfork)(long res) { | ||
| 2840 | COMMON_SYSCALL_POST_FORK(res); | ||
| 2841 | } | ||
| 2842 | |||
| 2843 | PRE_SYSCALL(sigaction)(long signum, const __sanitizer_kernel_sigaction_t *act, | ||
| 2844 | __sanitizer_kernel_sigaction_t *oldact) { | ||
| 2845 | if (act) { | ||
| 2846 | PRE_READ(&act->sigaction, sizeof(act->sigaction)); | ||
| 2847 | PRE_READ(&act->sa_flags, sizeof(act->sa_flags)); | ||
| 2848 | PRE_READ(&act->sa_mask, sizeof(act->sa_mask)); | ||
| 2849 | } | ||
| 2850 | } | ||
| 2851 | |||
| 2852 | POST_SYSCALL(sigaction)(long res, long signum, | ||
| 2853 | const __sanitizer_kernel_sigaction_t *act, | ||
| 2854 | __sanitizer_kernel_sigaction_t *oldact) { | ||
| 2855 | if (res >= 0 && oldact) POST_WRITE(oldact, sizeof(*oldact)); | ||
| 2856 | } | ||
| 2857 | |||
| 2858 | PRE_SYSCALL(rt_sigaction)(long signum, | ||
| 2859 | const __sanitizer_kernel_sigaction_t *act, | ||
| 2860 | __sanitizer_kernel_sigaction_t *oldact, SIZE_T sz) { | ||
| 2861 | if (act) { | ||
| 2862 | PRE_READ(&act->sigaction, sizeof(act->sigaction)); | ||
| 2863 | PRE_READ(&act->sa_flags, sizeof(act->sa_flags)); | ||
| 2864 | PRE_READ(&act->sa_mask, sz); | ||
| 2865 | } | ||
| 2866 | } | ||
| 2867 | |||
| 2868 | POST_SYSCALL(rt_sigaction)(long res, long signum, | ||
| 2869 | const __sanitizer_kernel_sigaction_t *act, | ||
| 2870 | __sanitizer_kernel_sigaction_t *oldact, SIZE_T sz) { | ||
| 2871 | if (res >= 0 && oldact) { | ||
| 2872 | SIZE_T oldact_sz = ((char *)&oldact->sa_mask) - ((char *)oldact) + sz; | ||
| 2873 | POST_WRITE(oldact, oldact_sz); | ||
| 2874 | } | ||
| 2875 | } | ||
| 2876 | |||
| 2877 | PRE_SYSCALL(getrandom)(void *buf, uptr count, long flags) { | ||
| 2878 | if (buf) { | ||
| 2879 | PRE_WRITE(buf, count); | ||
| 2880 | } | ||
| 2881 | } | ||
| 2882 | |||
| 2883 | POST_SYSCALL(getrandom)(long res, void *buf, uptr count, long flags) { | ||
| 2884 | if (res > 0 && buf) { | ||
| 2885 | POST_WRITE(buf, res); | ||
| 2886 | } | ||
| 2887 | } | ||
| 2888 | |||
| 2889 | PRE_SYSCALL(sigaltstack)(const void *ss, void *oss) { | ||
| 2890 | if (ss != nullptr) { | ||
| 2891 | PRE_READ(ss, struct_stack_t_sz); | ||
| 2892 | } | ||
| 2893 | if (oss != nullptr) { | ||
| 2894 | PRE_WRITE(oss, struct_stack_t_sz); | ||
| 2895 | } | ||
| 2896 | } | ||
| 2897 | |||
| 2898 | POST_SYSCALL(sigaltstack)(long res, void *ss, void *oss) { | ||
| 2899 | if (res == 0) { | ||
| 2900 | if (oss != nullptr) { | ||
| 2901 | POST_WRITE(oss, struct_stack_t_sz); | ||
| 2902 | } | ||
| 2903 | } | ||
| 2904 | } | ||
| 2905 | } // extern "C" | ||
| 2906 | |||
| 2907 | #undef PRE_SYSCALL | ||
| 2908 | #undef PRE_READ | ||
| 2909 | #undef PRE_WRITE | ||
| 2910 | #undef POST_SYSCALL | ||
| 2911 | #undef POST_READ | ||
| 2912 | #undef POST_WRITE | ||
| 2913 | |||
| 2914 | #endif // SANITIZER_LINUX | ||
lib/tsan/sanitizer_common/sanitizer_coverage_interface.inc created+33| ... | @@ -0,0 +1,33 @@ | ||
| 1 | //===-- sanitizer_coverage_interface.inc ----------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // Sanitizer Coverage interface list. | ||
| 9 | //===----------------------------------------------------------------------===// | ||
| 10 | INTERFACE_FUNCTION(__sanitizer_cov_dump) | ||
| 11 | INTERFACE_FUNCTION(__sanitizer_cov_reset) | ||
| 12 | INTERFACE_FUNCTION(__sanitizer_dump_coverage) | ||
| 13 | INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage) | ||
| 14 | INTERFACE_WEAK_FUNCTION(__sancov_default_options) | ||
| 15 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp) | ||
| 16 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp1) | ||
| 17 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp2) | ||
| 18 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp4) | ||
| 19 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp8) | ||
| 20 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp1) | ||
| 21 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp2) | ||
| 22 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp4) | ||
| 23 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp8) | ||
| 24 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_div4) | ||
| 25 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_div8) | ||
| 26 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_gep) | ||
| 27 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard) | ||
| 28 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard_init) | ||
| 29 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_indir) | ||
| 30 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_switch) | ||
| 31 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_8bit_counters_init) | ||
| 32 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_bool_flag_init) | ||
| 33 | INTERFACE_WEAK_FUNCTION(__sanitizer_cov_pcs_init) | ||
lib/tsan/sanitizer_common/sanitizer_dbghelp.h created+41| ... | @@ -0,0 +1,41 @@ | ||
| 1 | //===-- sanitizer_dbghelp.h ------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Wrappers for lazy loaded dbghelp.dll. Provides function pointers and a | ||
| 10 | // callback to initialize them. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_SYMBOLIZER_WIN_H | ||
| 15 | #define SANITIZER_SYMBOLIZER_WIN_H | ||
| 16 | |||
| 17 | #if !SANITIZER_WINDOWS | ||
| 18 | #error "sanitizer_dbghelp.h is a Windows-only header" | ||
| 19 | #endif | ||
| 20 | |||
| 21 | #define WIN32_LEAN_AND_MEAN | ||
| 22 | #include <windows.h> | ||
| 23 | #include <dbghelp.h> | ||
| 24 | |||
| 25 | namespace __sanitizer { | ||
| 26 | |||
| 27 | extern decltype(::StackWalk64) *StackWalk64; | ||
| 28 | extern decltype(::SymCleanup) *SymCleanup; | ||
| 29 | extern decltype(::SymFromAddr) *SymFromAddr; | ||
| 30 | extern decltype(::SymFunctionTableAccess64) *SymFunctionTableAccess64; | ||
| 31 | extern decltype(::SymGetLineFromAddr64) *SymGetLineFromAddr64; | ||
| 32 | extern decltype(::SymGetModuleBase64) *SymGetModuleBase64; | ||
| 33 | extern decltype(::SymGetSearchPathW) *SymGetSearchPathW; | ||
| 34 | extern decltype(::SymInitialize) *SymInitialize; | ||
| 35 | extern decltype(::SymSetOptions) *SymSetOptions; | ||
| 36 | extern decltype(::SymSetSearchPathW) *SymSetSearchPathW; | ||
| 37 | extern decltype(::UnDecorateSymbolName) *UnDecorateSymbolName; | ||
| 38 | |||
| 39 | } // namespace __sanitizer | ||
| 40 | |||
| 41 | #endif // SANITIZER_SYMBOLIZER_WIN_H | ||
lib/tsan/sanitizer_common/sanitizer_deadlock_detector.h created+410| ... | @@ -0,0 +1,410 @@ | ||
| 1 | //===-- sanitizer_deadlock_detector.h ---------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer runtime. | ||
| 10 | // The deadlock detector maintains a directed graph of lock acquisitions. | ||
| 11 | // When a lock event happens, the detector checks if the locks already held by | ||
| 12 | // the current thread are reachable from the newly acquired lock. | ||
| 13 | // | ||
| 14 | // The detector can handle only a fixed amount of simultaneously live locks | ||
| 15 | // (a lock is alive if it has been locked at least once and has not been | ||
| 16 | // destroyed). When the maximal number of locks is reached the entire graph | ||
| 17 | // is flushed and the new lock epoch is started. The node ids from the old | ||
| 18 | // epochs can not be used with any of the detector methods except for | ||
| 19 | // nodeBelongsToCurrentEpoch(). | ||
| 20 | // | ||
| 21 | // FIXME: this is work in progress, nothing really works yet. | ||
| 22 | // | ||
| 23 | //===----------------------------------------------------------------------===// | ||
| 24 | |||
| 25 | #ifndef SANITIZER_DEADLOCK_DETECTOR_H | ||
| 26 | #define SANITIZER_DEADLOCK_DETECTOR_H | ||
| 27 | |||
| 28 | #include "sanitizer_bvgraph.h" | ||
| 29 | #include "sanitizer_common.h" | ||
| 30 | |||
| 31 | namespace __sanitizer { | ||
| 32 | |||
| 33 | // Thread-local state for DeadlockDetector. | ||
| 34 | // It contains the locks currently held by the owning thread. | ||
| 35 | template <class BV> | ||
| 36 | class DeadlockDetectorTLS { | ||
| 37 | public: | ||
| 38 | // No CTOR. | ||
| 39 | void clear() { | ||
| 40 | bv_.clear(); | ||
| 41 | epoch_ = 0; | ||
| 42 | n_recursive_locks = 0; | ||
| 43 | n_all_locks_ = 0; | ||
| 44 | } | ||
| 45 | |||
| 46 | bool empty() const { return bv_.empty(); } | ||
| 47 | |||
| 48 | void ensureCurrentEpoch(uptr current_epoch) { | ||
| 49 | if (epoch_ == current_epoch) return; | ||
| 50 | bv_.clear(); | ||
| 51 | epoch_ = current_epoch; | ||
| 52 | n_recursive_locks = 0; | ||
| 53 | n_all_locks_ = 0; | ||
| 54 | } | ||
| 55 | |||
| 56 | uptr getEpoch() const { return epoch_; } | ||
| 57 | |||
| 58 | // Returns true if this is the first (non-recursive) acquisition of this lock. | ||
| 59 | bool addLock(uptr lock_id, uptr current_epoch, u32 stk) { | ||
| 60 | CHECK_EQ(epoch_, current_epoch); | ||
| 61 | if (!bv_.setBit(lock_id)) { | ||
| 62 | // The lock is already held by this thread, it must be recursive. | ||
| 63 | CHECK_LT(n_recursive_locks, ARRAY_SIZE(recursive_locks)); | ||
| 64 | recursive_locks[n_recursive_locks++] = lock_id; | ||
| 65 | return false; | ||
| 66 | } | ||
| 67 | CHECK_LT(n_all_locks_, ARRAY_SIZE(all_locks_with_contexts_)); | ||
| 68 | // lock_id < BV::kSize, can cast to a smaller int. | ||
| 69 | u32 lock_id_short = static_cast<u32>(lock_id); | ||
| 70 | LockWithContext l = {lock_id_short, stk}; | ||
| 71 | all_locks_with_contexts_[n_all_locks_++] = l; | ||
| 72 | return true; | ||
| 73 | } | ||
| 74 | |||
| 75 | void removeLock(uptr lock_id) { | ||
| 76 | if (n_recursive_locks) { | ||
| 77 | for (sptr i = n_recursive_locks - 1; i >= 0; i--) { | ||
| 78 | if (recursive_locks[i] == lock_id) { | ||
| 79 | n_recursive_locks--; | ||
| 80 | Swap(recursive_locks[i], recursive_locks[n_recursive_locks]); | ||
| 81 | return; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | } | ||
| 85 | if (!bv_.clearBit(lock_id)) | ||
| 86 | return; // probably addLock happened before flush | ||
| 87 | if (n_all_locks_) { | ||
| 88 | for (sptr i = n_all_locks_ - 1; i >= 0; i--) { | ||
| 89 | if (all_locks_with_contexts_[i].lock == static_cast<u32>(lock_id)) { | ||
| 90 | Swap(all_locks_with_contexts_[i], | ||
| 91 | all_locks_with_contexts_[n_all_locks_ - 1]); | ||
| 92 | n_all_locks_--; | ||
| 93 | break; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | u32 findLockContext(uptr lock_id) { | ||
| 100 | for (uptr i = 0; i < n_all_locks_; i++) | ||
| 101 | if (all_locks_with_contexts_[i].lock == static_cast<u32>(lock_id)) | ||
| 102 | return all_locks_with_contexts_[i].stk; | ||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | const BV &getLocks(uptr current_epoch) const { | ||
| 107 | CHECK_EQ(epoch_, current_epoch); | ||
| 108 | return bv_; | ||
| 109 | } | ||
| 110 | |||
| 111 | uptr getNumLocks() const { return n_all_locks_; } | ||
| 112 | uptr getLock(uptr idx) const { return all_locks_with_contexts_[idx].lock; } | ||
| 113 | |||
| 114 | private: | ||
| 115 | BV bv_; | ||
| 116 | uptr epoch_; | ||
| 117 | uptr recursive_locks[64]; | ||
| 118 | uptr n_recursive_locks; | ||
| 119 | struct LockWithContext { | ||
| 120 | u32 lock; | ||
| 121 | u32 stk; | ||
| 122 | }; | ||
| 123 | LockWithContext all_locks_with_contexts_[64]; | ||
| 124 | uptr n_all_locks_; | ||
| 125 | }; | ||
| 126 | |||
| 127 | // DeadlockDetector. | ||
| 128 | // For deadlock detection to work we need one global DeadlockDetector object | ||
| 129 | // and one DeadlockDetectorTLS object per evey thread. | ||
| 130 | // This class is not thread safe, all concurrent accesses should be guarded | ||
| 131 | // by an external lock. | ||
| 132 | // Most of the methods of this class are not thread-safe (i.e. should | ||
| 133 | // be protected by an external lock) unless explicitly told otherwise. | ||
| 134 | template <class BV> | ||
| 135 | class DeadlockDetector { | ||
| 136 | public: | ||
| 137 | typedef BV BitVector; | ||
| 138 | |||
| 139 | uptr size() const { return g_.size(); } | ||
| 140 | |||
| 141 | // No CTOR. | ||
| 142 | void clear() { | ||
| 143 | current_epoch_ = 0; | ||
| 144 | available_nodes_.clear(); | ||
| 145 | recycled_nodes_.clear(); | ||
| 146 | g_.clear(); | ||
| 147 | n_edges_ = 0; | ||
| 148 | } | ||
| 149 | |||
| 150 | // Allocate new deadlock detector node. | ||
| 151 | // If we are out of available nodes first try to recycle some. | ||
| 152 | // If there is nothing to recycle, flush the graph and increment the epoch. | ||
| 153 | // Associate 'data' (opaque user's object) with the new node. | ||
| 154 | uptr newNode(uptr data) { | ||
| 155 | if (!available_nodes_.empty()) | ||
| 156 | return getAvailableNode(data); | ||
| 157 | if (!recycled_nodes_.empty()) { | ||
| 158 | for (sptr i = n_edges_ - 1; i >= 0; i--) { | ||
| 159 | if (recycled_nodes_.getBit(edges_[i].from) || | ||
| 160 | recycled_nodes_.getBit(edges_[i].to)) { | ||
| 161 | Swap(edges_[i], edges_[n_edges_ - 1]); | ||
| 162 | n_edges_--; | ||
| 163 | } | ||
| 164 | } | ||
| 165 | CHECK(available_nodes_.empty()); | ||
| 166 | // removeEdgesFrom was called in removeNode. | ||
| 167 | g_.removeEdgesTo(recycled_nodes_); | ||
| 168 | available_nodes_.setUnion(recycled_nodes_); | ||
| 169 | recycled_nodes_.clear(); | ||
| 170 | return getAvailableNode(data); | ||
| 171 | } | ||
| 172 | // We are out of vacant nodes. Flush and increment the current_epoch_. | ||
| 173 | current_epoch_ += size(); | ||
| 174 | recycled_nodes_.clear(); | ||
| 175 | available_nodes_.setAll(); | ||
| 176 | g_.clear(); | ||
| 177 | n_edges_ = 0; | ||
| 178 | return getAvailableNode(data); | ||
| 179 | } | ||
| 180 | |||
| 181 | // Get data associated with the node created by newNode(). | ||
| 182 | uptr getData(uptr node) const { return data_[nodeToIndex(node)]; } | ||
| 183 | |||
| 184 | bool nodeBelongsToCurrentEpoch(uptr node) { | ||
| 185 | return node && (node / size() * size()) == current_epoch_; | ||
| 186 | } | ||
| 187 | |||
| 188 | void removeNode(uptr node) { | ||
| 189 | uptr idx = nodeToIndex(node); | ||
| 190 | CHECK(!available_nodes_.getBit(idx)); | ||
| 191 | CHECK(recycled_nodes_.setBit(idx)); | ||
| 192 | g_.removeEdgesFrom(idx); | ||
| 193 | } | ||
| 194 | |||
| 195 | void ensureCurrentEpoch(DeadlockDetectorTLS<BV> *dtls) { | ||
| 196 | dtls->ensureCurrentEpoch(current_epoch_); | ||
| 197 | } | ||
| 198 | |||
| 199 | // Returns true if there is a cycle in the graph after this lock event. | ||
| 200 | // Ideally should be called before the lock is acquired so that we can | ||
| 201 | // report a deadlock before a real deadlock happens. | ||
| 202 | bool onLockBefore(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) { | ||
| 203 | ensureCurrentEpoch(dtls); | ||
| 204 | uptr cur_idx = nodeToIndex(cur_node); | ||
| 205 | return g_.isReachable(cur_idx, dtls->getLocks(current_epoch_)); | ||
| 206 | } | ||
| 207 | |||
| 208 | u32 findLockContext(DeadlockDetectorTLS<BV> *dtls, uptr node) { | ||
| 209 | return dtls->findLockContext(nodeToIndex(node)); | ||
| 210 | } | ||
| 211 | |||
| 212 | // Add cur_node to the set of locks held currently by dtls. | ||
| 213 | void onLockAfter(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) { | ||
| 214 | ensureCurrentEpoch(dtls); | ||
| 215 | uptr cur_idx = nodeToIndex(cur_node); | ||
| 216 | dtls->addLock(cur_idx, current_epoch_, stk); | ||
| 217 | } | ||
| 218 | |||
| 219 | // Experimental *racy* fast path function. | ||
| 220 | // Returns true if all edges from the currently held locks to cur_node exist. | ||
| 221 | bool hasAllEdges(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) { | ||
| 222 | uptr local_epoch = dtls->getEpoch(); | ||
| 223 | // Read from current_epoch_ is racy. | ||
| 224 | if (cur_node && local_epoch == current_epoch_ && | ||
| 225 | local_epoch == nodeToEpoch(cur_node)) { | ||
| 226 | uptr cur_idx = nodeToIndexUnchecked(cur_node); | ||
| 227 | for (uptr i = 0, n = dtls->getNumLocks(); i < n; i++) { | ||
| 228 | if (!g_.hasEdge(dtls->getLock(i), cur_idx)) | ||
| 229 | return false; | ||
| 230 | } | ||
| 231 | return true; | ||
| 232 | } | ||
| 233 | return false; | ||
| 234 | } | ||
| 235 | |||
| 236 | // Adds edges from currently held locks to cur_node, | ||
| 237 | // returns the number of added edges, and puts the sources of added edges | ||
| 238 | // into added_edges[]. | ||
| 239 | // Should be called before onLockAfter. | ||
| 240 | uptr addEdges(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk, | ||
| 241 | int unique_tid) { | ||
| 242 | ensureCurrentEpoch(dtls); | ||
| 243 | uptr cur_idx = nodeToIndex(cur_node); | ||
| 244 | uptr added_edges[40]; | ||
| 245 | uptr n_added_edges = g_.addEdges(dtls->getLocks(current_epoch_), cur_idx, | ||
| 246 | added_edges, ARRAY_SIZE(added_edges)); | ||
| 247 | for (uptr i = 0; i < n_added_edges; i++) { | ||
| 248 | if (n_edges_ < ARRAY_SIZE(edges_)) { | ||
| 249 | Edge e = {(u16)added_edges[i], (u16)cur_idx, | ||
| 250 | dtls->findLockContext(added_edges[i]), stk, | ||
| 251 | unique_tid}; | ||
| 252 | edges_[n_edges_++] = e; | ||
| 253 | } | ||
| 254 | } | ||
| 255 | return n_added_edges; | ||
| 256 | } | ||
| 257 | |||
| 258 | bool findEdge(uptr from_node, uptr to_node, u32 *stk_from, u32 *stk_to, | ||
| 259 | int *unique_tid) { | ||
| 260 | uptr from_idx = nodeToIndex(from_node); | ||
| 261 | uptr to_idx = nodeToIndex(to_node); | ||
| 262 | for (uptr i = 0; i < n_edges_; i++) { | ||
| 263 | if (edges_[i].from == from_idx && edges_[i].to == to_idx) { | ||
| 264 | *stk_from = edges_[i].stk_from; | ||
| 265 | *stk_to = edges_[i].stk_to; | ||
| 266 | *unique_tid = edges_[i].unique_tid; | ||
| 267 | return true; | ||
| 268 | } | ||
| 269 | } | ||
| 270 | return false; | ||
| 271 | } | ||
| 272 | |||
| 273 | // Test-only function. Handles the before/after lock events, | ||
| 274 | // returns true if there is a cycle. | ||
| 275 | bool onLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) { | ||
| 276 | ensureCurrentEpoch(dtls); | ||
| 277 | bool is_reachable = !isHeld(dtls, cur_node) && onLockBefore(dtls, cur_node); | ||
| 278 | addEdges(dtls, cur_node, stk, 0); | ||
| 279 | onLockAfter(dtls, cur_node, stk); | ||
| 280 | return is_reachable; | ||
| 281 | } | ||
| 282 | |||
| 283 | // Handles the try_lock event, returns false. | ||
| 284 | // When a try_lock event happens (i.e. a try_lock call succeeds) we need | ||
| 285 | // to add this lock to the currently held locks, but we should not try to | ||
| 286 | // change the lock graph or to detect a cycle. We may want to investigate | ||
| 287 | // whether a more aggressive strategy is possible for try_lock. | ||
| 288 | bool onTryLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) { | ||
| 289 | ensureCurrentEpoch(dtls); | ||
| 290 | uptr cur_idx = nodeToIndex(cur_node); | ||
| 291 | dtls->addLock(cur_idx, current_epoch_, stk); | ||
| 292 | return false; | ||
| 293 | } | ||
| 294 | |||
| 295 | // Returns true iff dtls is empty (no locks are currently held) and we can | ||
| 296 | // add the node to the currently held locks w/o chanding the global state. | ||
| 297 | // This operation is thread-safe as it only touches the dtls. | ||
| 298 | bool onFirstLock(DeadlockDetectorTLS<BV> *dtls, uptr node, u32 stk = 0) { | ||
| 299 | if (!dtls->empty()) return false; | ||
| 300 | if (dtls->getEpoch() && dtls->getEpoch() == nodeToEpoch(node)) { | ||
| 301 | dtls->addLock(nodeToIndexUnchecked(node), nodeToEpoch(node), stk); | ||
| 302 | return true; | ||
| 303 | } | ||
| 304 | return false; | ||
| 305 | } | ||
| 306 | |||
| 307 | // Finds a path between the lock 'cur_node' (currently not held in dtls) | ||
| 308 | // and some currently held lock, returns the length of the path | ||
| 309 | // or 0 on failure. | ||
| 310 | uptr findPathToLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, uptr *path, | ||
| 311 | uptr path_size) { | ||
| 312 | tmp_bv_.copyFrom(dtls->getLocks(current_epoch_)); | ||
| 313 | uptr idx = nodeToIndex(cur_node); | ||
| 314 | CHECK(!tmp_bv_.getBit(idx)); | ||
| 315 | uptr res = g_.findShortestPath(idx, tmp_bv_, path, path_size); | ||
| 316 | for (uptr i = 0; i < res; i++) | ||
| 317 | path[i] = indexToNode(path[i]); | ||
| 318 | if (res) | ||
| 319 | CHECK_EQ(path[0], cur_node); | ||
| 320 | return res; | ||
| 321 | } | ||
| 322 | |||
| 323 | // Handle the unlock event. | ||
| 324 | // This operation is thread-safe as it only touches the dtls. | ||
| 325 | void onUnlock(DeadlockDetectorTLS<BV> *dtls, uptr node) { | ||
| 326 | if (dtls->getEpoch() == nodeToEpoch(node)) | ||
| 327 | dtls->removeLock(nodeToIndexUnchecked(node)); | ||
| 328 | } | ||
| 329 | |||
| 330 | // Tries to handle the lock event w/o writing to global state. | ||
| 331 | // Returns true on success. | ||
| 332 | // This operation is thread-safe as it only touches the dtls | ||
| 333 | // (modulo racy nature of hasAllEdges). | ||
| 334 | bool onLockFast(DeadlockDetectorTLS<BV> *dtls, uptr node, u32 stk = 0) { | ||
| 335 | if (hasAllEdges(dtls, node)) { | ||
| 336 | dtls->addLock(nodeToIndexUnchecked(node), nodeToEpoch(node), stk); | ||
| 337 | return true; | ||
| 338 | } | ||
| 339 | return false; | ||
| 340 | } | ||
| 341 | |||
| 342 | bool isHeld(DeadlockDetectorTLS<BV> *dtls, uptr node) const { | ||
| 343 | return dtls->getLocks(current_epoch_).getBit(nodeToIndex(node)); | ||
| 344 | } | ||
| 345 | |||
| 346 | uptr testOnlyGetEpoch() const { return current_epoch_; } | ||
| 347 | bool testOnlyHasEdge(uptr l1, uptr l2) { | ||
| 348 | return g_.hasEdge(nodeToIndex(l1), nodeToIndex(l2)); | ||
| 349 | } | ||
| 350 | // idx1 and idx2 are raw indices to g_, not lock IDs. | ||
| 351 | bool testOnlyHasEdgeRaw(uptr idx1, uptr idx2) { | ||
| 352 | return g_.hasEdge(idx1, idx2); | ||
| 353 | } | ||
| 354 | |||
| 355 | void Print() { | ||
| 356 | for (uptr from = 0; from < size(); from++) | ||
| 357 | for (uptr to = 0; to < size(); to++) | ||
| 358 | if (g_.hasEdge(from, to)) | ||
| 359 | Printf(" %zx => %zx\n", from, to); | ||
| 360 | } | ||
| 361 | |||
| 362 | private: | ||
| 363 | void check_idx(uptr idx) const { CHECK_LT(idx, size()); } | ||
| 364 | |||
| 365 | void check_node(uptr node) const { | ||
| 366 | CHECK_GE(node, size()); | ||
| 367 | CHECK_EQ(current_epoch_, nodeToEpoch(node)); | ||
| 368 | } | ||
| 369 | |||
| 370 | uptr indexToNode(uptr idx) const { | ||
| 371 | check_idx(idx); | ||
| 372 | return idx + current_epoch_; | ||
| 373 | } | ||
| 374 | |||
| 375 | uptr nodeToIndexUnchecked(uptr node) const { return node % size(); } | ||
| 376 | |||
| 377 | uptr nodeToIndex(uptr node) const { | ||
| 378 | check_node(node); | ||
| 379 | return nodeToIndexUnchecked(node); | ||
| 380 | } | ||
| 381 | |||
| 382 | uptr nodeToEpoch(uptr node) const { return node / size() * size(); } | ||
| 383 | |||
| 384 | uptr getAvailableNode(uptr data) { | ||
| 385 | uptr idx = available_nodes_.getAndClearFirstOne(); | ||
| 386 | data_[idx] = data; | ||
| 387 | return indexToNode(idx); | ||
| 388 | } | ||
| 389 | |||
| 390 | struct Edge { | ||
| 391 | u16 from; | ||
| 392 | u16 to; | ||
| 393 | u32 stk_from; | ||
| 394 | u32 stk_to; | ||
| 395 | int unique_tid; | ||
| 396 | }; | ||
| 397 | |||
| 398 | uptr current_epoch_; | ||
| 399 | BV available_nodes_; | ||
| 400 | BV recycled_nodes_; | ||
| 401 | BV tmp_bv_; | ||
| 402 | BVGraph<BV> g_; | ||
| 403 | uptr data_[BV::kSize]; | ||
| 404 | Edge edges_[BV::kSize * 32]; | ||
| 405 | uptr n_edges_; | ||
| 406 | }; | ||
| 407 | |||
| 408 | } // namespace __sanitizer | ||
| 409 | |||
| 410 | #endif // SANITIZER_DEADLOCK_DETECTOR_H | ||
lib/tsan/sanitizer_common/sanitizer_deadlock_detector1.cpp created+194| ... | @@ -0,0 +1,194 @@ | ||
| 1 | //===-- sanitizer_deadlock_detector1.cpp ----------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Deadlock detector implementation based on NxN adjacency bit matrix. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_deadlock_detector_interface.h" | ||
| 14 | #include "sanitizer_deadlock_detector.h" | ||
| 15 | #include "sanitizer_allocator_internal.h" | ||
| 16 | #include "sanitizer_placement_new.h" | ||
| 17 | #include "sanitizer_mutex.h" | ||
| 18 | |||
| 19 | #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1 | ||
| 20 | |||
| 21 | namespace __sanitizer { | ||
| 22 | |||
| 23 | typedef TwoLevelBitVector<> DDBV; // DeadlockDetector's bit vector. | ||
| 24 | |||
| 25 | struct DDPhysicalThread { | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct DDLogicalThread { | ||
| 29 | u64 ctx; | ||
| 30 | DeadlockDetectorTLS<DDBV> dd; | ||
| 31 | DDReport rep; | ||
| 32 | bool report_pending; | ||
| 33 | }; | ||
| 34 | |||
| 35 | struct DD : public DDetector { | ||
| 36 | SpinMutex mtx; | ||
| 37 | DeadlockDetector<DDBV> dd; | ||
| 38 | DDFlags flags; | ||
| 39 | |||
| 40 | explicit DD(const DDFlags *flags); | ||
| 41 | |||
| 42 | DDPhysicalThread *CreatePhysicalThread() override; | ||
| 43 | void DestroyPhysicalThread(DDPhysicalThread *pt) override; | ||
| 44 | |||
| 45 | DDLogicalThread *CreateLogicalThread(u64 ctx) override; | ||
| 46 | void DestroyLogicalThread(DDLogicalThread *lt) override; | ||
| 47 | |||
| 48 | void MutexInit(DDCallback *cb, DDMutex *m) override; | ||
| 49 | void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) override; | ||
| 50 | void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, | ||
| 51 | bool trylock) override; | ||
| 52 | void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) override; | ||
| 53 | void MutexDestroy(DDCallback *cb, DDMutex *m) override; | ||
| 54 | |||
| 55 | DDReport *GetReport(DDCallback *cb) override; | ||
| 56 | |||
| 57 | void MutexEnsureID(DDLogicalThread *lt, DDMutex *m); | ||
| 58 | void ReportDeadlock(DDCallback *cb, DDMutex *m); | ||
| 59 | }; | ||
| 60 | |||
| 61 | DDetector *DDetector::Create(const DDFlags *flags) { | ||
| 62 | (void)flags; | ||
| 63 | void *mem = MmapOrDie(sizeof(DD), "deadlock detector"); | ||
| 64 | return new(mem) DD(flags); | ||
| 65 | } | ||
| 66 | |||
| 67 | DD::DD(const DDFlags *flags) | ||
| 68 | : flags(*flags) { | ||
| 69 | dd.clear(); | ||
| 70 | } | ||
| 71 | |||
| 72 | DDPhysicalThread* DD::CreatePhysicalThread() { | ||
| 73 | return nullptr; | ||
| 74 | } | ||
| 75 | |||
| 76 | void DD::DestroyPhysicalThread(DDPhysicalThread *pt) { | ||
| 77 | } | ||
| 78 | |||
| 79 | DDLogicalThread* DD::CreateLogicalThread(u64 ctx) { | ||
| 80 | DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc(sizeof(*lt)); | ||
| 81 | lt->ctx = ctx; | ||
| 82 | lt->dd.clear(); | ||
| 83 | lt->report_pending = false; | ||
| 84 | return lt; | ||
| 85 | } | ||
| 86 | |||
| 87 | void DD::DestroyLogicalThread(DDLogicalThread *lt) { | ||
| 88 | lt->~DDLogicalThread(); | ||
| 89 | InternalFree(lt); | ||
| 90 | } | ||
| 91 | |||
| 92 | void DD::MutexInit(DDCallback *cb, DDMutex *m) { | ||
| 93 | m->id = 0; | ||
| 94 | m->stk = cb->Unwind(); | ||
| 95 | } | ||
| 96 | |||
| 97 | void DD::MutexEnsureID(DDLogicalThread *lt, DDMutex *m) { | ||
| 98 | if (!dd.nodeBelongsToCurrentEpoch(m->id)) | ||
| 99 | m->id = dd.newNode(reinterpret_cast<uptr>(m)); | ||
| 100 | dd.ensureCurrentEpoch(&lt->dd); | ||
| 101 | } | ||
| 102 | |||
| 103 | void DD::MutexBeforeLock(DDCallback *cb, | ||
| 104 | DDMutex *m, bool wlock) { | ||
| 105 | DDLogicalThread *lt = cb->lt; | ||
| 106 | if (lt->dd.empty()) return; // This will be the first lock held by lt. | ||
| 107 | if (dd.hasAllEdges(&lt->dd, m->id)) return; // We already have all edges. | ||
| 108 | SpinMutexLock lk(&mtx); | ||
| 109 | MutexEnsureID(lt, m); | ||
| 110 | if (dd.isHeld(&lt->dd, m->id)) | ||
| 111 | return; // FIXME: allow this only for recursive locks. | ||
| 112 | if (dd.onLockBefore(&lt->dd, m->id)) { | ||
| 113 | // Actually add this edge now so that we have all the stack traces. | ||
| 114 | dd.addEdges(&lt->dd, m->id, cb->Unwind(), cb->UniqueTid()); | ||
| 115 | ReportDeadlock(cb, m); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | void DD::ReportDeadlock(DDCallback *cb, DDMutex *m) { | ||
| 120 | DDLogicalThread *lt = cb->lt; | ||
| 121 | uptr path[20]; | ||
| 122 | uptr len = dd.findPathToLock(&lt->dd, m->id, path, ARRAY_SIZE(path)); | ||
| 123 | if (len == 0U) { | ||
| 124 | // A cycle of 20+ locks? Well, that's a bit odd... | ||
| 125 | Printf("WARNING: too long mutex cycle found\n"); | ||
| 126 | return; | ||
| 127 | } | ||
| 128 | CHECK_EQ(m->id, path[0]); | ||
| 129 | lt->report_pending = true; | ||
| 130 | len = Min<uptr>(len, DDReport::kMaxLoopSize); | ||
| 131 | DDReport *rep = &lt->rep; | ||
| 132 | rep->n = len; | ||
| 133 | for (uptr i = 0; i < len; i++) { | ||
| 134 | uptr from = path[i]; | ||
| 135 | uptr to = path[(i + 1) % len]; | ||
| 136 | DDMutex *m0 = (DDMutex*)dd.getData(from); | ||
| 137 | DDMutex *m1 = (DDMutex*)dd.getData(to); | ||
| 138 | |||
| 139 | u32 stk_from = -1U, stk_to = -1U; | ||
| 140 | int unique_tid = 0; | ||
| 141 | dd.findEdge(from, to, &stk_from, &stk_to, &unique_tid); | ||
| 142 | // Printf("Edge: %zd=>%zd: %u/%u T%d\n", from, to, stk_from, stk_to, | ||
| 143 | // unique_tid); | ||
| 144 | rep->loop[i].thr_ctx = unique_tid; | ||
| 145 | rep->loop[i].mtx_ctx0 = m0->ctx; | ||
| 146 | rep->loop[i].mtx_ctx1 = m1->ctx; | ||
| 147 | rep->loop[i].stk[0] = stk_to; | ||
| 148 | rep->loop[i].stk[1] = stk_from; | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock) { | ||
| 153 | DDLogicalThread *lt = cb->lt; | ||
| 154 | u32 stk = 0; | ||
| 155 | if (flags.second_deadlock_stack) | ||
| 156 | stk = cb->Unwind(); | ||
| 157 | // Printf("T%p MutexLock: %zx stk %u\n", lt, m->id, stk); | ||
| 158 | if (dd.onFirstLock(&lt->dd, m->id, stk)) | ||
| 159 | return; | ||
| 160 | if (dd.onLockFast(&lt->dd, m->id, stk)) | ||
| 161 | return; | ||
| 162 | |||
| 163 | SpinMutexLock lk(&mtx); | ||
| 164 | MutexEnsureID(lt, m); | ||
| 165 | if (wlock) // Only a recursive rlock may be held. | ||
| 166 | CHECK(!dd.isHeld(&lt->dd, m->id)); | ||
| 167 | if (!trylock) | ||
| 168 | dd.addEdges(&lt->dd, m->id, stk ? stk : cb->Unwind(), cb->UniqueTid()); | ||
| 169 | dd.onLockAfter(&lt->dd, m->id, stk); | ||
| 170 | } | ||
| 171 | |||
| 172 | void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) { | ||
| 173 | // Printf("T%p MutexUnLock: %zx\n", cb->lt, m->id); | ||
| 174 | dd.onUnlock(&cb->lt->dd, m->id); | ||
| 175 | } | ||
| 176 | |||
| 177 | void DD::MutexDestroy(DDCallback *cb, | ||
| 178 | DDMutex *m) { | ||
| 179 | if (!m->id) return; | ||
| 180 | SpinMutexLock lk(&mtx); | ||
| 181 | if (dd.nodeBelongsToCurrentEpoch(m->id)) | ||
| 182 | dd.removeNode(m->id); | ||
| 183 | m->id = 0; | ||
| 184 | } | ||
| 185 | |||
| 186 | DDReport *DD::GetReport(DDCallback *cb) { | ||
| 187 | if (!cb->lt->report_pending) | ||
| 188 | return nullptr; | ||
| 189 | cb->lt->report_pending = false; | ||
| 190 | return &cb->lt->rep; | ||
| 191 | } | ||
| 192 | |||
| 193 | } // namespace __sanitizer | ||
| 194 | #endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1 | ||
lib/tsan/sanitizer_common/sanitizer_deadlock_detector2.cpp created+423| ... | @@ -0,0 +1,423 @@ | ||
| 1 | //===-- sanitizer_deadlock_detector2.cpp ----------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Deadlock detector implementation based on adjacency lists. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_deadlock_detector_interface.h" | ||
| 14 | #include "sanitizer_common.h" | ||
| 15 | #include "sanitizer_allocator_internal.h" | ||
| 16 | #include "sanitizer_placement_new.h" | ||
| 17 | #include "sanitizer_mutex.h" | ||
| 18 | |||
| 19 | #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 2 | ||
| 20 | |||
| 21 | namespace __sanitizer { | ||
| 22 | |||
| 23 | const int kMaxNesting = 64; | ||
| 24 | const u32 kNoId = -1; | ||
| 25 | const u32 kEndId = -2; | ||
| 26 | const int kMaxLink = 8; | ||
| 27 | const int kL1Size = 1024; | ||
| 28 | const int kL2Size = 1024; | ||
| 29 | const int kMaxMutex = kL1Size * kL2Size; | ||
| 30 | |||
| 31 | struct Id { | ||
| 32 | u32 id; | ||
| 33 | u32 seq; | ||
| 34 | |||
| 35 | explicit Id(u32 id = 0, u32 seq = 0) | ||
| 36 | : id(id) | ||
| 37 | , seq(seq) { | ||
| 38 | } | ||
| 39 | }; | ||
| 40 | |||
| 41 | struct Link { | ||
| 42 | u32 id; | ||
| 43 | u32 seq; | ||
| 44 | u32 tid; | ||
| 45 | u32 stk0; | ||
| 46 | u32 stk1; | ||
| 47 | |||
| 48 | explicit Link(u32 id = 0, u32 seq = 0, u32 tid = 0, u32 s0 = 0, u32 s1 = 0) | ||
| 49 | : id(id) | ||
| 50 | , seq(seq) | ||
| 51 | , tid(tid) | ||
| 52 | , stk0(s0) | ||
| 53 | , stk1(s1) { | ||
| 54 | } | ||
| 55 | }; | ||
| 56 | |||
| 57 | struct DDPhysicalThread { | ||
| 58 | DDReport rep; | ||
| 59 | bool report_pending; | ||
| 60 | bool visited[kMaxMutex]; | ||
| 61 | Link pending[kMaxMutex]; | ||
| 62 | Link path[kMaxMutex]; | ||
| 63 | }; | ||
| 64 | |||
| 65 | struct ThreadMutex { | ||
| 66 | u32 id; | ||
| 67 | u32 stk; | ||
| 68 | }; | ||
| 69 | |||
| 70 | struct DDLogicalThread { | ||
| 71 | u64 ctx; | ||
| 72 | ThreadMutex locked[kMaxNesting]; | ||
| 73 | int nlocked; | ||
| 74 | }; | ||
| 75 | |||
| 76 | struct Mutex { | ||
| 77 | StaticSpinMutex mtx; | ||
| 78 | u32 seq; | ||
| 79 | int nlink; | ||
| 80 | Link link[kMaxLink]; | ||
| 81 | }; | ||
| 82 | |||
| 83 | struct DD : public DDetector { | ||
| 84 | explicit DD(const DDFlags *flags); | ||
| 85 | |||
| 86 | DDPhysicalThread* CreatePhysicalThread(); | ||
| 87 | void DestroyPhysicalThread(DDPhysicalThread *pt); | ||
| 88 | |||
| 89 | DDLogicalThread* CreateLogicalThread(u64 ctx); | ||
| 90 | void DestroyLogicalThread(DDLogicalThread *lt); | ||
| 91 | |||
| 92 | void MutexInit(DDCallback *cb, DDMutex *m); | ||
| 93 | void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock); | ||
| 94 | void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, | ||
| 95 | bool trylock); | ||
| 96 | void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock); | ||
| 97 | void MutexDestroy(DDCallback *cb, DDMutex *m); | ||
| 98 | |||
| 99 | DDReport *GetReport(DDCallback *cb); | ||
| 100 | |||
| 101 | void CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt, DDMutex *mtx); | ||
| 102 | void Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath); | ||
| 103 | u32 allocateId(DDCallback *cb); | ||
| 104 | Mutex *getMutex(u32 id); | ||
| 105 | u32 getMutexId(Mutex *m); | ||
| 106 | |||
| 107 | DDFlags flags; | ||
| 108 | |||
| 109 | Mutex* mutex[kL1Size]; | ||
| 110 | |||
| 111 | SpinMutex mtx; | ||
| 112 | InternalMmapVector<u32> free_id; | ||
| 113 | int id_gen = 0; | ||
| 114 | }; | ||
| 115 | |||
| 116 | DDetector *DDetector::Create(const DDFlags *flags) { | ||
| 117 | (void)flags; | ||
| 118 | void *mem = MmapOrDie(sizeof(DD), "deadlock detector"); | ||
| 119 | return new(mem) DD(flags); | ||
| 120 | } | ||
| 121 | |||
| 122 | DD::DD(const DDFlags *flags) : flags(*flags) { free_id.reserve(1024); } | ||
| 123 | |||
| 124 | DDPhysicalThread* DD::CreatePhysicalThread() { | ||
| 125 | DDPhysicalThread *pt = (DDPhysicalThread*)MmapOrDie(sizeof(DDPhysicalThread), | ||
| 126 | "deadlock detector (physical thread)"); | ||
| 127 | return pt; | ||
| 128 | } | ||
| 129 | |||
| 130 | void DD::DestroyPhysicalThread(DDPhysicalThread *pt) { | ||
| 131 | pt->~DDPhysicalThread(); | ||
| 132 | UnmapOrDie(pt, sizeof(DDPhysicalThread)); | ||
| 133 | } | ||
| 134 | |||
| 135 | DDLogicalThread* DD::CreateLogicalThread(u64 ctx) { | ||
| 136 | DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc( | ||
| 137 | sizeof(DDLogicalThread)); | ||
| 138 | lt->ctx = ctx; | ||
| 139 | lt->nlocked = 0; | ||
| 140 | return lt; | ||
| 141 | } | ||
| 142 | |||
| 143 | void DD::DestroyLogicalThread(DDLogicalThread *lt) { | ||
| 144 | lt->~DDLogicalThread(); | ||
| 145 | InternalFree(lt); | ||
| 146 | } | ||
| 147 | |||
| 148 | void DD::MutexInit(DDCallback *cb, DDMutex *m) { | ||
| 149 | VPrintf(2, "#%llu: DD::MutexInit(%p)\n", cb->lt->ctx, m); | ||
| 150 | m->id = kNoId; | ||
| 151 | m->recursion = 0; | ||
| 152 | atomic_store(&m->owner, 0, memory_order_relaxed); | ||
| 153 | } | ||
| 154 | |||
| 155 | Mutex *DD::getMutex(u32 id) { | ||
| 156 | return &mutex[id / kL2Size][id % kL2Size]; | ||
| 157 | } | ||
| 158 | |||
| 159 | u32 DD::getMutexId(Mutex *m) { | ||
| 160 | for (int i = 0; i < kL1Size; i++) { | ||
| 161 | Mutex *tab = mutex[i]; | ||
| 162 | if (tab == 0) | ||
| 163 | break; | ||
| 164 | if (m >= tab && m < tab + kL2Size) | ||
| 165 | return i * kL2Size + (m - tab); | ||
| 166 | } | ||
| 167 | return -1; | ||
| 168 | } | ||
| 169 | |||
| 170 | u32 DD::allocateId(DDCallback *cb) { | ||
| 171 | u32 id = -1; | ||
| 172 | SpinMutexLock l(&mtx); | ||
| 173 | if (free_id.size() > 0) { | ||
| 174 | id = free_id.back(); | ||
| 175 | free_id.pop_back(); | ||
| 176 | } else { | ||
| 177 | CHECK_LT(id_gen, kMaxMutex); | ||
| 178 | if ((id_gen % kL2Size) == 0) { | ||
| 179 | mutex[id_gen / kL2Size] = (Mutex*)MmapOrDie(kL2Size * sizeof(Mutex), | ||
| 180 | "deadlock detector (mutex table)"); | ||
| 181 | } | ||
| 182 | id = id_gen++; | ||
| 183 | } | ||
| 184 | CHECK_LE(id, kMaxMutex); | ||
| 185 | VPrintf(3, "#%llu: DD::allocateId assign id %d\n", cb->lt->ctx, id); | ||
| 186 | return id; | ||
| 187 | } | ||
| 188 | |||
| 189 | void DD::MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) { | ||
| 190 | VPrintf(2, "#%llu: DD::MutexBeforeLock(%p, wlock=%d) nlocked=%d\n", | ||
| 191 | cb->lt->ctx, m, wlock, cb->lt->nlocked); | ||
| 192 | DDPhysicalThread *pt = cb->pt; | ||
| 193 | DDLogicalThread *lt = cb->lt; | ||
| 194 | |||
| 195 | uptr owner = atomic_load(&m->owner, memory_order_relaxed); | ||
| 196 | if (owner == (uptr)cb->lt) { | ||
| 197 | VPrintf(3, "#%llu: DD::MutexBeforeLock recursive\n", | ||
| 198 | cb->lt->ctx); | ||
| 199 | return; | ||
| 200 | } | ||
| 201 | |||
| 202 | CHECK_LE(lt->nlocked, kMaxNesting); | ||
| 203 | |||
| 204 | // FIXME(dvyukov): don't allocate id if lt->nlocked == 0? | ||
| 205 | if (m->id == kNoId) | ||
| 206 | m->id = allocateId(cb); | ||
| 207 | |||
| 208 | ThreadMutex *tm = &lt->locked[lt->nlocked++]; | ||
| 209 | tm->id = m->id; | ||
| 210 | if (flags.second_deadlock_stack) | ||
| 211 | tm->stk = cb->Unwind(); | ||
| 212 | if (lt->nlocked == 1) { | ||
| 213 | VPrintf(3, "#%llu: DD::MutexBeforeLock first mutex\n", | ||
| 214 | cb->lt->ctx); | ||
| 215 | return; | ||
| 216 | } | ||
| 217 | |||
| 218 | bool added = false; | ||
| 219 | Mutex *mtx = getMutex(m->id); | ||
| 220 | for (int i = 0; i < lt->nlocked - 1; i++) { | ||
| 221 | u32 id1 = lt->locked[i].id; | ||
| 222 | u32 stk1 = lt->locked[i].stk; | ||
| 223 | Mutex *mtx1 = getMutex(id1); | ||
| 224 | SpinMutexLock l(&mtx1->mtx); | ||
| 225 | if (mtx1->nlink == kMaxLink) { | ||
| 226 | // FIXME(dvyukov): check stale links | ||
| 227 | continue; | ||
| 228 | } | ||
| 229 | int li = 0; | ||
| 230 | for (; li < mtx1->nlink; li++) { | ||
| 231 | Link *link = &mtx1->link[li]; | ||
| 232 | if (link->id == m->id) { | ||
| 233 | if (link->seq != mtx->seq) { | ||
| 234 | link->seq = mtx->seq; | ||
| 235 | link->tid = lt->ctx; | ||
| 236 | link->stk0 = stk1; | ||
| 237 | link->stk1 = cb->Unwind(); | ||
| 238 | added = true; | ||
| 239 | VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n", | ||
| 240 | cb->lt->ctx, getMutexId(mtx1), m->id); | ||
| 241 | } | ||
| 242 | break; | ||
| 243 | } | ||
| 244 | } | ||
| 245 | if (li == mtx1->nlink) { | ||
| 246 | // FIXME(dvyukov): check stale links | ||
| 247 | Link *link = &mtx1->link[mtx1->nlink++]; | ||
| 248 | link->id = m->id; | ||
| 249 | link->seq = mtx->seq; | ||
| 250 | link->tid = lt->ctx; | ||
| 251 | link->stk0 = stk1; | ||
| 252 | link->stk1 = cb->Unwind(); | ||
| 253 | added = true; | ||
| 254 | VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n", | ||
| 255 | cb->lt->ctx, getMutexId(mtx1), m->id); | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | if (!added || mtx->nlink == 0) { | ||
| 260 | VPrintf(3, "#%llu: DD::MutexBeforeLock don't check\n", | ||
| 261 | cb->lt->ctx); | ||
| 262 | return; | ||
| 263 | } | ||
| 264 | |||
| 265 | CycleCheck(pt, lt, m); | ||
| 266 | } | ||
| 267 | |||
| 268 | void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, | ||
| 269 | bool trylock) { | ||
| 270 | VPrintf(2, "#%llu: DD::MutexAfterLock(%p, wlock=%d, try=%d) nlocked=%d\n", | ||
| 271 | cb->lt->ctx, m, wlock, trylock, cb->lt->nlocked); | ||
| 272 | DDLogicalThread *lt = cb->lt; | ||
| 273 | |||
| 274 | uptr owner = atomic_load(&m->owner, memory_order_relaxed); | ||
| 275 | if (owner == (uptr)cb->lt) { | ||
| 276 | VPrintf(3, "#%llu: DD::MutexAfterLock recursive\n", cb->lt->ctx); | ||
| 277 | CHECK(wlock); | ||
| 278 | m->recursion++; | ||
| 279 | return; | ||
| 280 | } | ||
| 281 | CHECK_EQ(owner, 0); | ||
| 282 | if (wlock) { | ||
| 283 | VPrintf(3, "#%llu: DD::MutexAfterLock set owner\n", cb->lt->ctx); | ||
| 284 | CHECK_EQ(m->recursion, 0); | ||
| 285 | m->recursion = 1; | ||
| 286 | atomic_store(&m->owner, (uptr)cb->lt, memory_order_relaxed); | ||
| 287 | } | ||
| 288 | |||
| 289 | if (!trylock) | ||
| 290 | return; | ||
| 291 | |||
| 292 | CHECK_LE(lt->nlocked, kMaxNesting); | ||
| 293 | if (m->id == kNoId) | ||
| 294 | m->id = allocateId(cb); | ||
| 295 | ThreadMutex *tm = &lt->locked[lt->nlocked++]; | ||
| 296 | tm->id = m->id; | ||
| 297 | if (flags.second_deadlock_stack) | ||
| 298 | tm->stk = cb->Unwind(); | ||
| 299 | } | ||
| 300 | |||
| 301 | void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) { | ||
| 302 | VPrintf(2, "#%llu: DD::MutexBeforeUnlock(%p, wlock=%d) nlocked=%d\n", | ||
| 303 | cb->lt->ctx, m, wlock, cb->lt->nlocked); | ||
| 304 | DDLogicalThread *lt = cb->lt; | ||
| 305 | |||
| 306 | uptr owner = atomic_load(&m->owner, memory_order_relaxed); | ||
| 307 | if (owner == (uptr)cb->lt) { | ||
| 308 | VPrintf(3, "#%llu: DD::MutexBeforeUnlock recursive\n", cb->lt->ctx); | ||
| 309 | if (--m->recursion > 0) | ||
| 310 | return; | ||
| 311 | VPrintf(3, "#%llu: DD::MutexBeforeUnlock reset owner\n", cb->lt->ctx); | ||
| 312 | atomic_store(&m->owner, 0, memory_order_relaxed); | ||
| 313 | } | ||
| 314 | CHECK_NE(m->id, kNoId); | ||
| 315 | int last = lt->nlocked - 1; | ||
| 316 | for (int i = last; i >= 0; i--) { | ||
| 317 | if (cb->lt->locked[i].id == m->id) { | ||
| 318 | lt->locked[i] = lt->locked[last]; | ||
| 319 | lt->nlocked--; | ||
| 320 | break; | ||
| 321 | } | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | void DD::MutexDestroy(DDCallback *cb, DDMutex *m) { | ||
| 326 | VPrintf(2, "#%llu: DD::MutexDestroy(%p)\n", | ||
| 327 | cb->lt->ctx, m); | ||
| 328 | DDLogicalThread *lt = cb->lt; | ||
| 329 | |||
| 330 | if (m->id == kNoId) | ||
| 331 | return; | ||
| 332 | |||
| 333 | // Remove the mutex from lt->locked if there. | ||
| 334 | int last = lt->nlocked - 1; | ||
| 335 | for (int i = last; i >= 0; i--) { | ||
| 336 | if (lt->locked[i].id == m->id) { | ||
| 337 | lt->locked[i] = lt->locked[last]; | ||
| 338 | lt->nlocked--; | ||
| 339 | break; | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | // Clear and invalidate the mutex descriptor. | ||
| 344 | { | ||
| 345 | Mutex *mtx = getMutex(m->id); | ||
| 346 | SpinMutexLock l(&mtx->mtx); | ||
| 347 | mtx->seq++; | ||
| 348 | mtx->nlink = 0; | ||
| 349 | } | ||
| 350 | |||
| 351 | // Return id to cache. | ||
| 352 | { | ||
| 353 | SpinMutexLock l(&mtx); | ||
| 354 | free_id.push_back(m->id); | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 358 | void DD::CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt, | ||
| 359 | DDMutex *m) { | ||
| 360 | internal_memset(pt->visited, 0, sizeof(pt->visited)); | ||
| 361 | int npath = 0; | ||
| 362 | int npending = 0; | ||
| 363 | { | ||
| 364 | Mutex *mtx = getMutex(m->id); | ||
| 365 | SpinMutexLock l(&mtx->mtx); | ||
| 366 | for (int li = 0; li < mtx->nlink; li++) | ||
| 367 | pt->pending[npending++] = mtx->link[li]; | ||
| 368 | } | ||
| 369 | while (npending > 0) { | ||
| 370 | Link link = pt->pending[--npending]; | ||
| 371 | if (link.id == kEndId) { | ||
| 372 | npath--; | ||
| 373 | continue; | ||
| 374 | } | ||
| 375 | if (pt->visited[link.id]) | ||
| 376 | continue; | ||
| 377 | Mutex *mtx1 = getMutex(link.id); | ||
| 378 | SpinMutexLock l(&mtx1->mtx); | ||
| 379 | if (mtx1->seq != link.seq) | ||
| 380 | continue; | ||
| 381 | pt->visited[link.id] = true; | ||
| 382 | if (mtx1->nlink == 0) | ||
| 383 | continue; | ||
| 384 | pt->path[npath++] = link; | ||
| 385 | pt->pending[npending++] = Link(kEndId); | ||
| 386 | if (link.id == m->id) | ||
| 387 | return Report(pt, lt, npath); // Bingo! | ||
| 388 | for (int li = 0; li < mtx1->nlink; li++) { | ||
| 389 | Link *link1 = &mtx1->link[li]; | ||
| 390 | // Mutex *mtx2 = getMutex(link->id); | ||
| 391 | // FIXME(dvyukov): fast seq check | ||
| 392 | // FIXME(dvyukov): fast nlink != 0 check | ||
| 393 | // FIXME(dvyukov): fast pending check? | ||
| 394 | // FIXME(dvyukov): npending can be larger than kMaxMutex | ||
| 395 | pt->pending[npending++] = *link1; | ||
| 396 | } | ||
| 397 | } | ||
| 398 | } | ||
| 399 | |||
| 400 | void DD::Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath) { | ||
| 401 | DDReport *rep = &pt->rep; | ||
| 402 | rep->n = npath; | ||
| 403 | for (int i = 0; i < npath; i++) { | ||
| 404 | Link *link = &pt->path[i]; | ||
| 405 | Link *link0 = &pt->path[i ? i - 1 : npath - 1]; | ||
| 406 | rep->loop[i].thr_ctx = link->tid; | ||
| 407 | rep->loop[i].mtx_ctx0 = link0->id; | ||
| 408 | rep->loop[i].mtx_ctx1 = link->id; | ||
| 409 | rep->loop[i].stk[0] = flags.second_deadlock_stack ? link->stk0 : 0; | ||
| 410 | rep->loop[i].stk[1] = link->stk1; | ||
| 411 | } | ||
| 412 | pt->report_pending = true; | ||
| 413 | } | ||
| 414 | |||
| 415 | DDReport *DD::GetReport(DDCallback *cb) { | ||
| 416 | if (!cb->pt->report_pending) | ||
| 417 | return 0; | ||
| 418 | cb->pt->report_pending = false; | ||
| 419 | return &cb->pt->rep; | ||
| 420 | } | ||
| 421 | |||
| 422 | } // namespace __sanitizer | ||
| 423 | #endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 2 | ||
lib/tsan/sanitizer_common/sanitizer_deadlock_detector_interface.h created+92| ... | @@ -0,0 +1,92 @@ | ||
| 1 | //===-- sanitizer_deadlock_detector_interface.h -----------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer runtime. | ||
| 10 | // Abstract deadlock detector interface. | ||
| 11 | // FIXME: this is work in progress, nothing really works yet. | ||
| 12 | // | ||
| 13 | //===----------------------------------------------------------------------===// | ||
| 14 | |||
| 15 | #ifndef SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H | ||
| 16 | #define SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H | ||
| 17 | |||
| 18 | #ifndef SANITIZER_DEADLOCK_DETECTOR_VERSION | ||
| 19 | # define SANITIZER_DEADLOCK_DETECTOR_VERSION 1 | ||
| 20 | #endif | ||
| 21 | |||
| 22 | #include "sanitizer_internal_defs.h" | ||
| 23 | #include "sanitizer_atomic.h" | ||
| 24 | |||
| 25 | namespace __sanitizer { | ||
| 26 | |||
| 27 | // dd - deadlock detector. | ||
| 28 | // lt - logical (user) thread. | ||
| 29 | // pt - physical (OS) thread. | ||
| 30 | |||
| 31 | struct DDPhysicalThread; | ||
| 32 | struct DDLogicalThread; | ||
| 33 | |||
| 34 | struct DDMutex { | ||
| 35 | #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1 | ||
| 36 | uptr id; | ||
| 37 | u32 stk; // creation stack | ||
| 38 | #elif SANITIZER_DEADLOCK_DETECTOR_VERSION == 2 | ||
| 39 | u32 id; | ||
| 40 | u32 recursion; | ||
| 41 | atomic_uintptr_t owner; | ||
| 42 | #else | ||
| 43 | # error "BAD SANITIZER_DEADLOCK_DETECTOR_VERSION" | ||
| 44 | #endif | ||
| 45 | u64 ctx; | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct DDFlags { | ||
| 49 | bool second_deadlock_stack; | ||
| 50 | }; | ||
| 51 | |||
| 52 | struct DDReport { | ||
| 53 | enum { kMaxLoopSize = 20 }; | ||
| 54 | int n; // number of entries in loop | ||
| 55 | struct { | ||
| 56 | u64 thr_ctx; // user thread context | ||
| 57 | u64 mtx_ctx0; // user mutex context, start of the edge | ||
| 58 | u64 mtx_ctx1; // user mutex context, end of the edge | ||
| 59 | u32 stk[2]; // stack ids for the edge | ||
| 60 | } loop[kMaxLoopSize]; | ||
| 61 | }; | ||
| 62 | |||
| 63 | struct DDCallback { | ||
| 64 | DDPhysicalThread *pt; | ||
| 65 | DDLogicalThread *lt; | ||
| 66 | |||
| 67 | virtual u32 Unwind() { return 0; } | ||
| 68 | virtual int UniqueTid() { return 0; } | ||
| 69 | }; | ||
| 70 | |||
| 71 | struct DDetector { | ||
| 72 | static DDetector *Create(const DDFlags *flags); | ||
| 73 | |||
| 74 | virtual DDPhysicalThread* CreatePhysicalThread() { return nullptr; } | ||
| 75 | virtual void DestroyPhysicalThread(DDPhysicalThread *pt) {} | ||
| 76 | |||
| 77 | virtual DDLogicalThread* CreateLogicalThread(u64 ctx) { return nullptr; } | ||
| 78 | virtual void DestroyLogicalThread(DDLogicalThread *lt) {} | ||
| 79 | |||
| 80 | virtual void MutexInit(DDCallback *cb, DDMutex *m) {} | ||
| 81 | virtual void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) {} | ||
| 82 | virtual void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, | ||
| 83 | bool trylock) {} | ||
| 84 | virtual void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {} | ||
| 85 | virtual void MutexDestroy(DDCallback *cb, DDMutex *m) {} | ||
| 86 | |||
| 87 | virtual DDReport *GetReport(DDCallback *cb) { return nullptr; } | ||
| 88 | }; | ||
| 89 | |||
| 90 | } // namespace __sanitizer | ||
| 91 | |||
| 92 | #endif // SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H | ||
lib/tsan/sanitizer_common/sanitizer_errno.cpp created+34| ... | @@ -0,0 +1,34 @@ | ||
| 1 | //===-- sanitizer_errno.cpp -------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between sanitizers run-time libraries. | ||
| 10 | // | ||
| 11 | // Defines errno to avoid including errno.h and its dependencies into other | ||
| 12 | // files (e.g. interceptors are not supposed to include any system headers). | ||
| 13 | // | ||
| 14 | //===----------------------------------------------------------------------===// | ||
| 15 | |||
| 16 | #include "sanitizer_errno_codes.h" | ||
| 17 | #include "sanitizer_internal_defs.h" | ||
| 18 | |||
| 19 | #include <errno.h> | ||
| 20 | |||
| 21 | namespace __sanitizer { | ||
| 22 | |||
| 23 | COMPILER_CHECK(errno_ENOMEM == ENOMEM); | ||
| 24 | COMPILER_CHECK(errno_EBUSY == EBUSY); | ||
| 25 | COMPILER_CHECK(errno_EINVAL == EINVAL); | ||
| 26 | |||
| 27 | // EOWNERDEAD is not present in some older platforms. | ||
| 28 | #if defined(EOWNERDEAD) | ||
| 29 | extern const int errno_EOWNERDEAD = EOWNERDEAD; | ||
| 30 | #else | ||
| 31 | extern const int errno_EOWNERDEAD = -1; | ||
| 32 | #endif | ||
| 33 | |||
| 34 | } // namespace __sanitizer | ||
lib/tsan/sanitizer_common/sanitizer_errno.h created+39| ... | @@ -0,0 +1,39 @@ | ||
| 1 | //===-- sanitizer_errno.h ---------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between sanitizers run-time libraries. | ||
| 10 | // | ||
| 11 | // Defines errno to avoid including errno.h and its dependencies into sensitive | ||
| 12 | // files (e.g. interceptors are not supposed to include any system headers). | ||
| 13 | // It's ok to use errno.h directly when your file already depend on other system | ||
| 14 | // includes though. | ||
| 15 | // | ||
| 16 | //===----------------------------------------------------------------------===// | ||
| 17 | |||
| 18 | #ifndef SANITIZER_ERRNO_H | ||
| 19 | #define SANITIZER_ERRNO_H | ||
| 20 | |||
| 21 | #include "sanitizer_errno_codes.h" | ||
| 22 | #include "sanitizer_platform.h" | ||
| 23 | |||
| 24 | #if SANITIZER_FREEBSD || SANITIZER_MAC | ||
| 25 | # define __errno_location __error | ||
| 26 | #elif SANITIZER_ANDROID || SANITIZER_NETBSD || SANITIZER_OPENBSD || \ | ||
| 27 | SANITIZER_RTEMS | ||
| 28 | # define __errno_location __errno | ||
| 29 | #elif SANITIZER_SOLARIS | ||
| 30 | # define __errno_location ___errno | ||
| 31 | #elif SANITIZER_WINDOWS | ||
| 32 | # define __errno_location _errno | ||
| 33 | #endif | ||
| 34 | |||
| 35 | extern "C" int *__errno_location(); | ||
| 36 | |||
| 37 | #define errno (*__errno_location()) | ||
| 38 | |||
| 39 | #endif // SANITIZER_ERRNO_H | ||
lib/tsan/sanitizer_common/sanitizer_errno_codes.h created+33| ... | @@ -0,0 +1,33 @@ | ||
| 1 | //===-- sanitizer_errno_codes.h ---------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between sanitizers run-time libraries. | ||
| 10 | // | ||
| 11 | // Defines errno codes to avoid including errno.h and its dependencies into | ||
| 12 | // sensitive files (e.g. interceptors are not supposed to include any system | ||
| 13 | // headers). | ||
| 14 | // It's ok to use errno.h directly when your file already depend on other system | ||
| 15 | // includes though. | ||
| 16 | // | ||
| 17 | //===----------------------------------------------------------------------===// | ||
| 18 | |||
| 19 | #ifndef SANITIZER_ERRNO_CODES_H | ||
| 20 | #define SANITIZER_ERRNO_CODES_H | ||
| 21 | |||
| 22 | namespace __sanitizer { | ||
| 23 | |||
| 24 | #define errno_ENOMEM 12 | ||
| 25 | #define errno_EBUSY 16 | ||
| 26 | #define errno_EINVAL 22 | ||
| 27 | |||
| 28 | // Those might not present or their value differ on different platforms. | ||
| 29 | extern const int errno_EOWNERDEAD; | ||
| 30 | |||
| 31 | } // namespace __sanitizer | ||
| 32 | |||
| 33 | #endif // SANITIZER_ERRNO_CODES_H | ||
lib/tsan/sanitizer_common/sanitizer_file.cpp created+215| ... | @@ -0,0 +1,215 @@ | ||
| 1 | //===-- sanitizer_file.cpp -----------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===---------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer | ||
| 10 | // run-time libraries. It defines filesystem-related interfaces. This | ||
| 11 | // is separate from sanitizer_common.cpp so that it's simpler to disable | ||
| 12 | // all the filesystem support code for a port that doesn't use it. | ||
| 13 | // | ||
| 14 | //===---------------------------------------------------------------------===// | ||
| 15 | |||
| 16 | #include "sanitizer_platform.h" | ||
| 17 | |||
| 18 | #if !SANITIZER_FUCHSIA | ||
| 19 | |||
| 20 | #include "sanitizer_common.h" | ||
| 21 | #include "sanitizer_file.h" | ||
| 22 | |||
| 23 | namespace __sanitizer { | ||
| 24 | |||
| 25 | void CatastrophicErrorWrite(const char *buffer, uptr length) { | ||
| 26 | WriteToFile(kStderrFd, buffer, length); | ||
| 27 | } | ||
| 28 | |||
| 29 | StaticSpinMutex report_file_mu; | ||
| 30 | ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; | ||
| 31 | |||
| 32 | void RawWrite(const char *buffer) { | ||
| 33 | report_file.Write(buffer, internal_strlen(buffer)); | ||
| 34 | } | ||
| 35 | |||
| 36 | void ReportFile::ReopenIfNecessary() { | ||
| 37 | mu->CheckLocked(); | ||
| 38 | if (fd == kStdoutFd || fd == kStderrFd) return; | ||
| 39 | |||
| 40 | uptr pid = internal_getpid(); | ||
| 41 | // If in tracer, use the parent's file. | ||
| 42 | if (pid == stoptheworld_tracer_pid) | ||
| 43 | pid = stoptheworld_tracer_ppid; | ||
| 44 | if (fd != kInvalidFd) { | ||
| 45 | // If the report file is already opened by the current process, | ||
| 46 | // do nothing. Otherwise the report file was opened by the parent | ||
| 47 | // process, close it now. | ||
| 48 | if (fd_pid == pid) | ||
| 49 | return; | ||
| 50 | else | ||
| 51 | CloseFile(fd); | ||
| 52 | } | ||
| 53 | |||
| 54 | const char *exe_name = GetProcessName(); | ||
| 55 | if (common_flags()->log_exe_name && exe_name) { | ||
| 56 | internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, | ||
| 57 | exe_name, pid); | ||
| 58 | } else { | ||
| 59 | internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); | ||
| 60 | } | ||
| 61 | fd = OpenFile(full_path, WrOnly); | ||
| 62 | if (fd == kInvalidFd) { | ||
| 63 | const char *ErrorMsgPrefix = "ERROR: Can't open file: "; | ||
| 64 | WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); | ||
| 65 | WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); | ||
| 66 | Die(); | ||
| 67 | } | ||
| 68 | fd_pid = pid; | ||
| 69 | } | ||
| 70 | |||
| 71 | void ReportFile::SetReportPath(const char *path) { | ||
| 72 | if (!path) | ||
| 73 | return; | ||
| 74 | uptr len = internal_strlen(path); | ||
| 75 | if (len > sizeof(path_prefix) - 100) { | ||
| 76 | Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", | ||
| 77 | path[0], path[1], path[2], path[3], | ||
| 78 | path[4], path[5], path[6], path[7]); | ||
| 79 | Die(); | ||
| 80 | } | ||
| 81 | |||
| 82 | SpinMutexLock l(mu); | ||
| 83 | if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) | ||
| 84 | CloseFile(fd); | ||
| 85 | fd = kInvalidFd; | ||
| 86 | if (internal_strcmp(path, "stdout") == 0) { | ||
| 87 | fd = kStdoutFd; | ||
| 88 | } else if (internal_strcmp(path, "stderr") == 0) { | ||
| 89 | fd = kStderrFd; | ||
| 90 | } else { | ||
| 91 | internal_snprintf(path_prefix, kMaxPathLength, "%s", path); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, | ||
| 96 | uptr *read_len, uptr max_len, error_t *errno_p) { | ||
| 97 | *buff = nullptr; | ||
| 98 | *buff_size = 0; | ||
| 99 | *read_len = 0; | ||
| 100 | if (!max_len) | ||
| 101 | return true; | ||
| 102 | uptr PageSize = GetPageSizeCached(); | ||
| 103 | uptr kMinFileLen = Min(PageSize, max_len); | ||
| 104 | |||
| 105 | // The files we usually open are not seekable, so try different buffer sizes. | ||
| 106 | for (uptr size = kMinFileLen;; size = Min(size * 2, max_len)) { | ||
| 107 | UnmapOrDie(*buff, *buff_size); | ||
| 108 | *buff = (char*)MmapOrDie(size, __func__); | ||
| 109 | *buff_size = size; | ||
| 110 | fd_t fd = OpenFile(file_name, RdOnly, errno_p); | ||
| 111 | if (fd == kInvalidFd) { | ||
| 112 | UnmapOrDie(*buff, *buff_size); | ||
| 113 | return false; | ||
| 114 | } | ||
| 115 | *read_len = 0; | ||
| 116 | // Read up to one page at a time. | ||
| 117 | bool reached_eof = false; | ||
| 118 | while (*read_len < size) { | ||
| 119 | uptr just_read; | ||
| 120 | if (!ReadFromFile(fd, *buff + *read_len, size - *read_len, &just_read, | ||
| 121 | errno_p)) { | ||
| 122 | UnmapOrDie(*buff, *buff_size); | ||
| 123 | CloseFile(fd); | ||
| 124 | return false; | ||
| 125 | } | ||
| 126 | *read_len += just_read; | ||
| 127 | if (just_read == 0 || *read_len == max_len) { | ||
| 128 | reached_eof = true; | ||
| 129 | break; | ||
| 130 | } | ||
| 131 | } | ||
| 132 | CloseFile(fd); | ||
| 133 | if (reached_eof) // We've read the whole file. | ||
| 134 | break; | ||
| 135 | } | ||
| 136 | return true; | ||
| 137 | } | ||
| 138 | |||
| 139 | bool ReadFileToVector(const char *file_name, | ||
| 140 | InternalMmapVectorNoCtor<char> *buff, uptr max_len, | ||
| 141 | error_t *errno_p) { | ||
| 142 | buff->clear(); | ||
| 143 | if (!max_len) | ||
| 144 | return true; | ||
| 145 | uptr PageSize = GetPageSizeCached(); | ||
| 146 | fd_t fd = OpenFile(file_name, RdOnly, errno_p); | ||
| 147 | if (fd == kInvalidFd) | ||
| 148 | return false; | ||
| 149 | uptr read_len = 0; | ||
| 150 | while (read_len < max_len) { | ||
| 151 | if (read_len >= buff->size()) | ||
| 152 | buff->resize(Min(Max(PageSize, read_len * 2), max_len)); | ||
| 153 | CHECK_LT(read_len, buff->size()); | ||
| 154 | CHECK_LE(buff->size(), max_len); | ||
| 155 | uptr just_read; | ||
| 156 | if (!ReadFromFile(fd, buff->data() + read_len, buff->size() - read_len, | ||
| 157 | &just_read, errno_p)) { | ||
| 158 | CloseFile(fd); | ||
| 159 | return false; | ||
| 160 | } | ||
| 161 | read_len += just_read; | ||
| 162 | if (!just_read) | ||
| 163 | break; | ||
| 164 | } | ||
| 165 | CloseFile(fd); | ||
| 166 | buff->resize(read_len); | ||
| 167 | return true; | ||
| 168 | } | ||
| 169 | |||
| 170 | static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; | ||
| 171 | |||
| 172 | char *FindPathToBinary(const char *name) { | ||
| 173 | if (FileExists(name)) { | ||
| 174 | return internal_strdup(name); | ||
| 175 | } | ||
| 176 | |||
| 177 | const char *path = GetEnv("PATH"); | ||
| 178 | if (!path) | ||
| 179 | return nullptr; | ||
| 180 | uptr name_len = internal_strlen(name); | ||
| 181 | InternalMmapVector<char> buffer(kMaxPathLength); | ||
| 182 | const char *beg = path; | ||
| 183 | while (true) { | ||
| 184 | const char *end = internal_strchrnul(beg, kPathSeparator); | ||
| 185 | uptr prefix_len = end - beg; | ||
| 186 | if (prefix_len + name_len + 2 <= kMaxPathLength) { | ||
| 187 | internal_memcpy(buffer.data(), beg, prefix_len); | ||
| 188 | buffer[prefix_len] = '/'; | ||
| 189 | internal_memcpy(&buffer[prefix_len + 1], name, name_len); | ||
| 190 | buffer[prefix_len + 1 + name_len] = '\0'; | ||
| 191 | if (FileExists(buffer.data())) | ||
| 192 | return internal_strdup(buffer.data()); | ||
| 193 | } | ||
| 194 | if (*end == '\0') break; | ||
| 195 | beg = end + 1; | ||
| 196 | } | ||
| 197 | return nullptr; | ||
| 198 | } | ||
| 199 | |||
| 200 | } // namespace __sanitizer | ||
| 201 | |||
| 202 | using namespace __sanitizer; | ||
| 203 | |||
| 204 | extern "C" { | ||
| 205 | void __sanitizer_set_report_path(const char *path) { | ||
| 206 | report_file.SetReportPath(path); | ||
| 207 | } | ||
| 208 | |||
| 209 | void __sanitizer_set_report_fd(void *fd) { | ||
| 210 | report_file.fd = (fd_t)reinterpret_cast<uptr>(fd); | ||
| 211 | report_file.fd_pid = internal_getpid(); | ||
| 212 | } | ||
| 213 | } // extern "C" | ||
| 214 | |||
| 215 | #endif // !SANITIZER_FUCHSIA | ||
lib/tsan/sanitizer_common/sanitizer_file.h created+106| ... | @@ -0,0 +1,106 @@ | ||
| 1 | //===-- sanitizer_file.h ---------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===---------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between run-time libraries of sanitizers. | ||
| 10 | // It declares filesystem-related interfaces. This is separate from | ||
| 11 | // sanitizer_common.h so that it's simpler to disable all the filesystem | ||
| 12 | // support code for a port that doesn't use it. | ||
| 13 | // | ||
| 14 | //===---------------------------------------------------------------------===// | ||
| 15 | #ifndef SANITIZER_FILE_H | ||
| 16 | #define SANITIZER_FILE_H | ||
| 17 | |||
| 18 | #include "sanitizer_interface_internal.h" | ||
| 19 | #include "sanitizer_internal_defs.h" | ||
| 20 | #include "sanitizer_libc.h" | ||
| 21 | #include "sanitizer_mutex.h" | ||
| 22 | |||
| 23 | namespace __sanitizer { | ||
| 24 | |||
| 25 | struct ReportFile { | ||
| 26 | void Write(const char *buffer, uptr length); | ||
| 27 | bool SupportsColors(); | ||
| 28 | void SetReportPath(const char *path); | ||
| 29 | |||
| 30 | // Don't use fields directly. They are only declared public to allow | ||
| 31 | // aggregate initialization. | ||
| 32 | |||
| 33 | // Protects fields below. | ||
| 34 | StaticSpinMutex *mu; | ||
| 35 | // Opened file descriptor. Defaults to stderr. It may be equal to | ||
| 36 | // kInvalidFd, in which case new file will be opened when necessary. | ||
| 37 | fd_t fd; | ||
| 38 | // Path prefix of report file, set via __sanitizer_set_report_path. | ||
| 39 | char path_prefix[kMaxPathLength]; | ||
| 40 | // Full path to report, obtained as <path_prefix>.PID | ||
| 41 | char full_path[kMaxPathLength]; | ||
| 42 | // PID of the process that opened fd. If a fork() occurs, | ||
| 43 | // the PID of child will be different from fd_pid. | ||
| 44 | uptr fd_pid; | ||
| 45 | |||
| 46 | private: | ||
| 47 | void ReopenIfNecessary(); | ||
| 48 | }; | ||
| 49 | extern ReportFile report_file; | ||
| 50 | |||
| 51 | enum FileAccessMode { | ||
| 52 | RdOnly, | ||
| 53 | WrOnly, | ||
| 54 | RdWr | ||
| 55 | }; | ||
| 56 | |||
| 57 | // Returns kInvalidFd on error. | ||
| 58 | fd_t OpenFile(const char *filename, FileAccessMode mode, | ||
| 59 | error_t *errno_p = nullptr); | ||
| 60 | void CloseFile(fd_t); | ||
| 61 | |||
| 62 | // Return true on success, false on error. | ||
| 63 | bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, | ||
| 64 | uptr *bytes_read = nullptr, error_t *error_p = nullptr); | ||
| 65 | bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, | ||
| 66 | uptr *bytes_written = nullptr, error_t *error_p = nullptr); | ||
| 67 | |||
| 68 | // Scoped file handle closer. | ||
| 69 | struct FileCloser { | ||
| 70 | explicit FileCloser(fd_t fd) : fd(fd) {} | ||
| 71 | ~FileCloser() { CloseFile(fd); } | ||
| 72 | fd_t fd; | ||
| 73 | }; | ||
| 74 | |||
| 75 | bool SupportsColoredOutput(fd_t fd); | ||
| 76 | |||
| 77 | // OS | ||
| 78 | const char *GetPwd(); | ||
| 79 | bool FileExists(const char *filename); | ||
| 80 | char *FindPathToBinary(const char *name); | ||
| 81 | bool IsPathSeparator(const char c); | ||
| 82 | bool IsAbsolutePath(const char *path); | ||
| 83 | // Starts a subprocess and returs its pid. | ||
| 84 | // If *_fd parameters are not kInvalidFd their corresponding input/output | ||
| 85 | // streams will be redirect to the file. The files will always be closed | ||
| 86 | // in parent process even in case of an error. | ||
| 87 | // The child process will close all fds after STDERR_FILENO | ||
| 88 | // before passing control to a program. | ||
| 89 | pid_t StartSubprocess(const char *filename, const char *const argv[], | ||
| 90 | const char *const envp[], fd_t stdin_fd = kInvalidFd, | ||
| 91 | fd_t stdout_fd = kInvalidFd, fd_t stderr_fd = kInvalidFd); | ||
| 92 | // Checks if specified process is still running | ||
| 93 | bool IsProcessRunning(pid_t pid); | ||
| 94 | // Waits for the process to finish and returns its exit code. | ||
| 95 | // Returns -1 in case of an error. | ||
| 96 | int WaitForProcess(pid_t pid); | ||
| 97 | |||
| 98 | // Maps given file to virtual memory, and returns pointer to it | ||
| 99 | // (or NULL if mapping fails). Stores the size of mmaped region | ||
| 100 | // in '*buff_size'. | ||
| 101 | void *MapFileToMemory(const char *file_name, uptr *buff_size); | ||
| 102 | void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset); | ||
| 103 | |||
| 104 | } // namespace __sanitizer | ||
| 105 | |||
| 106 | #endif // SANITIZER_FILE_H | ||
lib/tsan/sanitizer_common/sanitizer_flag_parser.cpp created+191| ... | @@ -0,0 +1,191 @@ | ||
| 1 | //===-- sanitizer_flag_parser.cpp -----------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer/AddressSanitizer runtime. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_flag_parser.h" | ||
| 14 | |||
| 15 | #include "sanitizer_common.h" | ||
| 16 | #include "sanitizer_libc.h" | ||
| 17 | #include "sanitizer_flags.h" | ||
| 18 | #include "sanitizer_flag_parser.h" | ||
| 19 | |||
| 20 | namespace __sanitizer { | ||
| 21 | |||
| 22 | LowLevelAllocator FlagParser::Alloc; | ||
| 23 | |||
| 24 | class UnknownFlags { | ||
| 25 | static const int kMaxUnknownFlags = 20; | ||
| 26 | const char *unknown_flags_[kMaxUnknownFlags]; | ||
| 27 | int n_unknown_flags_; | ||
| 28 | |||
| 29 | public: | ||
| 30 | void Add(const char *name) { | ||
| 31 | CHECK_LT(n_unknown_flags_, kMaxUnknownFlags); | ||
| 32 | unknown_flags_[n_unknown_flags_++] = name; | ||
| 33 | } | ||
| 34 | |||
| 35 | void Report() { | ||
| 36 | if (!n_unknown_flags_) return; | ||
| 37 | Printf("WARNING: found %d unrecognized flag(s):\n", n_unknown_flags_); | ||
| 38 | for (int i = 0; i < n_unknown_flags_; ++i) | ||
| 39 | Printf(" %s\n", unknown_flags_[i]); | ||
| 40 | n_unknown_flags_ = 0; | ||
| 41 | } | ||
| 42 | }; | ||
| 43 | |||
| 44 | UnknownFlags unknown_flags; | ||
| 45 | |||
| 46 | void ReportUnrecognizedFlags() { | ||
| 47 | unknown_flags.Report(); | ||
| 48 | } | ||
| 49 | |||
| 50 | char *FlagParser::ll_strndup(const char *s, uptr n) { | ||
| 51 | uptr len = internal_strnlen(s, n); | ||
| 52 | char *s2 = (char*)Alloc.Allocate(len + 1); | ||
| 53 | internal_memcpy(s2, s, len); | ||
| 54 | s2[len] = 0; | ||
| 55 | return s2; | ||
| 56 | } | ||
| 57 | |||
| 58 | void FlagParser::PrintFlagDescriptions() { | ||
| 59 | char buffer[128]; | ||
| 60 | buffer[sizeof(buffer) - 1] = '\0'; | ||
| 61 | Printf("Available flags for %s:\n", SanitizerToolName); | ||
| 62 | for (int i = 0; i < n_flags_; ++i) { | ||
| 63 | bool truncated = !(flags_[i].handler->Format(buffer, sizeof(buffer))); | ||
| 64 | CHECK_EQ(buffer[sizeof(buffer) - 1], '\0'); | ||
| 65 | const char *truncation_str = truncated ? " Truncated" : ""; | ||
| 66 | Printf("\t%s\n\t\t- %s (Current Value%s: %s)\n", flags_[i].name, | ||
| 67 | flags_[i].desc, truncation_str, buffer); | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | void FlagParser::fatal_error(const char *err) { | ||
| 72 | Printf("%s: ERROR: %s\n", SanitizerToolName, err); | ||
| 73 | Die(); | ||
| 74 | } | ||
| 75 | |||
| 76 | bool FlagParser::is_space(char c) { | ||
| 77 | return c == ' ' || c == ',' || c == ':' || c == '\n' || c == '\t' || | ||
| 78 | c == '\r'; | ||
| 79 | } | ||
| 80 | |||
| 81 | void FlagParser::skip_whitespace() { | ||
| 82 | while (is_space(buf_[pos_])) ++pos_; | ||
| 83 | } | ||
| 84 | |||
| 85 | void FlagParser::parse_flag(const char *env_option_name) { | ||
| 86 | uptr name_start = pos_; | ||
| 87 | while (buf_[pos_] != 0 && buf_[pos_] != '=' && !is_space(buf_[pos_])) ++pos_; | ||
| 88 | if (buf_[pos_] != '=') { | ||
| 89 | if (env_option_name) { | ||
| 90 | Printf("%s: ERROR: expected '=' in %s\n", SanitizerToolName, | ||
| 91 | env_option_name); | ||
| 92 | Die(); | ||
| 93 | } else { | ||
| 94 | fatal_error("expected '='"); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | char *name = ll_strndup(buf_ + name_start, pos_ - name_start); | ||
| 98 | |||
| 99 | uptr value_start = ++pos_; | ||
| 100 | char *value; | ||
| 101 | if (buf_[pos_] == '\'' || buf_[pos_] == '"') { | ||
| 102 | char quote = buf_[pos_++]; | ||
| 103 | while (buf_[pos_] != 0 && buf_[pos_] != quote) ++pos_; | ||
| 104 | if (buf_[pos_] == 0) fatal_error("unterminated string"); | ||
| 105 | value = ll_strndup(buf_ + value_start + 1, pos_ - value_start - 1); | ||
| 106 | ++pos_; // consume the closing quote | ||
| 107 | } else { | ||
| 108 | while (buf_[pos_] != 0 && !is_space(buf_[pos_])) ++pos_; | ||
| 109 | if (buf_[pos_] != 0 && !is_space(buf_[pos_])) | ||
| 110 | fatal_error("expected separator or eol"); | ||
| 111 | value = ll_strndup(buf_ + value_start, pos_ - value_start); | ||
| 112 | } | ||
| 113 | |||
| 114 | bool res = run_handler(name, value); | ||
| 115 | if (!res) fatal_error("Flag parsing failed."); | ||
| 116 | } | ||
| 117 | |||
| 118 | void FlagParser::parse_flags(const char *env_option_name) { | ||
| 119 | while (true) { | ||
| 120 | skip_whitespace(); | ||
| 121 | if (buf_[pos_] == 0) break; | ||
| 122 | parse_flag(env_option_name); | ||
| 123 | } | ||
| 124 | |||
| 125 | // Do a sanity check for certain flags. | ||
| 126 | if (common_flags_dont_use.malloc_context_size < 1) | ||
| 127 | common_flags_dont_use.malloc_context_size = 1; | ||
| 128 | } | ||
| 129 | |||
| 130 | void FlagParser::ParseStringFromEnv(const char *env_name) { | ||
| 131 | const char *env = GetEnv(env_name); | ||
| 132 | VPrintf(1, "%s: %s\n", env_name, env ? env : "<empty>"); | ||
| 133 | ParseString(env, env_name); | ||
| 134 | } | ||
| 135 | |||
| 136 | void FlagParser::ParseString(const char *s, const char *env_option_name) { | ||
| 137 | if (!s) return; | ||
| 138 | // Backup current parser state to allow nested ParseString() calls. | ||
| 139 | const char *old_buf_ = buf_; | ||
| 140 | uptr old_pos_ = pos_; | ||
| 141 | buf_ = s; | ||
| 142 | pos_ = 0; | ||
| 143 | |||
| 144 | parse_flags(env_option_name); | ||
| 145 | |||
| 146 | buf_ = old_buf_; | ||
| 147 | pos_ = old_pos_; | ||
| 148 | } | ||
| 149 | |||
| 150 | bool FlagParser::ParseFile(const char *path, bool ignore_missing) { | ||
| 151 | static const uptr kMaxIncludeSize = 1 << 15; | ||
| 152 | char *data; | ||
| 153 | uptr data_mapped_size; | ||
| 154 | error_t err; | ||
| 155 | uptr len; | ||
| 156 | if (!ReadFileToBuffer(path, &data, &data_mapped_size, &len, | ||
| 157 | Max(kMaxIncludeSize, GetPageSizeCached()), &err)) { | ||
| 158 | if (ignore_missing) | ||
| 159 | return true; | ||
| 160 | Printf("Failed to read options from '%s': error %d\n", path, err); | ||
| 161 | return false; | ||
| 162 | } | ||
| 163 | ParseString(data, path); | ||
| 164 | UnmapOrDie(data, data_mapped_size); | ||
| 165 | return true; | ||
| 166 | } | ||
| 167 | |||
| 168 | bool FlagParser::run_handler(const char *name, const char *value) { | ||
| 169 | for (int i = 0; i < n_flags_; ++i) { | ||
| 170 | if (internal_strcmp(name, flags_[i].name) == 0) | ||
| 171 | return flags_[i].handler->Parse(value); | ||
| 172 | } | ||
| 173 | // Unrecognized flag. This is not a fatal error, we may print a warning later. | ||
| 174 | unknown_flags.Add(name); | ||
| 175 | return true; | ||
| 176 | } | ||
| 177 | |||
| 178 | void FlagParser::RegisterHandler(const char *name, FlagHandlerBase *handler, | ||
| 179 | const char *desc) { | ||
| 180 | CHECK_LT(n_flags_, kMaxFlags); | ||
| 181 | flags_[n_flags_].name = name; | ||
| 182 | flags_[n_flags_].desc = desc; | ||
| 183 | flags_[n_flags_].handler = handler; | ||
| 184 | ++n_flags_; | ||
| 185 | } | ||
| 186 | |||
| 187 | FlagParser::FlagParser() : n_flags_(0), buf_(nullptr), pos_(0) { | ||
| 188 | flags_ = (Flag *)Alloc.Allocate(sizeof(Flag) * kMaxFlags); | ||
| 189 | } | ||
| 190 | |||
| 191 | } // namespace __sanitizer | ||
lib/tsan/sanitizer_common/sanitizer_flag_parser.h created+204| ... | @@ -0,0 +1,204 @@ | ||
| 1 | //===-- sanitizer_flag_parser.h ---------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer/AddressSanitizer runtime. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef SANITIZER_FLAG_REGISTRY_H | ||
| 14 | #define SANITIZER_FLAG_REGISTRY_H | ||
| 15 | |||
| 16 | #include "sanitizer_internal_defs.h" | ||
| 17 | #include "sanitizer_libc.h" | ||
| 18 | #include "sanitizer_common.h" | ||
| 19 | |||
| 20 | namespace __sanitizer { | ||
| 21 | |||
| 22 | class FlagHandlerBase { | ||
| 23 | public: | ||
| 24 | virtual bool Parse(const char *value) { return false; } | ||
| 25 | // Write the C string representation of the current value (truncated to fit) | ||
| 26 | // into the buffer of size `size`. Returns false if truncation occurred and | ||
| 27 | // returns true otherwise. | ||
| 28 | virtual bool Format(char *buffer, uptr size) { | ||
| 29 | if (size > 0) | ||
| 30 | buffer[0] = '\0'; | ||
| 31 | return false; | ||
| 32 | } | ||
| 33 | |||
| 34 | protected: | ||
| 35 | ~FlagHandlerBase() {} | ||
| 36 | |||
| 37 | inline bool FormatString(char *buffer, uptr size, const char *str_to_use) { | ||
| 38 | uptr num_symbols_should_write = | ||
| 39 | internal_snprintf(buffer, size, "%s", str_to_use); | ||
| 40 | return num_symbols_should_write < size; | ||
| 41 | } | ||
| 42 | }; | ||
| 43 | |||
| 44 | template <typename T> | ||
| 45 | class FlagHandler : public FlagHandlerBase { | ||
| 46 | T *t_; | ||
| 47 | |||
| 48 | public: | ||
| 49 | explicit FlagHandler(T *t) : t_(t) {} | ||
| 50 | bool Parse(const char *value) final; | ||
| 51 | bool Format(char *buffer, uptr size) final; | ||
| 52 | }; | ||
| 53 | |||
| 54 | inline bool ParseBool(const char *value, bool *b) { | ||
| 55 | if (internal_strcmp(value, "0") == 0 || | ||
| 56 | internal_strcmp(value, "no") == 0 || | ||
| 57 | internal_strcmp(value, "false") == 0) { | ||
| 58 | *b = false; | ||
| 59 | return true; | ||
| 60 | } | ||
| 61 | if (internal_strcmp(value, "1") == 0 || | ||
| 62 | internal_strcmp(value, "yes") == 0 || | ||
| 63 | internal_strcmp(value, "true") == 0) { | ||
| 64 | *b = true; | ||
| 65 | return true; | ||
| 66 | } | ||
| 67 | return false; | ||
| 68 | } | ||
| 69 | |||
| 70 | template <> | ||
| 71 | inline bool FlagHandler<bool>::Parse(const char *value) { | ||
| 72 | if (ParseBool(value, t_)) return true; | ||
| 73 | Printf("ERROR: Invalid value for bool option: '%s'\n", value); | ||
| 74 | return false; | ||
| 75 | } | ||
| 76 | |||
| 77 | template <> | ||
| 78 | inline bool FlagHandler<bool>::Format(char *buffer, uptr size) { | ||
| 79 | return FormatString(buffer, size, *t_ ? "true" : "false"); | ||
| 80 | } | ||
| 81 | |||
| 82 | template <> | ||
| 83 | inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) { | ||
| 84 | bool b; | ||
| 85 | if (ParseBool(value, &b)) { | ||
| 86 | *t_ = b ? kHandleSignalYes : kHandleSignalNo; | ||
| 87 | return true; | ||
| 88 | } | ||
| 89 | if (internal_strcmp(value, "2") == 0 || | ||
| 90 | internal_strcmp(value, "exclusive") == 0) { | ||
| 91 | *t_ = kHandleSignalExclusive; | ||
| 92 | return true; | ||
| 93 | } | ||
| 94 | Printf("ERROR: Invalid value for signal handler option: '%s'\n", value); | ||
| 95 | return false; | ||
| 96 | } | ||
| 97 | |||
| 98 | template <> | ||
| 99 | inline bool FlagHandler<HandleSignalMode>::Format(char *buffer, uptr size) { | ||
| 100 | uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_); | ||
| 101 | return num_symbols_should_write < size; | ||
| 102 | } | ||
| 103 | |||
| 104 | template <> | ||
| 105 | inline bool FlagHandler<const char *>::Parse(const char *value) { | ||
| 106 | *t_ = value; | ||
| 107 | return true; | ||
| 108 | } | ||
| 109 | |||
| 110 | template <> | ||
| 111 | inline bool FlagHandler<const char *>::Format(char *buffer, uptr size) { | ||
| 112 | return FormatString(buffer, size, *t_); | ||
| 113 | } | ||
| 114 | |||
| 115 | template <> | ||
| 116 | inline bool FlagHandler<int>::Parse(const char *value) { | ||
| 117 | const char *value_end; | ||
| 118 | *t_ = internal_simple_strtoll(value, &value_end, 10); | ||
| 119 | bool ok = *value_end == 0; | ||
| 120 | if (!ok) Printf("ERROR: Invalid value for int option: '%s'\n", value); | ||
| 121 | return ok; | ||
| 122 | } | ||
| 123 | |||
| 124 | template <> | ||
| 125 | inline bool FlagHandler<int>::Format(char *buffer, uptr size) { | ||
| 126 | uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_); | ||
| 127 | return num_symbols_should_write < size; | ||
| 128 | } | ||
| 129 | |||
| 130 | template <> | ||
| 131 | inline bool FlagHandler<uptr>::Parse(const char *value) { | ||
| 132 | const char *value_end; | ||
| 133 | *t_ = internal_simple_strtoll(value, &value_end, 10); | ||
| 134 | bool ok = *value_end == 0; | ||
| 135 | if (!ok) Printf("ERROR: Invalid value for uptr option: '%s'\n", value); | ||
| 136 | return ok; | ||
| 137 | } | ||
| 138 | |||
| 139 | template <> | ||
| 140 | inline bool FlagHandler<uptr>::Format(char *buffer, uptr size) { | ||
| 141 | uptr num_symbols_should_write = internal_snprintf(buffer, size, "%p", *t_); | ||
| 142 | return num_symbols_should_write < size; | ||
| 143 | } | ||
| 144 | |||
| 145 | template <> | ||
| 146 | inline bool FlagHandler<s64>::Parse(const char *value) { | ||
| 147 | const char *value_end; | ||
| 148 | *t_ = internal_simple_strtoll(value, &value_end, 10); | ||
| 149 | bool ok = *value_end == 0; | ||
| 150 | if (!ok) Printf("ERROR: Invalid value for s64 option: '%s'\n", value); | ||
| 151 | return ok; | ||
| 152 | } | ||
| 153 | |||
| 154 | template <> | ||
| 155 | inline bool FlagHandler<s64>::Format(char *buffer, uptr size) { | ||
| 156 | uptr num_symbols_should_write = internal_snprintf(buffer, size, "%lld", *t_); | ||
| 157 | return num_symbols_should_write < size; | ||
| 158 | } | ||
| 159 | |||
| 160 | class FlagParser { | ||
| 161 | static const int kMaxFlags = 200; | ||
| 162 | struct Flag { | ||
| 163 | const char *name; | ||
| 164 | const char *desc; | ||
| 165 | FlagHandlerBase *handler; | ||
| 166 | } *flags_; | ||
| 167 | int n_flags_; | ||
| 168 | |||
| 169 | const char *buf_; | ||
| 170 | uptr pos_; | ||
| 171 | |||
| 172 | public: | ||
| 173 | FlagParser(); | ||
| 174 | void RegisterHandler(const char *name, FlagHandlerBase *handler, | ||
| 175 | const char *desc); | ||
| 176 | void ParseString(const char *s, const char *env_name = 0); | ||
| 177 | void ParseStringFromEnv(const char *env_name); | ||
| 178 | bool ParseFile(const char *path, bool ignore_missing); | ||
| 179 | void PrintFlagDescriptions(); | ||
| 180 | |||
| 181 | static LowLevelAllocator Alloc; | ||
| 182 | |||
| 183 | private: | ||
| 184 | void fatal_error(const char *err); | ||
| 185 | bool is_space(char c); | ||
| 186 | void skip_whitespace(); | ||
| 187 | void parse_flags(const char *env_option_name); | ||
| 188 | void parse_flag(const char *env_option_name); | ||
| 189 | bool run_handler(const char *name, const char *value); | ||
| 190 | char *ll_strndup(const char *s, uptr n); | ||
| 191 | }; | ||
| 192 | |||
| 193 | template <typename T> | ||
| 194 | static void RegisterFlag(FlagParser *parser, const char *name, const char *desc, | ||
| 195 | T *var) { | ||
| 196 | FlagHandler<T> *fh = new (FlagParser::Alloc) FlagHandler<T>(var); | ||
| 197 | parser->RegisterHandler(name, fh, desc); | ||
| 198 | } | ||
| 199 | |||
| 200 | void ReportUnrecognizedFlags(); | ||
| 201 | |||
| 202 | } // namespace __sanitizer | ||
| 203 | |||
| 204 | #endif // SANITIZER_FLAG_REGISTRY_H | ||
lib/tsan/sanitizer_common/sanitizer_flags.cpp created+129| ... | @@ -0,0 +1,129 @@ | ||
| 1 | //===-- sanitizer_flags.cpp -----------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer/AddressSanitizer runtime. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_flags.h" | ||
| 14 | |||
| 15 | #include "sanitizer_common.h" | ||
| 16 | #include "sanitizer_libc.h" | ||
| 17 | #include "sanitizer_list.h" | ||
| 18 | #include "sanitizer_flag_parser.h" | ||
| 19 | |||
| 20 | namespace __sanitizer { | ||
| 21 | |||
| 22 | CommonFlags common_flags_dont_use; | ||
| 23 | |||
| 24 | void CommonFlags::SetDefaults() { | ||
| 25 | #define COMMON_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; | ||
| 26 | #include "sanitizer_flags.inc" | ||
| 27 | #undef COMMON_FLAG | ||
| 28 | } | ||
| 29 | |||
| 30 | void CommonFlags::CopyFrom(const CommonFlags &other) { | ||
| 31 | internal_memcpy(this, &other, sizeof(*this)); | ||
| 32 | } | ||
| 33 | |||
| 34 | // Copy the string from "s" to "out", making the following substitutions: | ||
| 35 | // %b = binary basename | ||
| 36 | // %p = pid | ||
| 37 | void SubstituteForFlagValue(const char *s, char *out, uptr out_size) { | ||
| 38 | char *out_end = out + out_size; | ||
| 39 | while (*s && out < out_end - 1) { | ||
| 40 | if (s[0] != '%') { | ||
| 41 | *out++ = *s++; | ||
| 42 | continue; | ||
| 43 | } | ||
| 44 | switch (s[1]) { | ||
| 45 | case 'b': { | ||
| 46 | const char *base = GetProcessName(); | ||
| 47 | CHECK(base); | ||
| 48 | while (*base && out < out_end - 1) | ||
| 49 | *out++ = *base++; | ||
| 50 | s += 2; // skip "%b" | ||
| 51 | break; | ||
| 52 | } | ||
| 53 | case 'p': { | ||
| 54 | int pid = internal_getpid(); | ||
| 55 | char buf[32]; | ||
| 56 | char *buf_pos = buf + 32; | ||
| 57 | do { | ||
| 58 | *--buf_pos = (pid % 10) + '0'; | ||
| 59 | pid /= 10; | ||
| 60 | } while (pid); | ||
| 61 | while (buf_pos < buf + 32 && out < out_end - 1) | ||
| 62 | *out++ = *buf_pos++; | ||
| 63 | s += 2; // skip "%p" | ||
| 64 | break; | ||
| 65 | } | ||
| 66 | default: | ||
| 67 | *out++ = *s++; | ||
| 68 | break; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | CHECK(out < out_end - 1); | ||
| 72 | *out = '\0'; | ||
| 73 | } | ||
| 74 | |||
| 75 | class FlagHandlerInclude : public FlagHandlerBase { | ||
| 76 | FlagParser *parser_; | ||
| 77 | bool ignore_missing_; | ||
| 78 | const char *original_path_; | ||
| 79 | |||
| 80 | public: | ||
| 81 | explicit FlagHandlerInclude(FlagParser *parser, bool ignore_missing) | ||
| 82 | : parser_(parser), ignore_missing_(ignore_missing), original_path_("") {} | ||
| 83 | bool Parse(const char *value) final { | ||
| 84 | original_path_ = value; | ||
| 85 | if (internal_strchr(value, '%')) { | ||
| 86 | char *buf = (char *)MmapOrDie(kMaxPathLength, "FlagHandlerInclude"); | ||
| 87 | SubstituteForFlagValue(value, buf, kMaxPathLength); | ||
| 88 | bool res = parser_->ParseFile(buf, ignore_missing_); | ||
| 89 | UnmapOrDie(buf, kMaxPathLength); | ||
| 90 | return res; | ||
| 91 | } | ||
| 92 | return parser_->ParseFile(value, ignore_missing_); | ||
| 93 | } | ||
| 94 | bool Format(char *buffer, uptr size) { | ||
| 95 | // Note `original_path_` isn't actually what's parsed due to `%` | ||
| 96 | // substitutions. Printing the substituted path would require holding onto | ||
| 97 | // mmap'ed memory. | ||
| 98 | return FormatString(buffer, size, original_path_); | ||
| 99 | } | ||
| 100 | }; | ||
| 101 | |||
| 102 | void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) { | ||
| 103 | FlagHandlerInclude *fh_include = new (FlagParser::Alloc) | ||
| 104 | FlagHandlerInclude(parser, /*ignore_missing*/ false); | ||
| 105 | parser->RegisterHandler("include", fh_include, | ||
| 106 | "read more options from the given file"); | ||
| 107 | FlagHandlerInclude *fh_include_if_exists = new (FlagParser::Alloc) | ||
| 108 | FlagHandlerInclude(parser, /*ignore_missing*/ true); | ||
| 109 | parser->RegisterHandler( | ||
| 110 | "include_if_exists", fh_include_if_exists, | ||
| 111 | "read more options from the given file (if it exists)"); | ||
| 112 | } | ||
| 113 | |||
| 114 | void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) { | ||
| 115 | #define COMMON_FLAG(Type, Name, DefaultValue, Description) \ | ||
| 116 | RegisterFlag(parser, #Name, Description, &cf->Name); | ||
| 117 | #include "sanitizer_flags.inc" | ||
| 118 | #undef COMMON_FLAG | ||
| 119 | |||
| 120 | RegisterIncludeFlags(parser, cf); | ||
| 121 | } | ||
| 122 | |||
| 123 | void InitializeCommonFlags(CommonFlags *cf) { | ||
| 124 | // need to record coverage to generate coverage report. | ||
| 125 | cf->coverage |= cf->html_cov_report; | ||
| 126 | SetVerbosity(cf->verbosity); | ||
| 127 | } | ||
| 128 | |||
| 129 | } // namespace __sanitizer | ||
lib/tsan/sanitizer_common/sanitizer_flags.h created+67| ... | @@ -0,0 +1,67 @@ | ||
| 1 | //===-- sanitizer_flags.h ---------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer/AddressSanitizer runtime. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef SANITIZER_FLAGS_H | ||
| 14 | #define SANITIZER_FLAGS_H | ||
| 15 | |||
| 16 | #include "sanitizer_internal_defs.h" | ||
| 17 | |||
| 18 | namespace __sanitizer { | ||
| 19 | |||
| 20 | enum HandleSignalMode { | ||
| 21 | kHandleSignalNo, | ||
| 22 | kHandleSignalYes, | ||
| 23 | kHandleSignalExclusive, | ||
| 24 | }; | ||
| 25 | |||
| 26 | struct CommonFlags { | ||
| 27 | #define COMMON_FLAG(Type, Name, DefaultValue, Description) Type Name; | ||
| 28 | #include "sanitizer_flags.inc" | ||
| 29 | #undef COMMON_FLAG | ||
| 30 | |||
| 31 | void SetDefaults(); | ||
| 32 | void CopyFrom(const CommonFlags &other); | ||
| 33 | }; | ||
| 34 | |||
| 35 | // Functions to get/set global CommonFlags shared by all sanitizer runtimes: | ||
| 36 | extern CommonFlags common_flags_dont_use; | ||
| 37 | inline const CommonFlags *common_flags() { | ||
| 38 | return &common_flags_dont_use; | ||
| 39 | } | ||
| 40 | |||
| 41 | inline void SetCommonFlagsDefaults() { | ||
| 42 | common_flags_dont_use.SetDefaults(); | ||
| 43 | } | ||
| 44 | |||
| 45 | // This function can only be used to setup tool-specific overrides for | ||
| 46 | // CommonFlags defaults. Generally, it should only be used right after | ||
| 47 | // SetCommonFlagsDefaults(), but before ParseCommonFlagsFromString(), and | ||
| 48 | // only during the flags initialization (i.e. before they are used for | ||
| 49 | // the first time). | ||
| 50 | inline void OverrideCommonFlags(const CommonFlags &cf) { | ||
| 51 | common_flags_dont_use.CopyFrom(cf); | ||
| 52 | } | ||
| 53 | |||
| 54 | void SubstituteForFlagValue(const char *s, char *out, uptr out_size); | ||
| 55 | |||
| 56 | class FlagParser; | ||
| 57 | void RegisterCommonFlags(FlagParser *parser, | ||
| 58 | CommonFlags *cf = &common_flags_dont_use); | ||
| 59 | void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf); | ||
| 60 | |||
| 61 | // Should be called after parsing all flags. Sets up common flag values | ||
| 62 | // and perform initializations common to all sanitizers (e.g. setting | ||
| 63 | // verbosity). | ||
| 64 | void InitializeCommonFlags(CommonFlags *cf = &common_flags_dont_use); | ||
| 65 | } // namespace __sanitizer | ||
| 66 | |||
| 67 | #endif // SANITIZER_FLAGS_H | ||
lib/tsan/sanitizer_common/sanitizer_flags.inc created+250| ... | @@ -0,0 +1,250 @@ | ||
| 1 | //===-- sanitizer_flags.h ---------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file describes common flags available in all sanitizers. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef COMMON_FLAG | ||
| 14 | #error "Define COMMON_FLAG prior to including this file!" | ||
| 15 | #endif | ||
| 16 | |||
| 17 | // COMMON_FLAG(Type, Name, DefaultValue, Description) | ||
| 18 | // Supported types: bool, const char *, int, uptr. | ||
| 19 | // Default value must be a compile-time constant. | ||
| 20 | // Description must be a string literal. | ||
| 21 | |||
| 22 | COMMON_FLAG( | ||
| 23 | bool, symbolize, true, | ||
| 24 | "If set, use the online symbolizer from common sanitizer runtime to turn " | ||
| 25 | "virtual addresses to file/line locations.") | ||
| 26 | COMMON_FLAG( | ||
| 27 | const char *, external_symbolizer_path, nullptr, | ||
| 28 | "Path to external symbolizer. If empty, the tool will search $PATH for " | ||
| 29 | "the symbolizer.") | ||
| 30 | COMMON_FLAG( | ||
| 31 | bool, allow_addr2line, false, | ||
| 32 | "If set, allows online symbolizer to run addr2line binary to symbolize " | ||
| 33 | "stack traces (addr2line will only be used if llvm-symbolizer binary is " | ||
| 34 | "unavailable.") | ||
| 35 | COMMON_FLAG(const char *, strip_path_prefix, "", | ||
| 36 | "Strips this prefix from file paths in error reports.") | ||
| 37 | COMMON_FLAG(bool, fast_unwind_on_check, false, | ||
| 38 | "If available, use the fast frame-pointer-based unwinder on " | ||
| 39 | "internal CHECK failures.") | ||
| 40 | COMMON_FLAG(bool, fast_unwind_on_fatal, false, | ||
| 41 | "If available, use the fast frame-pointer-based unwinder on fatal " | ||
| 42 | "errors.") | ||
| 43 | COMMON_FLAG(bool, fast_unwind_on_malloc, true, | ||
| 44 | "If available, use the fast frame-pointer-based unwinder on " | ||
| 45 | "malloc/free.") | ||
| 46 | COMMON_FLAG(bool, handle_ioctl, false, "Intercept and handle ioctl requests.") | ||
| 47 | COMMON_FLAG(int, malloc_context_size, 1, | ||
| 48 | "Max number of stack frames kept for each allocation/deallocation.") | ||
| 49 | COMMON_FLAG( | ||
| 50 | const char *, log_path, "stderr", | ||
| 51 | "Write logs to \"log_path.pid\". The special values are \"stdout\" and " | ||
| 52 | "\"stderr\". The default is \"stderr\".") | ||
| 53 | COMMON_FLAG( | ||
| 54 | bool, log_exe_name, false, | ||
| 55 | "Mention name of executable when reporting error and " | ||
| 56 | "append executable name to logs (as in \"log_path.exe_name.pid\").") | ||
| 57 | COMMON_FLAG( | ||
| 58 | bool, log_to_syslog, (bool)SANITIZER_ANDROID || (bool)SANITIZER_MAC, | ||
| 59 | "Write all sanitizer output to syslog in addition to other means of " | ||
| 60 | "logging.") | ||
| 61 | COMMON_FLAG( | ||
| 62 | int, verbosity, 0, | ||
| 63 | "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).") | ||
| 64 | COMMON_FLAG(bool, strip_env, 1, | ||
| 65 | "Whether to remove the sanitizer from DYLD_INSERT_LIBRARIES to " | ||
| 66 | "avoid passing it to children. Default is true.") | ||
| 67 | COMMON_FLAG(bool, detect_leaks, !SANITIZER_MAC, "Enable memory leak detection.") | ||
| 68 | COMMON_FLAG( | ||
| 69 | bool, leak_check_at_exit, true, | ||
| 70 | "Invoke leak checking in an atexit handler. Has no effect if " | ||
| 71 | "detect_leaks=false, or if __lsan_do_leak_check() is called before the " | ||
| 72 | "handler has a chance to run.") | ||
| 73 | COMMON_FLAG(bool, allocator_may_return_null, false, | ||
| 74 | "If false, the allocator will crash instead of returning 0 on " | ||
| 75 | "out-of-memory.") | ||
| 76 | COMMON_FLAG(bool, print_summary, true, | ||
| 77 | "If false, disable printing error summaries in addition to error " | ||
| 78 | "reports.") | ||
| 79 | COMMON_FLAG(int, print_module_map, 0, | ||
| 80 | "OS X only (0 - don't print, 1 - print only once before process " | ||
| 81 | "exits, 2 - print after each report).") | ||
| 82 | COMMON_FLAG(bool, check_printf, true, "Check printf arguments.") | ||
| 83 | #define COMMON_FLAG_HANDLE_SIGNAL_HELP(signal) \ | ||
| 84 | "Controls custom tool's " #signal " handler (0 - do not registers the " \ | ||
| 85 | "handler, 1 - register the handler and allow user to set own, " \ | ||
| 86 | "2 - registers the handler and block user from changing it). " | ||
| 87 | COMMON_FLAG(HandleSignalMode, handle_segv, kHandleSignalYes, | ||
| 88 | COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGSEGV)) | ||
| 89 | COMMON_FLAG(HandleSignalMode, handle_sigbus, kHandleSignalYes, | ||
| 90 | COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGBUS)) | ||
| 91 | COMMON_FLAG(HandleSignalMode, handle_abort, kHandleSignalNo, | ||
| 92 | COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGABRT)) | ||
| 93 | COMMON_FLAG(HandleSignalMode, handle_sigill, kHandleSignalNo, | ||
| 94 | COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGILL)) | ||
| 95 | COMMON_FLAG(HandleSignalMode, handle_sigtrap, kHandleSignalNo, | ||
| 96 | COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGTRAP)) | ||
| 97 | COMMON_FLAG(HandleSignalMode, handle_sigfpe, kHandleSignalYes, | ||
| 98 | COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGFPE)) | ||
| 99 | #undef COMMON_FLAG_HANDLE_SIGNAL_HELP | ||
| 100 | COMMON_FLAG(bool, allow_user_segv_handler, true, | ||
| 101 | "Deprecated. True has no effect, use handle_sigbus=1. If false, " | ||
| 102 | "handle_*=1 will be upgraded to handle_*=2.") | ||
| 103 | COMMON_FLAG(bool, use_sigaltstack, true, | ||
| 104 | "If set, uses alternate stack for signal handling.") | ||
| 105 | COMMON_FLAG(bool, detect_deadlocks, true, | ||
| 106 | "If set, deadlock detection is enabled.") | ||
| 107 | COMMON_FLAG( | ||
| 108 | uptr, clear_shadow_mmap_threshold, 64 * 1024, | ||
| 109 | "Large shadow regions are zero-filled using mmap(NORESERVE) instead of " | ||
| 110 | "memset(). This is the threshold size in bytes.") | ||
| 111 | COMMON_FLAG(const char *, color, "auto", | ||
| 112 | "Colorize reports: (always|never|auto).") | ||
| 113 | COMMON_FLAG( | ||
| 114 | bool, legacy_pthread_cond, false, | ||
| 115 | "Enables support for dynamic libraries linked with libpthread 2.2.5.") | ||
| 116 | COMMON_FLAG(bool, intercept_tls_get_addr, false, "Intercept __tls_get_addr.") | ||
| 117 | COMMON_FLAG(bool, help, false, "Print the flag descriptions.") | ||
| 118 | COMMON_FLAG(uptr, mmap_limit_mb, 0, | ||
| 119 | "Limit the amount of mmap-ed memory (excluding shadow) in Mb; " | ||
| 120 | "not a user-facing flag, used mosly for testing the tools") | ||
| 121 | COMMON_FLAG(uptr, hard_rss_limit_mb, 0, | ||
| 122 | "Hard RSS limit in Mb." | ||
| 123 | " If non-zero, a background thread is spawned at startup" | ||
| 124 | " which periodically reads RSS and aborts the process if the" | ||
| 125 | " limit is reached") | ||
| 126 | COMMON_FLAG(uptr, soft_rss_limit_mb, 0, | ||
| 127 | "Soft RSS limit in Mb." | ||
| 128 | " If non-zero, a background thread is spawned at startup" | ||
| 129 | " which periodically reads RSS. If the limit is reached" | ||
| 130 | " all subsequent malloc/new calls will fail or return NULL" | ||
| 131 | " (depending on the value of allocator_may_return_null)" | ||
| 132 | " until the RSS goes below the soft limit." | ||
| 133 | " This limit does not affect memory allocations other than" | ||
| 134 | " malloc/new.") | ||
| 135 | COMMON_FLAG(uptr, max_allocation_size_mb, 0, | ||
| 136 | "If non-zero, malloc/new calls larger than this size will return " | ||
| 137 | "nullptr (or crash if allocator_may_return_null=false).") | ||
| 138 | COMMON_FLAG(bool, heap_profile, false, "Experimental heap profiler, asan-only") | ||
| 139 | COMMON_FLAG(s32, allocator_release_to_os_interval_ms, | ||
| 140 | ((bool)SANITIZER_FUCHSIA || (bool)SANITIZER_WINDOWS) ? -1 : 5000, | ||
| 141 | "Only affects a 64-bit allocator. If set, tries to release unused " | ||
| 142 | "memory to the OS, but not more often than this interval (in " | ||
| 143 | "milliseconds). Negative values mean do not attempt to release " | ||
| 144 | "memory to the OS.\n") | ||
| 145 | COMMON_FLAG(bool, can_use_proc_maps_statm, true, | ||
| 146 | "If false, do not attempt to read /proc/maps/statm." | ||
| 147 | " Mostly useful for testing sanitizers.") | ||
| 148 | COMMON_FLAG( | ||
| 149 | bool, coverage, false, | ||
| 150 | "If set, coverage information will be dumped at program shutdown (if the " | ||
| 151 | "coverage instrumentation was enabled at compile time).") | ||
| 152 | COMMON_FLAG(const char *, coverage_dir, ".", | ||
| 153 | "Target directory for coverage dumps. Defaults to the current " | ||
| 154 | "directory.") | ||
| 155 | COMMON_FLAG(bool, full_address_space, false, | ||
| 156 | "Sanitize complete address space; " | ||
| 157 | "by default kernel area on 32-bit platforms will not be sanitized") | ||
| 158 | COMMON_FLAG(bool, print_suppressions, true, | ||
| 159 | "Print matched suppressions at exit.") | ||
| 160 | COMMON_FLAG( | ||
| 161 | bool, disable_coredump, (SANITIZER_WORDSIZE == 64) && !SANITIZER_GO, | ||
| 162 | "Disable core dumping. By default, disable_coredump=1 on 64-bit to avoid" | ||
| 163 | " dumping a 16T+ core file. Ignored on OSes that don't dump core by" | ||
| 164 | " default and for sanitizers that don't reserve lots of virtual memory.") | ||
| 165 | COMMON_FLAG(bool, use_madv_dontdump, true, | ||
| 166 | "If set, instructs kernel to not store the (huge) shadow " | ||
| 167 | "in core file.") | ||
| 168 | COMMON_FLAG(bool, symbolize_inline_frames, true, | ||
| 169 | "Print inlined frames in stacktraces. Defaults to true.") | ||
| 170 | COMMON_FLAG(bool, symbolize_vs_style, false, | ||
| 171 | "Print file locations in Visual Studio style (e.g: " | ||
| 172 | " file(10,42): ...") | ||
| 173 | COMMON_FLAG(int, dedup_token_length, 0, | ||
| 174 | "If positive, after printing a stack trace also print a short " | ||
| 175 | "string token based on this number of frames that will simplify " | ||
| 176 | "deduplication of the reports. " | ||
| 177 | "Example: 'DEDUP_TOKEN: foo-bar-main'. Default is 0.") | ||
| 178 | COMMON_FLAG(const char *, stack_trace_format, "DEFAULT", | ||
| 179 | "Format string used to render stack frames. " | ||
| 180 | "See sanitizer_stacktrace_printer.h for the format description. " | ||
| 181 | "Use DEFAULT to get default format.") | ||
| 182 | COMMON_FLAG(bool, no_huge_pages_for_shadow, true, | ||
| 183 | "If true, the shadow is not allowed to use huge pages. ") | ||
| 184 | COMMON_FLAG(bool, strict_string_checks, false, | ||
| 185 | "If set check that string arguments are properly null-terminated") | ||
| 186 | COMMON_FLAG(bool, intercept_strstr, true, | ||
| 187 | "If set, uses custom wrappers for strstr and strcasestr functions " | ||
| 188 | "to find more errors.") | ||
| 189 | COMMON_FLAG(bool, intercept_strspn, true, | ||
| 190 | "If set, uses custom wrappers for strspn and strcspn function " | ||
| 191 | "to find more errors.") | ||
| 192 | COMMON_FLAG(bool, intercept_strtok, true, | ||
| 193 | "If set, uses a custom wrapper for the strtok function " | ||
| 194 | "to find more errors.") | ||
| 195 | COMMON_FLAG(bool, intercept_strpbrk, true, | ||
| 196 | "If set, uses custom wrappers for strpbrk function " | ||
| 197 | "to find more errors.") | ||
| 198 | COMMON_FLAG(bool, intercept_strlen, true, | ||
| 199 | "If set, uses custom wrappers for strlen and strnlen functions " | ||
| 200 | "to find more errors.") | ||
| 201 | COMMON_FLAG(bool, intercept_strndup, true, | ||
| 202 | "If set, uses custom wrappers for strndup functions " | ||
| 203 | "to find more errors.") | ||
| 204 | COMMON_FLAG(bool, intercept_strchr, true, | ||
| 205 | "If set, uses custom wrappers for strchr, strchrnul, and strrchr " | ||
| 206 | "functions to find more errors.") | ||
| 207 | COMMON_FLAG(bool, intercept_memcmp, true, | ||
| 208 | "If set, uses custom wrappers for memcmp function " | ||
| 209 | "to find more errors.") | ||
| 210 | COMMON_FLAG(bool, strict_memcmp, true, | ||
| 211 | "If true, assume that memcmp(p1, p2, n) always reads n bytes before " | ||
| 212 | "comparing p1 and p2.") | ||
| 213 | COMMON_FLAG(bool, intercept_memmem, true, | ||
| 214 | "If set, uses a wrapper for memmem() to find more errors.") | ||
| 215 | COMMON_FLAG(bool, intercept_intrin, true, | ||
| 216 | "If set, uses custom wrappers for memset/memcpy/memmove " | ||
| 217 | "intrinsics to find more errors.") | ||
| 218 | COMMON_FLAG(bool, intercept_stat, true, | ||
| 219 | "If set, uses custom wrappers for *stat functions " | ||
| 220 | "to find more errors.") | ||
| 221 | COMMON_FLAG(bool, intercept_send, true, | ||
| 222 | "If set, uses custom wrappers for send* functions " | ||
| 223 | "to find more errors.") | ||
| 224 | COMMON_FLAG(bool, decorate_proc_maps, (bool)SANITIZER_ANDROID, | ||
| 225 | "If set, decorate sanitizer mappings in /proc/self/maps with " | ||
| 226 | "user-readable names") | ||
| 227 | COMMON_FLAG(int, exitcode, 1, "Override the program exit status if the tool " | ||
| 228 | "found an error") | ||
| 229 | COMMON_FLAG( | ||
| 230 | bool, abort_on_error, (bool)SANITIZER_ANDROID || (bool)SANITIZER_MAC, | ||
| 231 | "If set, the tool calls abort() instead of _exit() after printing the " | ||
| 232 | "error report.") | ||
| 233 | COMMON_FLAG(bool, suppress_equal_pcs, true, | ||
| 234 | "Deduplicate multiple reports for single source location in " | ||
| 235 | "halt_on_error=false mode (asan only).") | ||
| 236 | COMMON_FLAG(bool, print_cmdline, false, "Print command line on crash " | ||
| 237 | "(asan only).") | ||
| 238 | COMMON_FLAG(bool, html_cov_report, false, "Generate html coverage report.") | ||
| 239 | COMMON_FLAG(const char *, sancov_path, "sancov", "Sancov tool location.") | ||
| 240 | COMMON_FLAG(bool, dump_instruction_bytes, false, | ||
| 241 | "If true, dump 16 bytes starting at the instruction that caused SEGV") | ||
| 242 | COMMON_FLAG(bool, dump_registers, true, | ||
| 243 | "If true, dump values of CPU registers when SEGV happens. Only " | ||
| 244 | "available on OS X for now.") | ||
| 245 | COMMON_FLAG(bool, detect_write_exec, false, | ||
| 246 | "If true, triggers warning when writable-executable pages requests " | ||
| 247 | "are being made") | ||
| 248 | COMMON_FLAG(bool, test_only_emulate_no_memorymap, false, | ||
| 249 | "TEST ONLY fail to read memory mappings to emulate sanitized " | ||
| 250 | "\"init\"") | ||
lib/tsan/sanitizer_common/sanitizer_freebsd.h created+137| ... | @@ -0,0 +1,137 @@ | ||
| 1 | //===-- sanitizer_freebsd.h -------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer runtime. It contains FreeBSD-specific | ||
| 10 | // definitions. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_FREEBSD_H | ||
| 15 | #define SANITIZER_FREEBSD_H | ||
| 16 | |||
| 17 | #include "sanitizer_internal_defs.h" | ||
| 18 | |||
| 19 | // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in | ||
| 20 | // 32-bit mode. | ||
| 21 | #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) | ||
| 22 | #include <osreldate.h> | ||
| 23 | #if __FreeBSD_version <= 902001 // v9.2 | ||
| 24 | #include <link.h> | ||
| 25 | #include <sys/param.h> | ||
| 26 | #include <ucontext.h> | ||
| 27 | |||
| 28 | namespace __sanitizer { | ||
| 29 | |||
| 30 | typedef unsigned long long __xuint64_t; | ||
| 31 | |||
| 32 | typedef __int32_t __xregister_t; | ||
| 33 | |||
| 34 | typedef struct __xmcontext { | ||
| 35 | __xregister_t mc_onstack; | ||
| 36 | __xregister_t mc_gs; | ||
| 37 | __xregister_t mc_fs; | ||
| 38 | __xregister_t mc_es; | ||
| 39 | __xregister_t mc_ds; | ||
| 40 | __xregister_t mc_edi; | ||
| 41 | __xregister_t mc_esi; | ||
| 42 | __xregister_t mc_ebp; | ||
| 43 | __xregister_t mc_isp; | ||
| 44 | __xregister_t mc_ebx; | ||
| 45 | __xregister_t mc_edx; | ||
| 46 | __xregister_t mc_ecx; | ||
| 47 | __xregister_t mc_eax; | ||
| 48 | __xregister_t mc_trapno; | ||
| 49 | __xregister_t mc_err; | ||
| 50 | __xregister_t mc_eip; | ||
| 51 | __xregister_t mc_cs; | ||
| 52 | __xregister_t mc_eflags; | ||
| 53 | __xregister_t mc_esp; | ||
| 54 | __xregister_t mc_ss; | ||
| 55 | |||
| 56 | int mc_len; | ||
| 57 | int mc_fpformat; | ||
| 58 | int mc_ownedfp; | ||
| 59 | __xregister_t mc_flags; | ||
| 60 | |||
| 61 | int mc_fpstate[128] __aligned(16); | ||
| 62 | __xregister_t mc_fsbase; | ||
| 63 | __xregister_t mc_gsbase; | ||
| 64 | __xregister_t mc_xfpustate; | ||
| 65 | __xregister_t mc_xfpustate_len; | ||
| 66 | |||
| 67 | int mc_spare2[4]; | ||
| 68 | } xmcontext_t; | ||
| 69 | |||
| 70 | typedef struct __xucontext { | ||
| 71 | sigset_t uc_sigmask; | ||
| 72 | xmcontext_t uc_mcontext; | ||
| 73 | |||
| 74 | struct __ucontext *uc_link; | ||
| 75 | stack_t uc_stack; | ||
| 76 | int uc_flags; | ||
| 77 | int __spare__[4]; | ||
| 78 | } xucontext_t; | ||
| 79 | |||
| 80 | struct xkinfo_vmentry { | ||
| 81 | int kve_structsize; | ||
| 82 | int kve_type; | ||
| 83 | __xuint64_t kve_start; | ||
| 84 | __xuint64_t kve_end; | ||
| 85 | __xuint64_t kve_offset; | ||
| 86 | __xuint64_t kve_vn_fileid; | ||
| 87 | __uint32_t kve_vn_fsid; | ||
| 88 | int kve_flags; | ||
| 89 | int kve_resident; | ||
| 90 | int kve_private_resident; | ||
| 91 | int kve_protection; | ||
| 92 | int kve_ref_count; | ||
| 93 | int kve_shadow_count; | ||
| 94 | int kve_vn_type; | ||
| 95 | __xuint64_t kve_vn_size; | ||
| 96 | __uint32_t kve_vn_rdev; | ||
| 97 | __uint16_t kve_vn_mode; | ||
| 98 | __uint16_t kve_status; | ||
| 99 | int _kve_ispare[12]; | ||
| 100 | char kve_path[PATH_MAX]; | ||
| 101 | }; | ||
| 102 | |||
| 103 | typedef struct { | ||
| 104 | __uint32_t p_type; | ||
| 105 | __uint32_t p_offset; | ||
| 106 | __uint32_t p_vaddr; | ||
| 107 | __uint32_t p_paddr; | ||
| 108 | __uint32_t p_filesz; | ||
| 109 | __uint32_t p_memsz; | ||
| 110 | __uint32_t p_flags; | ||
| 111 | __uint32_t p_align; | ||
| 112 | } XElf32_Phdr; | ||
| 113 | |||
| 114 | struct xdl_phdr_info { | ||
| 115 | Elf_Addr dlpi_addr; | ||
| 116 | const char *dlpi_name; | ||
| 117 | const XElf32_Phdr *dlpi_phdr; | ||
| 118 | Elf_Half dlpi_phnum; | ||
| 119 | unsigned long long int dlpi_adds; | ||
| 120 | unsigned long long int dlpi_subs; | ||
| 121 | size_t dlpi_tls_modid; | ||
| 122 | void *dlpi_tls_data; | ||
| 123 | }; | ||
| 124 | |||
| 125 | typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info *, size_t, | ||
| 126 | void *); | ||
| 127 | typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void *); | ||
| 128 | |||
| 129 | #define xdl_iterate_phdr(callback, param) \ | ||
| 130 | (((xdl_iterate_phdr_t *)dl_iterate_phdr)((callback), (param))) | ||
| 131 | |||
| 132 | } // namespace __sanitizer | ||
| 133 | |||
| 134 | #endif // __FreeBSD_version <= 902001 | ||
| 135 | #endif // SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) | ||
| 136 | |||
| 137 | #endif // SANITIZER_FREEBSD_H | ||
lib/tsan/sanitizer_common/sanitizer_fuchsia.cpp created+531| ... | @@ -0,0 +1,531 @@ | ||
| 1 | //===-- sanitizer_fuchsia.cpp ---------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and other sanitizer | ||
| 10 | // run-time libraries and implements Fuchsia-specific functions from | ||
| 11 | // sanitizer_common.h. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_fuchsia.h" | ||
| 15 | #if SANITIZER_FUCHSIA | ||
| 16 | |||
| 17 | #include "sanitizer_common.h" | ||
| 18 | #include "sanitizer_libc.h" | ||
| 19 | #include "sanitizer_mutex.h" | ||
| 20 | |||
| 21 | #include <limits.h> | ||
| 22 | #include <pthread.h> | ||
| 23 | #include <stdlib.h> | ||
| 24 | #include <unistd.h> | ||
| 25 | #include <zircon/errors.h> | ||
| 26 | #include <zircon/process.h> | ||
| 27 | #include <zircon/syscalls.h> | ||
| 28 | |||
| 29 | namespace __sanitizer { | ||
| 30 | |||
| 31 | void NORETURN internal__exit(int exitcode) { _zx_process_exit(exitcode); } | ||
| 32 | |||
| 33 | uptr internal_sched_yield() { | ||
| 34 | zx_status_t status = _zx_nanosleep(0); | ||
| 35 | CHECK_EQ(status, ZX_OK); | ||
| 36 | return 0; // Why doesn't this return void? | ||
| 37 | } | ||
| 38 | |||
| 39 | static void internal_nanosleep(zx_time_t ns) { | ||
| 40 | zx_status_t status = _zx_nanosleep(_zx_deadline_after(ns)); | ||
| 41 | CHECK_EQ(status, ZX_OK); | ||
| 42 | } | ||
| 43 | |||
| 44 | unsigned int internal_sleep(unsigned int seconds) { | ||
| 45 | internal_nanosleep(ZX_SEC(seconds)); | ||
| 46 | return 0; | ||
| 47 | } | ||
| 48 | |||
| 49 | u64 NanoTime() { | ||
| 50 | zx_time_t time; | ||
| 51 | zx_status_t status = _zx_clock_get(ZX_CLOCK_UTC, &time); | ||
| 52 | CHECK_EQ(status, ZX_OK); | ||
| 53 | return time; | ||
| 54 | } | ||
| 55 | |||
| 56 | u64 MonotonicNanoTime() { return _zx_clock_get_monotonic(); } | ||
| 57 | |||
| 58 | uptr internal_getpid() { | ||
| 59 | zx_info_handle_basic_t info; | ||
| 60 | zx_status_t status = | ||
| 61 | _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &info, | ||
| 62 | sizeof(info), NULL, NULL); | ||
| 63 | CHECK_EQ(status, ZX_OK); | ||
| 64 | uptr pid = static_cast<uptr>(info.koid); | ||
| 65 | CHECK_EQ(pid, info.koid); | ||
| 66 | return pid; | ||
| 67 | } | ||
| 68 | |||
| 69 | int internal_dlinfo(void *handle, int request, void *p) { | ||
| 70 | UNIMPLEMENTED(); | ||
| 71 | } | ||
| 72 | |||
| 73 | uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); } | ||
| 74 | |||
| 75 | tid_t GetTid() { return GetThreadSelf(); } | ||
| 76 | |||
| 77 | void Abort() { abort(); } | ||
| 78 | |||
| 79 | int Atexit(void (*function)(void)) { return atexit(function); } | ||
| 80 | |||
| 81 | void SleepForSeconds(int seconds) { internal_sleep(seconds); } | ||
| 82 | |||
| 83 | void SleepForMillis(int millis) { internal_nanosleep(ZX_MSEC(millis)); } | ||
| 84 | |||
| 85 | void GetThreadStackTopAndBottom(bool, uptr *stack_top, uptr *stack_bottom) { | ||
| 86 | pthread_attr_t attr; | ||
| 87 | CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); | ||
| 88 | void *base; | ||
| 89 | size_t size; | ||
| 90 | CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0); | ||
| 91 | CHECK_EQ(pthread_attr_destroy(&attr), 0); | ||
| 92 | |||
| 93 | *stack_bottom = reinterpret_cast<uptr>(base); | ||
| 94 | *stack_top = *stack_bottom + size; | ||
| 95 | } | ||
| 96 | |||
| 97 | void InitializePlatformEarly() {} | ||
| 98 | void MaybeReexec() {} | ||
| 99 | void CheckASLR() {} | ||
| 100 | void CheckMPROTECT() {} | ||
| 101 | void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} | ||
| 102 | void DisableCoreDumperIfNecessary() {} | ||
| 103 | void InstallDeadlySignalHandlers(SignalHandlerType handler) {} | ||
| 104 | void SetAlternateSignalStack() {} | ||
| 105 | void UnsetAlternateSignalStack() {} | ||
| 106 | void InitTlsSize() {} | ||
| 107 | |||
| 108 | void PrintModuleMap() {} | ||
| 109 | |||
| 110 | bool SignalContext::IsStackOverflow() const { return false; } | ||
| 111 | void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); } | ||
| 112 | const char *SignalContext::Describe() const { UNIMPLEMENTED(); } | ||
| 113 | |||
| 114 | enum MutexState : int { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 }; | ||
| 115 | |||
| 116 | BlockingMutex::BlockingMutex() { | ||
| 117 | // NOTE! It's important that this use internal_memset, because plain | ||
| 118 | // memset might be intercepted (e.g., actually be __asan_memset). | ||
| 119 | // Defining this so the compiler initializes each field, e.g.: | ||
| 120 | // BlockingMutex::BlockingMutex() : BlockingMutex(LINKER_INITIALIZED) {} | ||
| 121 | // might result in the compiler generating a call to memset, which would | ||
| 122 | // have the same problem. | ||
| 123 | internal_memset(this, 0, sizeof(*this)); | ||
| 124 | } | ||
| 125 | |||
| 126 | void BlockingMutex::Lock() { | ||
| 127 | CHECK_EQ(owner_, 0); | ||
| 128 | atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_); | ||
| 129 | if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked) | ||
| 130 | return; | ||
| 131 | while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) { | ||
| 132 | zx_status_t status = | ||
| 133 | _zx_futex_wait(reinterpret_cast<zx_futex_t *>(m), MtxSleeping, | ||
| 134 | ZX_HANDLE_INVALID, ZX_TIME_INFINITE); | ||
| 135 | if (status != ZX_ERR_BAD_STATE) // Normal race. | ||
| 136 | CHECK_EQ(status, ZX_OK); | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | void BlockingMutex::Unlock() { | ||
| 141 | atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_); | ||
| 142 | u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release); | ||
| 143 | CHECK_NE(v, MtxUnlocked); | ||
| 144 | if (v == MtxSleeping) { | ||
| 145 | zx_status_t status = _zx_futex_wake(reinterpret_cast<zx_futex_t *>(m), 1); | ||
| 146 | CHECK_EQ(status, ZX_OK); | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | void BlockingMutex::CheckLocked() { | ||
| 151 | atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_); | ||
| 152 | CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed)); | ||
| 153 | } | ||
| 154 | |||
| 155 | uptr GetPageSize() { return PAGE_SIZE; } | ||
| 156 | |||
| 157 | uptr GetMmapGranularity() { return PAGE_SIZE; } | ||
| 158 | |||
| 159 | sanitizer_shadow_bounds_t ShadowBounds; | ||
| 160 | |||
| 161 | uptr GetMaxUserVirtualAddress() { | ||
| 162 | ShadowBounds = __sanitizer_shadow_bounds(); | ||
| 163 | return ShadowBounds.memory_limit - 1; | ||
| 164 | } | ||
| 165 | |||
| 166 | uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); } | ||
| 167 | |||
| 168 | static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type, | ||
| 169 | bool raw_report, bool die_for_nomem) { | ||
| 170 | size = RoundUpTo(size, PAGE_SIZE); | ||
| 171 | |||
| 172 | zx_handle_t vmo; | ||
| 173 | zx_status_t status = _zx_vmo_create(size, 0, &vmo); | ||
| 174 | if (status != ZX_OK) { | ||
| 175 | if (status != ZX_ERR_NO_MEMORY || die_for_nomem) | ||
| 176 | ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status, | ||
| 177 | raw_report); | ||
| 178 | return nullptr; | ||
| 179 | } | ||
| 180 | _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type, | ||
| 181 | internal_strlen(mem_type)); | ||
| 182 | |||
| 183 | // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that? | ||
| 184 | uintptr_t addr; | ||
| 185 | status = | ||
| 186 | _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, | ||
| 187 | vmo, 0, size, &addr); | ||
| 188 | _zx_handle_close(vmo); | ||
| 189 | |||
| 190 | if (status != ZX_OK) { | ||
| 191 | if (status != ZX_ERR_NO_MEMORY || die_for_nomem) | ||
| 192 | ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status, | ||
| 193 | raw_report); | ||
| 194 | return nullptr; | ||
| 195 | } | ||
| 196 | |||
| 197 | IncreaseTotalMmap(size); | ||
| 198 | |||
| 199 | return reinterpret_cast<void *>(addr); | ||
| 200 | } | ||
| 201 | |||
| 202 | void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { | ||
| 203 | return DoAnonymousMmapOrDie(size, mem_type, raw_report, true); | ||
| 204 | } | ||
| 205 | |||
| 206 | void *MmapNoReserveOrDie(uptr size, const char *mem_type) { | ||
| 207 | return MmapOrDie(size, mem_type); | ||
| 208 | } | ||
| 209 | |||
| 210 | void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { | ||
| 211 | return DoAnonymousMmapOrDie(size, mem_type, false, false); | ||
| 212 | } | ||
| 213 | |||
| 214 | uptr ReservedAddressRange::Init(uptr init_size, const char *name, | ||
| 215 | uptr fixed_addr) { | ||
| 216 | init_size = RoundUpTo(init_size, PAGE_SIZE); | ||
| 217 | DCHECK_EQ(os_handle_, ZX_HANDLE_INVALID); | ||
| 218 | uintptr_t base; | ||
| 219 | zx_handle_t vmar; | ||
| 220 | zx_status_t status = | ||
| 221 | _zx_vmar_allocate( | ||
| 222 | _zx_vmar_root_self(), | ||
| 223 | ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, | ||
| 224 | 0, init_size, &vmar, &base); | ||
| 225 | if (status != ZX_OK) | ||
| 226 | ReportMmapFailureAndDie(init_size, name, "zx_vmar_allocate", status); | ||
| 227 | base_ = reinterpret_cast<void *>(base); | ||
| 228 | size_ = init_size; | ||
| 229 | name_ = name; | ||
| 230 | os_handle_ = vmar; | ||
| 231 | |||
| 232 | return reinterpret_cast<uptr>(base_); | ||
| 233 | } | ||
| 234 | |||
| 235 | static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size, | ||
| 236 | void *base, const char *name, bool die_for_nomem) { | ||
| 237 | uptr offset = fixed_addr - reinterpret_cast<uptr>(base); | ||
| 238 | map_size = RoundUpTo(map_size, PAGE_SIZE); | ||
| 239 | zx_handle_t vmo; | ||
| 240 | zx_status_t status = _zx_vmo_create(map_size, 0, &vmo); | ||
| 241 | if (status != ZX_OK) { | ||
| 242 | if (status != ZX_ERR_NO_MEMORY || die_for_nomem) | ||
| 243 | ReportMmapFailureAndDie(map_size, name, "zx_vmo_create", status); | ||
| 244 | return 0; | ||
| 245 | } | ||
| 246 | _zx_object_set_property(vmo, ZX_PROP_NAME, name, internal_strlen(name)); | ||
| 247 | DCHECK_GE(base + size_, map_size + offset); | ||
| 248 | uintptr_t addr; | ||
| 249 | |||
| 250 | status = | ||
| 251 | _zx_vmar_map(vmar, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC, | ||
| 252 | offset, vmo, 0, map_size, &addr); | ||
| 253 | _zx_handle_close(vmo); | ||
| 254 | if (status != ZX_OK) { | ||
| 255 | if (status != ZX_ERR_NO_MEMORY || die_for_nomem) { | ||
| 256 | ReportMmapFailureAndDie(map_size, name, "zx_vmar_map", status); | ||
| 257 | } | ||
| 258 | return 0; | ||
| 259 | } | ||
| 260 | IncreaseTotalMmap(map_size); | ||
| 261 | return addr; | ||
| 262 | } | ||
| 263 | |||
| 264 | uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size, | ||
| 265 | const char *name) { | ||
| 266 | return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, | ||
| 267 | name_, false); | ||
| 268 | } | ||
| 269 | |||
| 270 | uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr map_size, | ||
| 271 | const char *name) { | ||
| 272 | return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, | ||
| 273 | name_, true); | ||
| 274 | } | ||
| 275 | |||
| 276 | void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar) { | ||
| 277 | if (!addr || !size) return; | ||
| 278 | size = RoundUpTo(size, PAGE_SIZE); | ||
| 279 | |||
| 280 | zx_status_t status = | ||
| 281 | _zx_vmar_unmap(target_vmar, reinterpret_cast<uintptr_t>(addr), size); | ||
| 282 | if (status != ZX_OK) { | ||
| 283 | Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", | ||
| 284 | SanitizerToolName, size, size, addr); | ||
| 285 | CHECK("unable to unmap" && 0); | ||
| 286 | } | ||
| 287 | |||
| 288 | DecreaseTotalMmap(size); | ||
| 289 | } | ||
| 290 | |||
| 291 | void ReservedAddressRange::Unmap(uptr addr, uptr size) { | ||
| 292 | CHECK_LE(size, size_); | ||
| 293 | const zx_handle_t vmar = static_cast<zx_handle_t>(os_handle_); | ||
| 294 | if (addr == reinterpret_cast<uptr>(base_)) { | ||
| 295 | if (size == size_) { | ||
| 296 | // Destroying the vmar effectively unmaps the whole mapping. | ||
| 297 | _zx_vmar_destroy(vmar); | ||
| 298 | _zx_handle_close(vmar); | ||
| 299 | os_handle_ = static_cast<uptr>(ZX_HANDLE_INVALID); | ||
| 300 | DecreaseTotalMmap(size); | ||
| 301 | return; | ||
| 302 | } | ||
| 303 | } else { | ||
| 304 | CHECK_EQ(addr + size, reinterpret_cast<uptr>(base_) + size_); | ||
| 305 | } | ||
| 306 | // Partial unmapping does not affect the fact that the initial range is still | ||
| 307 | // reserved, and the resulting unmapped memory can't be reused. | ||
| 308 | UnmapOrDieVmar(reinterpret_cast<void *>(addr), size, vmar); | ||
| 309 | } | ||
| 310 | |||
| 311 | // This should never be called. | ||
| 312 | void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { | ||
| 313 | UNIMPLEMENTED(); | ||
| 314 | } | ||
| 315 | |||
| 316 | void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, | ||
| 317 | const char *mem_type) { | ||
| 318 | CHECK_GE(size, PAGE_SIZE); | ||
| 319 | CHECK(IsPowerOfTwo(size)); | ||
| 320 | CHECK(IsPowerOfTwo(alignment)); | ||
| 321 | |||
| 322 | zx_handle_t vmo; | ||
| 323 | zx_status_t status = _zx_vmo_create(size, 0, &vmo); | ||
| 324 | if (status != ZX_OK) { | ||
| 325 | if (status != ZX_ERR_NO_MEMORY) | ||
| 326 | ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status, false); | ||
| 327 | return nullptr; | ||
| 328 | } | ||
| 329 | _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type, | ||
| 330 | internal_strlen(mem_type)); | ||
| 331 | |||
| 332 | // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that? | ||
| 333 | |||
| 334 | // Map a larger size to get a chunk of address space big enough that | ||
| 335 | // it surely contains an aligned region of the requested size. Then | ||
| 336 | // overwrite the aligned middle portion with a mapping from the | ||
| 337 | // beginning of the VMO, and unmap the excess before and after. | ||
| 338 | size_t map_size = size + alignment; | ||
| 339 | uintptr_t addr; | ||
| 340 | status = | ||
| 341 | _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, | ||
| 342 | vmo, 0, map_size, &addr); | ||
| 343 | if (status == ZX_OK) { | ||
| 344 | uintptr_t map_addr = addr; | ||
| 345 | uintptr_t map_end = map_addr + map_size; | ||
| 346 | addr = RoundUpTo(map_addr, alignment); | ||
| 347 | uintptr_t end = addr + size; | ||
| 348 | if (addr != map_addr) { | ||
| 349 | zx_info_vmar_t info; | ||
| 350 | status = _zx_object_get_info(_zx_vmar_root_self(), ZX_INFO_VMAR, &info, | ||
| 351 | sizeof(info), NULL, NULL); | ||
| 352 | if (status == ZX_OK) { | ||
| 353 | uintptr_t new_addr; | ||
| 354 | status = _zx_vmar_map( | ||
| 355 | _zx_vmar_root_self(), | ||
| 356 | ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC_OVERWRITE, | ||
| 357 | addr - info.base, vmo, 0, size, &new_addr); | ||
| 358 | if (status == ZX_OK) CHECK_EQ(new_addr, addr); | ||
| 359 | } | ||
| 360 | } | ||
| 361 | if (status == ZX_OK && addr != map_addr) | ||
| 362 | status = _zx_vmar_unmap(_zx_vmar_root_self(), map_addr, addr - map_addr); | ||
| 363 | if (status == ZX_OK && end != map_end) | ||
| 364 | status = _zx_vmar_unmap(_zx_vmar_root_self(), end, map_end - end); | ||
| 365 | } | ||
| 366 | _zx_handle_close(vmo); | ||
| 367 | |||
| 368 | if (status != ZX_OK) { | ||
| 369 | if (status != ZX_ERR_NO_MEMORY) | ||
| 370 | ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status, false); | ||
| 371 | return nullptr; | ||
| 372 | } | ||
| 373 | |||
| 374 | IncreaseTotalMmap(size); | ||
| 375 | |||
| 376 | return reinterpret_cast<void *>(addr); | ||
| 377 | } | ||
| 378 | |||
| 379 | void UnmapOrDie(void *addr, uptr size) { | ||
| 380 | UnmapOrDieVmar(addr, size, _zx_vmar_root_self()); | ||
| 381 | } | ||
| 382 | |||
| 383 | // This is used on the shadow mapping, which cannot be changed. | ||
| 384 | // Zircon doesn't have anything like MADV_DONTNEED. | ||
| 385 | void ReleaseMemoryPagesToOS(uptr beg, uptr end) {} | ||
| 386 | |||
| 387 | void DumpProcessMap() { | ||
| 388 | // TODO(mcgrathr): write it | ||
| 389 | return; | ||
| 390 | } | ||
| 391 | |||
| 392 | bool IsAccessibleMemoryRange(uptr beg, uptr size) { | ||
| 393 | // TODO(mcgrathr): Figure out a better way. | ||
| 394 | zx_handle_t vmo; | ||
| 395 | zx_status_t status = _zx_vmo_create(size, 0, &vmo); | ||
| 396 | if (status == ZX_OK) { | ||
| 397 | status = _zx_vmo_write(vmo, reinterpret_cast<const void *>(beg), 0, size); | ||
| 398 | _zx_handle_close(vmo); | ||
| 399 | } | ||
| 400 | return status == ZX_OK; | ||
| 401 | } | ||
| 402 | |||
| 403 | // FIXME implement on this platform. | ||
| 404 | void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {} | ||
| 405 | |||
| 406 | bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, | ||
| 407 | uptr *read_len, uptr max_len, error_t *errno_p) { | ||
| 408 | zx_handle_t vmo; | ||
| 409 | zx_status_t status = __sanitizer_get_configuration(file_name, &vmo); | ||
| 410 | if (status == ZX_OK) { | ||
| 411 | uint64_t vmo_size; | ||
| 412 | status = _zx_vmo_get_size(vmo, &vmo_size); | ||
| 413 | if (status == ZX_OK) { | ||
| 414 | if (vmo_size < max_len) max_len = vmo_size; | ||
| 415 | size_t map_size = RoundUpTo(max_len, PAGE_SIZE); | ||
| 416 | uintptr_t addr; | ||
| 417 | status = _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ, 0, vmo, 0, | ||
| 418 | map_size, &addr); | ||
| 419 | if (status == ZX_OK) { | ||
| 420 | *buff = reinterpret_cast<char *>(addr); | ||
| 421 | *buff_size = map_size; | ||
| 422 | *read_len = max_len; | ||
| 423 | } | ||
| 424 | } | ||
| 425 | _zx_handle_close(vmo); | ||
| 426 | } | ||
| 427 | if (status != ZX_OK && errno_p) *errno_p = status; | ||
| 428 | return status == ZX_OK; | ||
| 429 | } | ||
| 430 | |||
| 431 | void RawWrite(const char *buffer) { | ||
| 432 | constexpr size_t size = 128; | ||
| 433 | static _Thread_local char line[size]; | ||
| 434 | static _Thread_local size_t lastLineEnd = 0; | ||
| 435 | static _Thread_local size_t cur = 0; | ||
| 436 | |||
| 437 | while (*buffer) { | ||
| 438 | if (cur >= size) { | ||
| 439 | if (lastLineEnd == 0) | ||
| 440 | lastLineEnd = size; | ||
| 441 | __sanitizer_log_write(line, lastLineEnd); | ||
| 442 | internal_memmove(line, line + lastLineEnd, cur - lastLineEnd); | ||
| 443 | cur = cur - lastLineEnd; | ||
| 444 | lastLineEnd = 0; | ||
| 445 | } | ||
| 446 | if (*buffer == '\n') | ||
| 447 | lastLineEnd = cur + 1; | ||
| 448 | line[cur++] = *buffer++; | ||
| 449 | } | ||
| 450 | // Flush all complete lines before returning. | ||
| 451 | if (lastLineEnd != 0) { | ||
| 452 | __sanitizer_log_write(line, lastLineEnd); | ||
| 453 | internal_memmove(line, line + lastLineEnd, cur - lastLineEnd); | ||
| 454 | cur = cur - lastLineEnd; | ||
| 455 | lastLineEnd = 0; | ||
| 456 | } | ||
| 457 | } | ||
| 458 | |||
| 459 | void CatastrophicErrorWrite(const char *buffer, uptr length) { | ||
| 460 | __sanitizer_log_write(buffer, length); | ||
| 461 | } | ||
| 462 | |||
| 463 | char **StoredArgv; | ||
| 464 | char **StoredEnviron; | ||
| 465 | |||
| 466 | char **GetArgv() { return StoredArgv; } | ||
| 467 | char **GetEnviron() { return StoredEnviron; } | ||
| 468 | |||
| 469 | const char *GetEnv(const char *name) { | ||
| 470 | if (StoredEnviron) { | ||
| 471 | uptr NameLen = internal_strlen(name); | ||
| 472 | for (char **Env = StoredEnviron; *Env != 0; Env++) { | ||
| 473 | if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=') | ||
| 474 | return (*Env) + NameLen + 1; | ||
| 475 | } | ||
| 476 | } | ||
| 477 | return nullptr; | ||
| 478 | } | ||
| 479 | |||
| 480 | uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) { | ||
| 481 | const char *argv0 = "<UNKNOWN>"; | ||
| 482 | if (StoredArgv && StoredArgv[0]) { | ||
| 483 | argv0 = StoredArgv[0]; | ||
| 484 | } | ||
| 485 | internal_strncpy(buf, argv0, buf_len); | ||
| 486 | return internal_strlen(buf); | ||
| 487 | } | ||
| 488 | |||
| 489 | uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { | ||
| 490 | return ReadBinaryName(buf, buf_len); | ||
| 491 | } | ||
| 492 | |||
| 493 | uptr MainThreadStackBase, MainThreadStackSize; | ||
| 494 | |||
| 495 | bool GetRandom(void *buffer, uptr length, bool blocking) { | ||
| 496 | CHECK_LE(length, ZX_CPRNG_DRAW_MAX_LEN); | ||
| 497 | _zx_cprng_draw(buffer, length); | ||
| 498 | return true; | ||
| 499 | } | ||
| 500 | |||
| 501 | u32 GetNumberOfCPUs() { | ||
| 502 | return zx_system_get_num_cpus(); | ||
| 503 | } | ||
| 504 | |||
| 505 | uptr GetRSS() { UNIMPLEMENTED(); } | ||
| 506 | |||
| 507 | } // namespace __sanitizer | ||
| 508 | |||
| 509 | using namespace __sanitizer; | ||
| 510 | |||
| 511 | extern "C" { | ||
| 512 | void __sanitizer_startup_hook(int argc, char **argv, char **envp, | ||
| 513 | void *stack_base, size_t stack_size) { | ||
| 514 | __sanitizer::StoredArgv = argv; | ||
| 515 | __sanitizer::StoredEnviron = envp; | ||
| 516 | __sanitizer::MainThreadStackBase = reinterpret_cast<uintptr_t>(stack_base); | ||
| 517 | __sanitizer::MainThreadStackSize = stack_size; | ||
| 518 | } | ||
| 519 | |||
| 520 | void __sanitizer_set_report_path(const char *path) { | ||
| 521 | // Handle the initialization code in each sanitizer, but no other calls. | ||
| 522 | // This setting is never consulted on Fuchsia. | ||
| 523 | DCHECK_EQ(path, common_flags()->log_path); | ||
| 524 | } | ||
| 525 | |||
| 526 | void __sanitizer_set_report_fd(void *fd) { | ||
| 527 | UNREACHABLE("not available on Fuchsia"); | ||
| 528 | } | ||
| 529 | } // extern "C" | ||
| 530 | |||
| 531 | #endif // SANITIZER_FUCHSIA | ||
lib/tsan/sanitizer_common/sanitizer_fuchsia.h created+36| ... | @@ -0,0 +1,36 @@ | ||
| 1 | //===-- sanitizer_fuchsia.h ------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===---------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Fuchsia-specific sanitizer support. | ||
| 10 | // | ||
| 11 | //===---------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_FUCHSIA_H | ||
| 13 | #define SANITIZER_FUCHSIA_H | ||
| 14 | |||
| 15 | #include "sanitizer_platform.h" | ||
| 16 | #if SANITIZER_FUCHSIA | ||
| 17 | |||
| 18 | #include "sanitizer_common.h" | ||
| 19 | |||
| 20 | #include <zircon/sanitizer.h> | ||
| 21 | #include <zircon/syscalls/object.h> | ||
| 22 | |||
| 23 | namespace __sanitizer { | ||
| 24 | |||
| 25 | extern uptr MainThreadStackBase, MainThreadStackSize; | ||
| 26 | extern sanitizer_shadow_bounds_t ShadowBounds; | ||
| 27 | |||
| 28 | struct MemoryMappingLayoutData { | ||
| 29 | InternalMmapVector<zx_info_maps_t> data; | ||
| 30 | size_t current; // Current index into the vector. | ||
| 31 | }; | ||
| 32 | |||
| 33 | } // namespace __sanitizer | ||
| 34 | |||
| 35 | #endif // SANITIZER_FUCHSIA | ||
| 36 | #endif // SANITIZER_FUCHSIA_H | ||
lib/tsan/sanitizer_common/sanitizer_getauxval.h created+59| ... | @@ -0,0 +1,59 @@ | ||
| 1 | //===-- sanitizer_getauxval.h -----------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Common getauxval() guards and definitions. | ||
| 10 | // getauxval() is not defined until glibc version 2.16, or until API level 21 | ||
| 11 | // for Android. | ||
| 12 | // Implement the getauxval() compat function for NetBSD. | ||
| 13 | // | ||
| 14 | //===----------------------------------------------------------------------===// | ||
| 15 | |||
| 16 | #ifndef SANITIZER_GETAUXVAL_H | ||
| 17 | #define SANITIZER_GETAUXVAL_H | ||
| 18 | |||
| 19 | #include "sanitizer_platform.h" | ||
| 20 | #include "sanitizer_glibc_version.h" | ||
| 21 | |||
| 22 | #if SANITIZER_LINUX || SANITIZER_FUCHSIA | ||
| 23 | |||
| 24 | # if __GLIBC_PREREQ(2, 16) || (SANITIZER_ANDROID && __ANDROID_API__ >= 21) || \ | ||
| 25 | SANITIZER_FUCHSIA | ||
| 26 | # define SANITIZER_USE_GETAUXVAL 1 | ||
| 27 | # else | ||
| 28 | # define SANITIZER_USE_GETAUXVAL 0 | ||
| 29 | # endif | ||
| 30 | |||
| 31 | # if SANITIZER_USE_GETAUXVAL | ||
| 32 | # include <sys/auxv.h> | ||
| 33 | # else | ||
| 34 | // The weak getauxval definition allows to check for the function at runtime. | ||
| 35 | // This is useful for Android, when compiled at a lower API level yet running | ||
| 36 | // on a more recent platform that offers the function. | ||
| 37 | extern "C" SANITIZER_WEAK_ATTRIBUTE unsigned long getauxval(unsigned long type); | ||
| 38 | # endif | ||
| 39 | |||
| 40 | #elif SANITIZER_NETBSD | ||
| 41 | |||
| 42 | #define SANITIZER_USE_GETAUXVAL 1 | ||
| 43 | |||
| 44 | #include <dlfcn.h> | ||
| 45 | #include <elf.h> | ||
| 46 | |||
| 47 | static inline decltype(AuxInfo::a_v) getauxval(decltype(AuxInfo::a_type) type) { | ||
| 48 | for (const AuxInfo *aux = (const AuxInfo *)_dlauxinfo(); | ||
| 49 | aux->a_type != AT_NULL; ++aux) { | ||
| 50 | if (type == aux->a_type) | ||
| 51 | return aux->a_v; | ||
| 52 | } | ||
| 53 | |||
| 54 | return 0; | ||
| 55 | } | ||
| 56 | |||
| 57 | #endif | ||
| 58 | |||
| 59 | #endif // SANITIZER_GETAUXVAL_H | ||
lib/tsan/sanitizer_common/sanitizer_glibc_version.h created+26| ... | @@ -0,0 +1,26 @@ | ||
| 1 | //===-- sanitizer_glibc_version.h -----------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer common code. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef SANITIZER_GLIBC_VERSION_H | ||
| 14 | #define SANITIZER_GLIBC_VERSION_H | ||
| 15 | |||
| 16 | #include "sanitizer_platform.h" | ||
| 17 | |||
| 18 | #if SANITIZER_LINUX || SANITIZER_FUCHSIA | ||
| 19 | #include <features.h> | ||
| 20 | #endif | ||
| 21 | |||
| 22 | #ifndef __GLIBC_PREREQ | ||
| 23 | #define __GLIBC_PREREQ(x, y) 0 | ||
| 24 | #endif | ||
| 25 | |||
| 26 | #endif | ||
lib/tsan/sanitizer_common/sanitizer_hash.h created+43| ... | @@ -0,0 +1,43 @@ | ||
| 1 | //===-- sanitizer_common.h --------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file implements a simple hash function. | ||
| 10 | //===----------------------------------------------------------------------===// | ||
| 11 | |||
| 12 | #ifndef SANITIZER_HASH_H | ||
| 13 | #define SANITIZER_HASH_H | ||
| 14 | |||
| 15 | #include "sanitizer_internal_defs.h" | ||
| 16 | |||
| 17 | namespace __sanitizer { | ||
| 18 | class MurMur2HashBuilder { | ||
| 19 | static const u32 m = 0x5bd1e995; | ||
| 20 | static const u32 seed = 0x9747b28c; | ||
| 21 | static const u32 r = 24; | ||
| 22 | u32 h; | ||
| 23 | |||
| 24 | public: | ||
| 25 | explicit MurMur2HashBuilder(u32 init = 0) { h = seed ^ init; } | ||
| 26 | void add(u32 k) { | ||
| 27 | k *= m; | ||
| 28 | k ^= k >> r; | ||
| 29 | k *= m; | ||
| 30 | h *= m; | ||
| 31 | h ^= k; | ||
| 32 | } | ||
| 33 | u32 get() { | ||
| 34 | u32 x = h; | ||
| 35 | x ^= x >> 13; | ||
| 36 | x *= m; | ||
| 37 | x ^= x >> 15; | ||
| 38 | return x; | ||
| 39 | } | ||
| 40 | }; | ||
| 41 | } //namespace __sanitizer | ||
| 42 | |||
| 43 | #endif // SANITIZER_HASH_H | ||
lib/tsan/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc created+1535| ... | @@ -0,0 +1,1535 @@ | ||
| 1 | //===-- sanitizer_interceptors_ioctl_netbsd.inc -----------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Ioctl handling in common sanitizer interceptors. | ||
| 10 | //===----------------------------------------------------------------------===// | ||
| 11 | |||
| 12 | #if SANITIZER_NETBSD | ||
| 13 | |||
| 14 | #include "sanitizer_flags.h" | ||
| 15 | |||
| 16 | struct ioctl_desc { | ||
| 17 | unsigned req; | ||
| 18 | // FIXME: support read+write arguments. Currently READWRITE and WRITE do the | ||
| 19 | // same thing. | ||
| 20 | // XXX: The declarations below may use WRITE instead of READWRITE, unless | ||
| 21 | // explicitly noted. | ||
| 22 | enum { NONE, READ, WRITE, READWRITE, CUSTOM } type : 3; | ||
| 23 | unsigned size : 29; | ||
| 24 | const char *name; | ||
| 25 | }; | ||
| 26 | |||
| 27 | const unsigned ioctl_table_max = 1238; | ||
| 28 | static ioctl_desc ioctl_table[ioctl_table_max]; | ||
| 29 | static unsigned ioctl_table_size = 0; | ||
| 30 | |||
| 31 | // This can not be declared as a global, because references to struct_*_sz | ||
| 32 | // require a global initializer. And this table must be available before global | ||
| 33 | // initializers are run. | ||
| 34 | static void ioctl_table_fill() { | ||
| 35 | #define _(rq, tp, sz) \ | ||
| 36 | if (IOCTL_##rq != IOCTL_NOT_PRESENT) { \ | ||
| 37 | CHECK(ioctl_table_size < ioctl_table_max); \ | ||
| 38 | ioctl_table[ioctl_table_size].req = IOCTL_##rq; \ | ||
| 39 | ioctl_table[ioctl_table_size].type = ioctl_desc::tp; \ | ||
| 40 | ioctl_table[ioctl_table_size].size = sz; \ | ||
| 41 | ioctl_table[ioctl_table_size].name = #rq; \ | ||
| 42 | ++ioctl_table_size; \ | ||
| 43 | } | ||
| 44 | |||
| 45 | /* Entries from file: altq/altq_afmap.h */ | ||
| 46 | _(AFM_ADDFMAP, READWRITE, struct_atm_flowmap_sz); | ||
| 47 | _(AFM_DELFMAP, READWRITE, struct_atm_flowmap_sz); | ||
| 48 | _(AFM_CLEANFMAP, READWRITE, struct_atm_flowmap_sz); | ||
| 49 | _(AFM_GETFMAP, READWRITE, struct_atm_flowmap_sz); | ||
| 50 | /* Entries from file: altq/altq.h */ | ||
| 51 | _(ALTQGTYPE, READWRITE, struct_altqreq_sz); | ||
| 52 | _(ALTQTBRSET, READ, struct_tbrreq_sz); | ||
| 53 | _(ALTQTBRGET, READWRITE, struct_tbrreq_sz); | ||
| 54 | /* Entries from file: altq/altq_blue.h */ | ||
| 55 | _(BLUE_IF_ATTACH, READ, struct_blue_interface_sz); | ||
| 56 | _(BLUE_DISABLE, READ, struct_blue_interface_sz); | ||
| 57 | _(BLUE_CONFIG, READWRITE, struct_blue_conf_sz); | ||
| 58 | _(BLUE_GETSTATS, READWRITE, struct_blue_stats_sz); | ||
| 59 | /* Entries from file: altq/altq_cbq.h */ | ||
| 60 | _(CBQ_ENABLE, READ, struct_cbq_interface_sz); | ||
| 61 | _(CBQ_ADD_CLASS, READWRITE, struct_cbq_add_class_sz); | ||
| 62 | _(CBQ_DEL_CLASS, READ, struct_cbq_delete_class_sz); | ||
| 63 | _(CBQ_MODIFY_CLASS, READWRITE, struct_cbq_modify_class_sz); | ||
| 64 | _(CBQ_DEL_FILTER, READ, struct_cbq_delete_filter_sz); | ||
| 65 | _(CBQ_GETSTATS, READWRITE, struct_cbq_getstats_sz); | ||
| 66 | /* Entries from file: altq/altq_cdnr.h */ | ||
| 67 | _(CDNR_IF_DETACH, READ, struct_cdnr_interface_sz); | ||
| 68 | _(CDNR_ADD_FILTER, READWRITE, struct_cdnr_add_filter_sz); | ||
| 69 | _(CDNR_GETSTATS, READWRITE, struct_cdnr_get_stats_sz); | ||
| 70 | _(CDNR_ADD_ELEM, READWRITE, struct_cdnr_add_element_sz); | ||
| 71 | _(CDNR_DEL_ELEM, READ, struct_cdnr_delete_element_sz); | ||
| 72 | _(CDNR_ADD_TBM, READWRITE, struct_cdnr_add_tbmeter_sz); | ||
| 73 | _(CDNR_MOD_TBM, READ, struct_cdnr_modify_tbmeter_sz); | ||
| 74 | _(CDNR_TBM_STATS, READWRITE, struct_cdnr_tbmeter_stats_sz); | ||
| 75 | _(CDNR_ADD_TCM, READWRITE, struct_cdnr_add_trtcm_sz); | ||
| 76 | _(CDNR_MOD_TCM, READWRITE, struct_cdnr_modify_trtcm_sz); | ||
| 77 | _(CDNR_TCM_STATS, READWRITE, struct_cdnr_tcm_stats_sz); | ||
| 78 | _(CDNR_ADD_TSW, READWRITE, struct_cdnr_add_tswtcm_sz); | ||
| 79 | _(CDNR_MOD_TSW, READWRITE, struct_cdnr_modify_tswtcm_sz); | ||
| 80 | /* Entries from file: altq/altq_fifoq.h */ | ||
| 81 | _(FIFOQ_CONFIG, READWRITE, struct_fifoq_conf_sz); | ||
| 82 | _(FIFOQ_GETSTATS, READWRITE, struct_fifoq_getstats_sz); | ||
| 83 | /* Entries from file: altq/altq_hfsc.h */ | ||
| 84 | _(HFSC_CLEAR_HIERARCHY, READ, struct_hfsc_interface_sz); | ||
| 85 | _(HFSC_ADD_CLASS, READWRITE, struct_hfsc_add_class_sz); | ||
| 86 | _(HFSC_GETSTATS, READWRITE, struct_hfsc_class_stats_sz); | ||
| 87 | /* Entries from file: altq/altq_jobs.h */ | ||
| 88 | _(JOBS_IF_ATTACH, READ, struct_jobs_attach_sz); | ||
| 89 | _(JOBS_IF_DETACH, READ, struct_jobs_interface_sz); | ||
| 90 | _(JOBS_ENABLE, READ, struct_jobs_interface_sz); | ||
| 91 | _(JOBS_DISABLE, READ, struct_jobs_interface_sz); | ||
| 92 | _(JOBS_CLEAR, READ, struct_jobs_interface_sz); | ||
| 93 | _(JOBS_ADD_CLASS, READWRITE, struct_jobs_add_class_sz); | ||
| 94 | _(JOBS_MOD_CLASS, READ, struct_jobs_modify_class_sz); | ||
| 95 | /* Entries from file: altq/altq_priq.h */ | ||
| 96 | _(PRIQ_IF_ATTACH, READ, struct_priq_interface_sz); | ||
| 97 | _(PRIQ_CLEAR, READ, struct_priq_interface_sz); | ||
| 98 | _(PRIQ_ADD_CLASS, READWRITE, struct_priq_add_class_sz); | ||
| 99 | _(PRIQ_DEL_CLASS, READ, struct_priq_delete_class_sz); | ||
| 100 | _(PRIQ_MOD_CLASS, READ, struct_priq_modify_class_sz); | ||
| 101 | _(PRIQ_ADD_FILTER, READWRITE, struct_priq_add_filter_sz); | ||
| 102 | _(PRIQ_DEL_FILTER, READ, struct_priq_delete_filter_sz); | ||
| 103 | _(PRIQ_GETSTATS, READWRITE, struct_priq_class_stats_sz); | ||
| 104 | /* Entries from file: altq/altq_red.h */ | ||
| 105 | _(RED_CONFIG, READWRITE, struct_red_conf_sz); | ||
| 106 | _(RED_GETSTATS, READWRITE, struct_red_stats_sz); | ||
| 107 | _(RED_SETDEFAULTS, READ, struct_redparams_sz); | ||
| 108 | /* Entries from file: altq/altq_rio.h */ | ||
| 109 | _(RIO_CONFIG, READWRITE, struct_rio_conf_sz); | ||
| 110 | _(RIO_GETSTATS, READWRITE, struct_rio_stats_sz); | ||
| 111 | _(RIO_SETDEFAULTS, READ, struct_redparams_sz); | ||
| 112 | /* Entries from file: altq/altq_wfq.h */ | ||
| 113 | _(WFQ_CONFIG, READWRITE, struct_wfq_conf_sz); | ||
| 114 | _(WFQ_GET_QID, READWRITE, struct_wfq_getqid_sz); | ||
| 115 | _(WFQ_SET_WEIGHT, READWRITE, struct_wfq_setweight_sz); | ||
| 116 | /* Entries from file: crypto/cryptodev.h */ | ||
| 117 | _(CRIOGET, READWRITE, sizeof(u32)); | ||
| 118 | _(CIOCFSESSION, READ, sizeof(u32)); | ||
| 119 | _(CIOCKEY, READWRITE, struct_crypt_kop_sz); | ||
| 120 | _(CIOCNFKEYM, READWRITE, struct_crypt_mkop_sz); | ||
| 121 | _(CIOCNFSESSION, READ, struct_crypt_sfop_sz); | ||
| 122 | _(CIOCNCRYPTRETM, READWRITE, struct_cryptret_sz); | ||
| 123 | _(CIOCNCRYPTRET, READWRITE, struct_crypt_result_sz); | ||
| 124 | _(CIOCGSESSION, READWRITE, struct_session_op_sz); | ||
| 125 | _(CIOCNGSESSION, READWRITE, struct_crypt_sgop_sz); | ||
| 126 | _(CIOCCRYPT, READWRITE, struct_crypt_op_sz); | ||
| 127 | _(CIOCNCRYPTM, READWRITE, struct_crypt_mop_sz); | ||
| 128 | _(CIOCASYMFEAT, WRITE, sizeof(u32)); | ||
| 129 | /* Entries from file: dev/apm/apmio.h */ | ||
| 130 | _(APM_IOC_REJECT, READ, struct_apm_event_info_sz); | ||
| 131 | _(OAPM_IOC_GETPOWER, WRITE, struct_apm_power_info_sz); | ||
| 132 | _(APM_IOC_GETPOWER, READWRITE, struct_apm_power_info_sz); | ||
| 133 | _(APM_IOC_NEXTEVENT, WRITE, struct_apm_event_info_sz); | ||
| 134 | _(APM_IOC_DEV_CTL, READ, struct_apm_ctl_sz); | ||
| 135 | /* Entries from file: dev/dm/netbsd-dm.h */ | ||
| 136 | _(NETBSD_DM_IOCTL, READWRITE, struct_plistref_sz); | ||
| 137 | /* Entries from file: dev/dmover/dmover_io.h */ | ||
| 138 | _(DMIO_SETFUNC, READ, struct_dmio_setfunc_sz); | ||
| 139 | /* Entries from file: dev/dtv/dtvio_demux.h */ | ||
| 140 | _(DMX_START, NONE, 0); | ||
| 141 | _(DMX_STOP, NONE, 0); | ||
| 142 | _(DMX_SET_FILTER, READ, struct_dmx_sct_filter_params_sz); | ||
| 143 | _(DMX_SET_PES_FILTER, READ, struct_dmx_pes_filter_params_sz); | ||
| 144 | _(DMX_SET_BUFFER_SIZE, NONE, 0); | ||
| 145 | _(DMX_GET_STC, READWRITE, struct_dmx_stc_sz); | ||
| 146 | _(DMX_ADD_PID, READ, sizeof(u16)); | ||
| 147 | _(DMX_REMOVE_PID, READ, sizeof(u16)); | ||
| 148 | _(DMX_GET_CAPS, WRITE, struct_dmx_caps_sz); | ||
| 149 | _(DMX_SET_SOURCE, READ, enum_dmx_source_sz); | ||
| 150 | /* Entries from file: dev/dtv/dtvio_frontend.h */ | ||
| 151 | _(FE_READ_STATUS, WRITE, enum_fe_status_sz); | ||
| 152 | _(FE_READ_BER, WRITE, sizeof(u32)); | ||
| 153 | _(FE_READ_SNR, WRITE, sizeof(u16)); | ||
| 154 | _(FE_READ_SIGNAL_STRENGTH, WRITE, sizeof(u16)); | ||
| 155 | _(FE_READ_UNCORRECTED_BLOCKS, WRITE, sizeof(u32)); | ||
| 156 | _(FE_SET_FRONTEND, READWRITE, struct_dvb_frontend_parameters_sz); | ||
| 157 | _(FE_GET_FRONTEND, WRITE, struct_dvb_frontend_parameters_sz); | ||
| 158 | _(FE_GET_EVENT, WRITE, struct_dvb_frontend_event_sz); | ||
| 159 | _(FE_GET_INFO, WRITE, struct_dvb_frontend_info_sz); | ||
| 160 | _(FE_DISEQC_RESET_OVERLOAD, NONE, 0); | ||
| 161 | _(FE_DISEQC_SEND_MASTER_CMD, READ, struct_dvb_diseqc_master_cmd_sz); | ||
| 162 | _(FE_DISEQC_RECV_SLAVE_REPLY, WRITE, struct_dvb_diseqc_slave_reply_sz); | ||
| 163 | _(FE_DISEQC_SEND_BURST, READ, enum_fe_sec_mini_cmd_sz); | ||
| 164 | _(FE_SET_TONE, READ, enum_fe_sec_tone_mode_sz); | ||
| 165 | _(FE_SET_VOLTAGE, READ, enum_fe_sec_voltage_sz); | ||
| 166 | _(FE_ENABLE_HIGH_LNB_VOLTAGE, READ, sizeof(int)); | ||
| 167 | _(FE_SET_FRONTEND_TUNE_MODE, READ, sizeof(unsigned int)); | ||
| 168 | _(FE_DISHNETWORK_SEND_LEGACY_CMD, READ, sizeof(unsigned long)); | ||
| 169 | /* Entries from file: dev/hdaudio/hdaudioio.h */ | ||
| 170 | _(HDAUDIO_FGRP_INFO, READWRITE, struct_plistref_sz); | ||
| 171 | _(HDAUDIO_FGRP_GETCONFIG, READWRITE, struct_plistref_sz); | ||
| 172 | _(HDAUDIO_FGRP_SETCONFIG, READWRITE, struct_plistref_sz); | ||
| 173 | _(HDAUDIO_FGRP_WIDGET_INFO, READWRITE, struct_plistref_sz); | ||
| 174 | _(HDAUDIO_FGRP_CODEC_INFO, READWRITE, struct_plistref_sz); | ||
| 175 | _(HDAUDIO_AFG_WIDGET_INFO, READWRITE, struct_plistref_sz); | ||
| 176 | _(HDAUDIO_AFG_CODEC_INFO, READWRITE, struct_plistref_sz); | ||
| 177 | /* Entries from file: dev/hdmicec/hdmicecio.h */ | ||
| 178 | _(CEC_GET_PHYS_ADDR, WRITE, sizeof(u16)); | ||
| 179 | _(CEC_GET_LOG_ADDRS, WRITE, sizeof(u16)); | ||
| 180 | _(CEC_SET_LOG_ADDRS, READ, sizeof(u16)); | ||
| 181 | _(CEC_GET_VENDOR_ID, WRITE, sizeof(u32)); | ||
| 182 | /* Entries from file: dev/hpc/hpcfbio.h */ | ||
| 183 | _(HPCFBIO_GCONF, READWRITE, struct_hpcfb_fbconf_sz); | ||
| 184 | _(HPCFBIO_SCONF, READ, struct_hpcfb_fbconf_sz); | ||
| 185 | _(HPCFBIO_GDSPCONF, READWRITE, struct_hpcfb_dspconf_sz); | ||
| 186 | _(HPCFBIO_SDSPCONF, READ, struct_hpcfb_dspconf_sz); | ||
| 187 | _(HPCFBIO_GOP, WRITE, struct_hpcfb_dsp_op_sz); | ||
| 188 | _(HPCFBIO_SOP, READWRITE, struct_hpcfb_dsp_op_sz); | ||
| 189 | /* Entries from file: dev/i2o/iopio.h */ | ||
| 190 | _(IOPIOCPT, READWRITE, struct_ioppt_sz); | ||
| 191 | _(IOPIOCGLCT, READWRITE, struct_iovec_sz); | ||
| 192 | _(IOPIOCGSTATUS, READWRITE, struct_iovec_sz); | ||
| 193 | _(IOPIOCRECONFIG, NONE, 0); | ||
| 194 | _(IOPIOCGTIDMAP, READWRITE, struct_iovec_sz); | ||
| 195 | /* Entries from file: dev/ic/athioctl.h */ | ||
| 196 | _(SIOCGATHSTATS, READWRITE, struct_ifreq_sz); | ||
| 197 | _(SIOCGATHDIAG, READWRITE, struct_ath_diag_sz); | ||
| 198 | /* Entries from file: dev/ic/bt8xx.h */ | ||
| 199 | _(METEORCAPTUR, READ, sizeof(int)); | ||
| 200 | _(METEORCAPFRM, READ, struct_meteor_capframe_sz); | ||
| 201 | _(METEORSETGEO, READ, struct_meteor_geomet_sz); | ||
| 202 | _(METEORGETGEO, WRITE, struct_meteor_geomet_sz); | ||
| 203 | _(METEORSTATUS, WRITE, sizeof(unsigned short)); | ||
| 204 | _(METEORSHUE, READ, sizeof(signed char)); | ||
| 205 | _(METEORGHUE, WRITE, sizeof(signed char)); | ||
| 206 | _(METEORSFMT, READ, sizeof(unsigned int)); | ||
| 207 | _(METEORGFMT, WRITE, sizeof(unsigned int)); | ||
| 208 | _(METEORSINPUT, READ, sizeof(unsigned int)); | ||
| 209 | _(METEORGINPUT, WRITE, sizeof(unsigned int)); | ||
| 210 | _(METEORSCHCV, READ, sizeof(unsigned char)); | ||
| 211 | _(METEORGCHCV, WRITE, sizeof(unsigned char)); | ||
| 212 | _(METEORSCOUNT, READ, struct_meteor_counts_sz); | ||
| 213 | _(METEORGCOUNT, WRITE, struct_meteor_counts_sz); | ||
| 214 | _(METEORSFPS, READ, sizeof(unsigned short)); | ||
| 215 | _(METEORGFPS, WRITE, sizeof(unsigned short)); | ||
| 216 | _(METEORSSIGNAL, READ, sizeof(unsigned int)); | ||
| 217 | _(METEORGSIGNAL, WRITE, sizeof(unsigned int)); | ||
| 218 | _(METEORSVIDEO, READ, struct_meteor_video_sz); | ||
| 219 | _(METEORGVIDEO, WRITE, struct_meteor_video_sz); | ||
| 220 | _(METEORSBRIG, READ, sizeof(unsigned char)); | ||
| 221 | _(METEORGBRIG, WRITE, sizeof(unsigned char)); | ||
| 222 | _(METEORSCSAT, READ, sizeof(unsigned char)); | ||
| 223 | _(METEORGCSAT, WRITE, sizeof(unsigned char)); | ||
| 224 | _(METEORSCONT, READ, sizeof(unsigned char)); | ||
| 225 | _(METEORGCONT, WRITE, sizeof(unsigned char)); | ||
| 226 | _(METEORSHWS, READ, sizeof(unsigned char)); | ||
| 227 | _(METEORGHWS, WRITE, sizeof(unsigned char)); | ||
| 228 | _(METEORSVWS, READ, sizeof(unsigned char)); | ||
| 229 | _(METEORGVWS, WRITE, sizeof(unsigned char)); | ||
| 230 | _(METEORSTS, READ, sizeof(unsigned char)); | ||
| 231 | _(METEORGTS, WRITE, sizeof(unsigned char)); | ||
| 232 | _(TVTUNER_SETCHNL, READ, sizeof(unsigned int)); | ||
| 233 | _(TVTUNER_GETCHNL, WRITE, sizeof(unsigned int)); | ||
| 234 | _(TVTUNER_SETTYPE, READ, sizeof(unsigned int)); | ||
| 235 | _(TVTUNER_GETTYPE, WRITE, sizeof(unsigned int)); | ||
| 236 | _(TVTUNER_GETSTATUS, WRITE, sizeof(unsigned int)); | ||
| 237 | _(TVTUNER_SETFREQ, READ, sizeof(unsigned int)); | ||
| 238 | _(TVTUNER_GETFREQ, WRITE, sizeof(unsigned int)); | ||
| 239 | _(TVTUNER_SETAFC, READ, sizeof(int)); | ||
| 240 | _(TVTUNER_GETAFC, WRITE, sizeof(int)); | ||
| 241 | _(RADIO_SETMODE, READ, sizeof(unsigned int)); | ||
| 242 | _(RADIO_GETMODE, WRITE, sizeof(unsigned char)); | ||
| 243 | _(RADIO_SETFREQ, READ, sizeof(unsigned int)); | ||
| 244 | _(RADIO_GETFREQ, WRITE, sizeof(unsigned int)); | ||
| 245 | _(METEORSACTPIXFMT, READ, sizeof(int)); | ||
| 246 | _(METEORGACTPIXFMT, WRITE, sizeof(int)); | ||
| 247 | _(METEORGSUPPIXFMT, READWRITE, struct_meteor_pixfmt_sz); | ||
| 248 | _(TVTUNER_GETCHNLSET, READWRITE, struct_bktr_chnlset_sz); | ||
| 249 | _(REMOTE_GETKEY, WRITE, struct_bktr_remote_sz); | ||
| 250 | /* Entries from file: dev/ic/icp_ioctl.h */ | ||
| 251 | _(GDT_IOCTL_GENERAL, READWRITE, struct_gdt_ucmd_sz); | ||
| 252 | _(GDT_IOCTL_DRVERS, WRITE, sizeof(int)); | ||
| 253 | _(GDT_IOCTL_CTRTYPE, READWRITE, struct_gdt_ctrt_sz); | ||
| 254 | _(GDT_IOCTL_OSVERS, WRITE, struct_gdt_osv_sz); | ||
| 255 | _(GDT_IOCTL_CTRCNT, WRITE, sizeof(int)); | ||
| 256 | _(GDT_IOCTL_EVENT, READWRITE, struct_gdt_event_sz); | ||
| 257 | _(GDT_IOCTL_STATIST, WRITE, struct_gdt_statist_sz); | ||
| 258 | _(GDT_IOCTL_RESCAN, READWRITE, struct_gdt_rescan_sz); | ||
| 259 | /* Entries from file: dev/ic/isp_ioctl.h */ | ||
| 260 | _(ISP_SDBLEV, READWRITE, sizeof(int)); | ||
| 261 | _(ISP_RESETHBA, NONE, 0); | ||
| 262 | _(ISP_RESCAN, NONE, 0); | ||
| 263 | _(ISP_SETROLE, READWRITE, sizeof(int)); | ||
| 264 | _(ISP_GETROLE, WRITE, sizeof(int)); | ||
| 265 | _(ISP_GET_STATS, WRITE, struct_isp_stats_sz); | ||
| 266 | _(ISP_CLR_STATS, NONE, 0); | ||
| 267 | _(ISP_FC_LIP, NONE, 0); | ||
| 268 | _(ISP_FC_GETDINFO, READWRITE, struct_isp_fc_device_sz); | ||
| 269 | _(ISP_GET_FW_CRASH_DUMP, NONE, 0); | ||
| 270 | _(ISP_FORCE_CRASH_DUMP, NONE, 0); | ||
| 271 | _(ISP_FC_GETHINFO, READWRITE, struct_isp_hba_device_sz); | ||
| 272 | _(ISP_TSK_MGMT, READWRITE, struct_isp_fc_tsk_mgmt_sz); | ||
| 273 | _(ISP_FC_GETDLIST, NONE, 0); | ||
| 274 | /* Entries from file: dev/ic/mlxio.h */ | ||
| 275 | _(MLXD_STATUS, WRITE, sizeof(int)); | ||
| 276 | _(MLXD_CHECKASYNC, WRITE, sizeof(int)); | ||
| 277 | _(MLXD_DETACH, READ, sizeof(int)); | ||
| 278 | _(MLX_RESCAN_DRIVES, NONE, 0); | ||
| 279 | _(MLX_PAUSE_CHANNEL, READ, struct_mlx_pause_sz); | ||
| 280 | _(MLX_COMMAND, READWRITE, struct_mlx_usercommand_sz); | ||
| 281 | _(MLX_REBUILDASYNC, READWRITE, struct_mlx_rebuild_request_sz); | ||
| 282 | _(MLX_REBUILDSTAT, WRITE, struct_mlx_rebuild_status_sz); | ||
| 283 | _(MLX_GET_SYSDRIVE, READWRITE, sizeof(int)); | ||
| 284 | _(MLX_GET_CINFO, WRITE, struct_mlx_cinfo_sz); | ||
| 285 | /* Entries from file: dev/ic/nvmeio.h */ | ||
| 286 | _(NVME_PASSTHROUGH_CMD, READWRITE, struct_nvme_pt_command_sz); | ||
| 287 | /* Entries from file: dev/ic/qemufwcfgio.h */ | ||
| 288 | _(FWCFGIO_SET_INDEX, READ, sizeof(u16)); | ||
| 289 | /* Entries from file: dev/ir/irdaio.h */ | ||
| 290 | _(IRDA_RESET_PARAMS, NONE, 0); | ||
| 291 | _(IRDA_SET_PARAMS, READ, struct_irda_params_sz); | ||
| 292 | _(IRDA_GET_SPEEDMASK, WRITE, sizeof(unsigned int)); | ||
| 293 | _(IRDA_GET_TURNAROUNDMASK, WRITE, sizeof(unsigned int)); | ||
| 294 | _(IRFRAMETTY_GET_DEVICE, WRITE, sizeof(unsigned int)); | ||
| 295 | _(IRFRAMETTY_GET_DONGLE, WRITE, sizeof(unsigned int)); | ||
| 296 | _(IRFRAMETTY_SET_DONGLE, READ, sizeof(unsigned int)); | ||
| 297 | /* Entries from file: dev/isa/isvio.h */ | ||
| 298 | _(ISV_CMD, READWRITE, struct_isv_cmd_sz); | ||
| 299 | /* Entries from file: dev/isa/wtreg.h */ | ||
| 300 | _(WTQICMD, NONE, 0); | ||
| 301 | /* Entries from file: dev/iscsi/iscsi_ioctl.h */ | ||
| 302 | _(ISCSI_GET_VERSION, READWRITE, struct_iscsi_get_version_parameters_sz); | ||
| 303 | _(ISCSI_LOGIN, READWRITE, struct_iscsi_login_parameters_sz); | ||
| 304 | _(ISCSI_LOGOUT, READWRITE, struct_iscsi_logout_parameters_sz); | ||
| 305 | _(ISCSI_ADD_CONNECTION, READWRITE, struct_iscsi_login_parameters_sz); | ||
| 306 | _(ISCSI_RESTORE_CONNECTION, READWRITE, struct_iscsi_login_parameters_sz); | ||
| 307 | _(ISCSI_REMOVE_CONNECTION, READWRITE, struct_iscsi_remove_parameters_sz); | ||
| 308 | _(ISCSI_CONNECTION_STATUS, READWRITE, struct_iscsi_conn_status_parameters_sz); | ||
| 309 | _(ISCSI_SEND_TARGETS, READWRITE, struct_iscsi_send_targets_parameters_sz); | ||
| 310 | _(ISCSI_SET_NODE_NAME, READWRITE, struct_iscsi_set_node_name_parameters_sz); | ||
| 311 | _(ISCSI_IO_COMMAND, READWRITE, struct_iscsi_iocommand_parameters_sz); | ||
| 312 | _(ISCSI_REGISTER_EVENT, READWRITE, struct_iscsi_register_event_parameters_sz); | ||
| 313 | _(ISCSI_DEREGISTER_EVENT, READWRITE, | ||
| 314 | struct_iscsi_register_event_parameters_sz); | ||
| 315 | _(ISCSI_WAIT_EVENT, READWRITE, struct_iscsi_wait_event_parameters_sz); | ||
| 316 | _(ISCSI_POLL_EVENT, READWRITE, struct_iscsi_wait_event_parameters_sz); | ||
| 317 | /* Entries from file: dev/ofw/openfirmio.h */ | ||
| 318 | _(OFIOCGET, READWRITE, struct_ofiocdesc_sz); | ||
| 319 | _(OFIOCSET, READ, struct_ofiocdesc_sz); | ||
| 320 | _(OFIOCNEXTPROP, READWRITE, struct_ofiocdesc_sz); | ||
| 321 | _(OFIOCGETOPTNODE, WRITE, sizeof(int)); | ||
| 322 | _(OFIOCGETNEXT, READWRITE, sizeof(int)); | ||
| 323 | _(OFIOCGETCHILD, READWRITE, sizeof(int)); | ||
| 324 | _(OFIOCFINDDEVICE, READWRITE, struct_ofiocdesc_sz); | ||
| 325 | /* Entries from file: dev/pci/amrio.h */ | ||
| 326 | _(AMR_IO_VERSION, WRITE, sizeof(int)); | ||
| 327 | _(AMR_IO_COMMAND, READWRITE, struct_amr_user_ioctl_sz); | ||
| 328 | /* Entries from file: dev/pci/mlyio.h */ | ||
| 329 | _(MLYIO_COMMAND, READWRITE, struct_mly_user_command_sz); | ||
| 330 | _(MLYIO_HEALTH, READ, struct_mly_user_health_sz); | ||
| 331 | /* Entries from file: dev/pci/pciio.h */ | ||
| 332 | _(PCI_IOC_CFGREAD, READWRITE, struct_pciio_cfgreg_sz); | ||
| 333 | _(PCI_IOC_CFGWRITE, READ, struct_pciio_cfgreg_sz); | ||
| 334 | _(PCI_IOC_BDF_CFGREAD, READWRITE, struct_pciio_bdf_cfgreg_sz); | ||
| 335 | _(PCI_IOC_BDF_CFGWRITE, READ, struct_pciio_bdf_cfgreg_sz); | ||
| 336 | _(PCI_IOC_BUSINFO, WRITE, struct_pciio_businfo_sz); | ||
| 337 | _(PCI_IOC_DRVNAME, READWRITE, struct_pciio_drvname_sz); | ||
| 338 | _(PCI_IOC_DRVNAMEONBUS, READWRITE, struct_pciio_drvnameonbus_sz); | ||
| 339 | /* Entries from file: dev/pci/tweio.h */ | ||
| 340 | _(TWEIO_COMMAND, READWRITE, struct_twe_usercommand_sz); | ||
| 341 | _(TWEIO_STATS, READWRITE, union_twe_statrequest_sz); | ||
| 342 | _(TWEIO_AEN_POLL, WRITE, sizeof(int)); | ||
| 343 | _(TWEIO_AEN_WAIT, WRITE, sizeof(int)); | ||
| 344 | _(TWEIO_SET_PARAM, READ, struct_twe_paramcommand_sz); | ||
| 345 | _(TWEIO_GET_PARAM, READ, struct_twe_paramcommand_sz); | ||
| 346 | _(TWEIO_RESET, NONE, 0); | ||
| 347 | _(TWEIO_ADD_UNIT, READ, struct_twe_drivecommand_sz); | ||
| 348 | _(TWEIO_DEL_UNIT, READ, struct_twe_drivecommand_sz); | ||
| 349 | /* Entries from file: dev/pcmcia/if_cnwioctl.h */ | ||
| 350 | _(SIOCSCNWDOMAIN, READ, struct_ifreq_sz); | ||
| 351 | _(SIOCGCNWDOMAIN, READWRITE, struct_ifreq_sz); | ||
| 352 | _(SIOCSCNWKEY, READWRITE, struct_ifreq_sz); | ||
| 353 | _(SIOCGCNWSTATUS, READWRITE, struct_cnwstatus_sz); | ||
| 354 | _(SIOCGCNWSTATS, READWRITE, struct_cnwistats_sz); | ||
| 355 | _(SIOCGCNWTRAIL, READWRITE, struct_cnwitrail_sz); | ||
| 356 | /* Entries from file: dev/pcmcia/if_rayreg.h */ | ||
| 357 | _(SIOCGRAYSIGLEV, READWRITE, struct_ifreq_sz); | ||
| 358 | /* Entries from file: dev/raidframe/raidframeio.h */ | ||
| 359 | _(RAIDFRAME_SHUTDOWN, NONE, 0); | ||
| 360 | _(RAIDFRAME_TUR, READ, sizeof(u64)); | ||
| 361 | _(RAIDFRAME_FAIL_DISK, READ, struct_rf_recon_req_sz); | ||
| 362 | _(RAIDFRAME_CHECK_RECON_STATUS, READWRITE, sizeof(int)); | ||
| 363 | _(RAIDFRAME_REWRITEPARITY, NONE, 0); | ||
| 364 | _(RAIDFRAME_COPYBACK, NONE, 0); | ||
| 365 | _(RAIDFRAME_SPARET_WAIT, WRITE, struct_RF_SparetWait_sz); | ||
| 366 | _(RAIDFRAME_SEND_SPARET, READ, sizeof(uptr)); | ||
| 367 | _(RAIDFRAME_ABORT_SPARET_WAIT, NONE, 0); | ||
| 368 | _(RAIDFRAME_START_ATRACE, NONE, 0); | ||
| 369 | _(RAIDFRAME_STOP_ATRACE, NONE, 0); | ||
| 370 | _(RAIDFRAME_GET_SIZE, WRITE, sizeof(int)); | ||
| 371 | _(RAIDFRAME_RESET_ACCTOTALS, NONE, 0); | ||
| 372 | _(RAIDFRAME_KEEP_ACCTOTALS, READ, sizeof(int)); | ||
| 373 | _(RAIDFRAME_GET_COMPONENT_LABEL, READWRITE, struct_RF_ComponentLabel_sz); | ||
| 374 | _(RAIDFRAME_SET_COMPONENT_LABEL, READ, struct_RF_ComponentLabel_sz); | ||
| 375 | _(RAIDFRAME_INIT_LABELS, READ, struct_RF_ComponentLabel_sz); | ||
| 376 | _(RAIDFRAME_ADD_HOT_SPARE, READ, struct_RF_SingleComponent_sz); | ||
| 377 | _(RAIDFRAME_REMOVE_HOT_SPARE, READ, struct_RF_SingleComponent_sz); | ||
| 378 | _(RAIDFRAME_REBUILD_IN_PLACE, READ, struct_RF_SingleComponent_sz); | ||
| 379 | _(RAIDFRAME_CHECK_PARITY, READWRITE, sizeof(int)); | ||
| 380 | _(RAIDFRAME_CHECK_PARITYREWRITE_STATUS, READWRITE, sizeof(int)); | ||
| 381 | _(RAIDFRAME_CHECK_COPYBACK_STATUS, READWRITE, sizeof(int)); | ||
| 382 | _(RAIDFRAME_SET_AUTOCONFIG, READWRITE, sizeof(int)); | ||
| 383 | _(RAIDFRAME_SET_ROOT, READWRITE, sizeof(int)); | ||
| 384 | _(RAIDFRAME_DELETE_COMPONENT, READ, struct_RF_SingleComponent_sz); | ||
| 385 | _(RAIDFRAME_INCORPORATE_HOT_SPARE, READ, struct_RF_SingleComponent_sz); | ||
| 386 | _(RAIDFRAME_CHECK_RECON_STATUS_EXT, READWRITE, struct_RF_ProgressInfo_sz); | ||
| 387 | _(RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT, READWRITE, | ||
| 388 | struct_RF_ProgressInfo_sz); | ||
| 389 | _(RAIDFRAME_CHECK_COPYBACK_STATUS_EXT, READWRITE, struct_RF_ProgressInfo_sz); | ||
| 390 | _(RAIDFRAME_PARITYMAP_STATUS, WRITE, struct_rf_pmstat_sz); | ||
| 391 | _(RAIDFRAME_PARITYMAP_GET_DISABLE, WRITE, sizeof(int)); | ||
| 392 | _(RAIDFRAME_PARITYMAP_SET_DISABLE, READ, sizeof(int)); | ||
| 393 | _(RAIDFRAME_PARITYMAP_SET_PARAMS, READ, struct_rf_pmparams_sz); | ||
| 394 | _(RAIDFRAME_SET_LAST_UNIT, READ, sizeof(int)); | ||
| 395 | _(RAIDFRAME_GET_INFO, READWRITE, sizeof(uptr)); | ||
| 396 | _(RAIDFRAME_CONFIGURE, READ, sizeof(uptr)); | ||
| 397 | /* Entries from file: dev/sbus/mbppio.h */ | ||
| 398 | _(MBPPIOCSPARAM, READ, struct_mbpp_param_sz); | ||
| 399 | _(MBPPIOCGPARAM, WRITE, struct_mbpp_param_sz); | ||
| 400 | _(MBPPIOCGSTAT, WRITE, sizeof(int)); | ||
| 401 | /* Entries from file: dev/scsipi/ses.h */ | ||
| 402 | _(SESIOC_GETNOBJ, NONE, 0); | ||
| 403 | _(SESIOC_GETOBJMAP, NONE, 0); | ||
| 404 | _(SESIOC_GETENCSTAT, NONE, 0); | ||
| 405 | _(SESIOC_SETENCSTAT, NONE, 0); | ||
| 406 | _(SESIOC_GETOBJSTAT, NONE, 0); | ||
| 407 | _(SESIOC_SETOBJSTAT, NONE, 0); | ||
| 408 | _(SESIOC_GETTEXT, NONE, 0); | ||
| 409 | _(SESIOC_INIT, NONE, 0); | ||
| 410 | /* Entries from file: dev/sun/disklabel.h */ | ||
| 411 | _(SUN_DKIOCGGEOM, WRITE, struct_sun_dkgeom_sz); | ||
| 412 | _(SUN_DKIOCINFO, WRITE, struct_sun_dkctlr_sz); | ||
| 413 | _(SUN_DKIOCGPART, WRITE, struct_sun_dkpart_sz); | ||
| 414 | /* Entries from file: dev/sun/fbio.h */ | ||
| 415 | _(FBIOGTYPE, WRITE, struct_fbtype_sz); | ||
| 416 | _(FBIOPUTCMAP, READ, struct_fbcmap_sz); | ||
| 417 | _(FBIOGETCMAP, READ, struct_fbcmap_sz); | ||
| 418 | _(FBIOGATTR, WRITE, struct_fbgattr_sz); | ||
| 419 | _(FBIOSVIDEO, READ, sizeof(int)); | ||
| 420 | _(FBIOGVIDEO, WRITE, sizeof(int)); | ||
| 421 | _(FBIOSCURSOR, READ, struct_fbcursor_sz); | ||
| 422 | _(FBIOGCURSOR, READWRITE, struct_fbcursor_sz); | ||
| 423 | _(FBIOSCURPOS, READ, struct_fbcurpos_sz); | ||
| 424 | _(FBIOGCURPOS, READ, struct_fbcurpos_sz); | ||
| 425 | _(FBIOGCURMAX, WRITE, struct_fbcurpos_sz); | ||
| 426 | /* Entries from file: dev/sun/kbio.h */ | ||
| 427 | _(KIOCTRANS, READ, sizeof(int)); | ||
| 428 | _(KIOCSETKEY, READWRITE, struct_okiockey_sz); | ||
| 429 | _(KIOCGETKEY, READWRITE, struct_okiockey_sz); | ||
| 430 | _(KIOCGTRANS, WRITE, sizeof(int)); | ||
| 431 | _(KIOCCMD, READ, sizeof(int)); | ||
| 432 | _(KIOCTYPE, WRITE, sizeof(int)); | ||
| 433 | _(KIOCSDIRECT, READ, sizeof(int)); | ||
| 434 | _(KIOCSKEY, READ, struct_kiockeymap_sz); | ||
| 435 | _(KIOCGKEY, READWRITE, struct_kiockeymap_sz); | ||
| 436 | _(KIOCSLED, READ, sizeof(char)); | ||
| 437 | _(KIOCGLED, WRITE, sizeof(char)); | ||
| 438 | _(KIOCLAYOUT, WRITE, sizeof(int)); | ||
| 439 | /* Entries from file: dev/sun/vuid_event.h */ | ||
| 440 | _(VUIDSFORMAT, READ, sizeof(int)); | ||
| 441 | _(VUIDGFORMAT, WRITE, sizeof(int)); | ||
| 442 | /* Entries from file: dev/tc/sticio.h */ | ||
| 443 | _(STICIO_GXINFO, WRITE, struct_stic_xinfo_sz); | ||
| 444 | _(STICIO_RESET, NONE, 0); | ||
| 445 | _(STICIO_STARTQ, NONE, 0); | ||
| 446 | _(STICIO_STOPQ, NONE, 0); | ||
| 447 | /* Entries from file: dev/usb/ukyopon.h */ | ||
| 448 | _(UKYOPON_IDENTIFY, WRITE, struct_ukyopon_identify_sz); | ||
| 449 | /* Entries from file: dev/usb/usb.h */ | ||
| 450 | _(USB_REQUEST, READWRITE, struct_usb_ctl_request_sz); | ||
| 451 | _(USB_SETDEBUG, READ, sizeof(int)); | ||
| 452 | _(USB_DISCOVER, NONE, 0); | ||
| 453 | _(USB_DEVICEINFO, READWRITE, struct_usb_device_info_sz); | ||
| 454 | _(USB_DEVICEINFO_OLD, READWRITE, struct_usb_device_info_old_sz); | ||
| 455 | _(USB_DEVICESTATS, WRITE, struct_usb_device_stats_sz); | ||
| 456 | _(USB_GET_REPORT_DESC, WRITE, struct_usb_ctl_report_desc_sz); | ||
| 457 | _(USB_SET_IMMED, READ, sizeof(int)); | ||
| 458 | _(USB_GET_REPORT, READWRITE, struct_usb_ctl_report_sz); | ||
| 459 | _(USB_SET_REPORT, READ, struct_usb_ctl_report_sz); | ||
| 460 | _(USB_GET_REPORT_ID, WRITE, sizeof(int)); | ||
| 461 | _(USB_GET_CONFIG, WRITE, sizeof(int)); | ||
| 462 | _(USB_SET_CONFIG, READ, sizeof(int)); | ||
| 463 | _(USB_GET_ALTINTERFACE, READWRITE, struct_usb_alt_interface_sz); | ||
| 464 | _(USB_SET_ALTINTERFACE, READWRITE, struct_usb_alt_interface_sz); | ||
| 465 | _(USB_GET_NO_ALT, READWRITE, struct_usb_alt_interface_sz); | ||
| 466 | _(USB_GET_DEVICE_DESC, WRITE, struct_usb_device_descriptor_sz); | ||
| 467 | _(USB_GET_CONFIG_DESC, READWRITE, struct_usb_config_desc_sz); | ||
| 468 | _(USB_GET_INTERFACE_DESC, READWRITE, struct_usb_interface_desc_sz); | ||
| 469 | _(USB_GET_ENDPOINT_DESC, READWRITE, struct_usb_endpoint_desc_sz); | ||
| 470 | _(USB_GET_FULL_DESC, READWRITE, struct_usb_full_desc_sz); | ||
| 471 | _(USB_GET_STRING_DESC, READWRITE, struct_usb_string_desc_sz); | ||
| 472 | _(USB_DO_REQUEST, READWRITE, struct_usb_ctl_request_sz); | ||
| 473 | _(USB_GET_DEVICEINFO, WRITE, struct_usb_device_info_sz); | ||
| 474 | _(USB_GET_DEVICEINFO_OLD, WRITE, struct_usb_device_info_old_sz); | ||
| 475 | _(USB_SET_SHORT_XFER, READ, sizeof(int)); | ||
| 476 | _(USB_SET_TIMEOUT, READ, sizeof(int)); | ||
| 477 | _(USB_SET_BULK_RA, READ, sizeof(int)); | ||
| 478 | _(USB_SET_BULK_WB, READ, sizeof(int)); | ||
| 479 | _(USB_SET_BULK_RA_OPT, READ, struct_usb_bulk_ra_wb_opt_sz); | ||
| 480 | _(USB_SET_BULK_WB_OPT, READ, struct_usb_bulk_ra_wb_opt_sz); | ||
| 481 | _(USB_GET_CM_OVER_DATA, WRITE, sizeof(int)); | ||
| 482 | _(USB_SET_CM_OVER_DATA, READ, sizeof(int)); | ||
| 483 | /* Entries from file: dev/usb/utoppy.h */ | ||
| 484 | _(UTOPPYIOTURBO, READ, sizeof(int)); | ||
| 485 | _(UTOPPYIOREBOOT, NONE, 0); | ||
| 486 | _(UTOPPYIOSTATS, WRITE, struct_utoppy_stats_sz); | ||
| 487 | _(UTOPPYIORENAME, READ, struct_utoppy_rename_sz); | ||
| 488 | _(UTOPPYIOMKDIR, READ, sizeof(uptr)); | ||
| 489 | _(UTOPPYIODELETE, READ, sizeof(uptr)); | ||
| 490 | _(UTOPPYIOREADDIR, READ, sizeof(uptr)); | ||
| 491 | _(UTOPPYIOREADFILE, READ, struct_utoppy_readfile_sz); | ||
| 492 | _(UTOPPYIOWRITEFILE, READ, struct_utoppy_writefile_sz); | ||
| 493 | /* Entries from file: dev/vme/xio.h */ | ||
| 494 | _(DIOSXDCMD, READWRITE, struct_xd_iocmd_sz); | ||
| 495 | /* Entries from file: dev/wscons/wsdisplay_usl_io.h */ | ||
| 496 | _(VT_OPENQRY, WRITE, sizeof(int)); | ||
| 497 | _(VT_SETMODE, READ, struct_vt_mode_sz); | ||
| 498 | _(VT_GETMODE, WRITE, struct_vt_mode_sz); | ||
| 499 | _(VT_RELDISP, NONE, 0); | ||
| 500 | _(VT_ACTIVATE, NONE, 0); | ||
| 501 | _(VT_WAITACTIVE, NONE, 0); | ||
| 502 | _(VT_GETACTIVE, WRITE, sizeof(int)); | ||
| 503 | _(VT_GETSTATE, WRITE, struct_vt_stat_sz); | ||
| 504 | _(KDGETKBENT, READWRITE, struct_kbentry_sz); | ||
| 505 | _(KDGKBMODE, WRITE, sizeof(int)); | ||
| 506 | _(KDSKBMODE, NONE, 0); | ||
| 507 | _(KDMKTONE, NONE, 0); | ||
| 508 | _(KDSETMODE, NONE, 0); | ||
| 509 | _(KDENABIO, NONE, 0); | ||
| 510 | _(KDDISABIO, NONE, 0); | ||
| 511 | _(KDGKBTYPE, WRITE, sizeof(char)); | ||
| 512 | _(KDGETLED, WRITE, sizeof(int)); | ||
| 513 | _(KDSETLED, NONE, 0); | ||
| 514 | _(KDSETRAD, NONE, 0); | ||
| 515 | _(VGAPCVTID, READWRITE, struct_pcvtid_sz); | ||
| 516 | _(CONS_GETVERS, WRITE, sizeof(int)); | ||
| 517 | /* Entries from file: dev/wscons/wsconsio.h */ | ||
| 518 | _(WSKBDIO_GTYPE, WRITE, sizeof(unsigned int)); | ||
| 519 | _(WSKBDIO_BELL, NONE, 0); | ||
| 520 | _(WSKBDIO_COMPLEXBELL, READ, struct_wskbd_bell_data_sz); | ||
| 521 | _(WSKBDIO_SETBELL, READ, struct_wskbd_bell_data_sz); | ||
| 522 | _(WSKBDIO_GETBELL, WRITE, struct_wskbd_bell_data_sz); | ||
| 523 | _(WSKBDIO_SETDEFAULTBELL, READ, struct_wskbd_bell_data_sz); | ||
| 524 | _(WSKBDIO_GETDEFAULTBELL, WRITE, struct_wskbd_bell_data_sz); | ||
| 525 | _(WSKBDIO_SETKEYREPEAT, READ, struct_wskbd_keyrepeat_data_sz); | ||
| 526 | _(WSKBDIO_GETKEYREPEAT, WRITE, struct_wskbd_keyrepeat_data_sz); | ||
| 527 | _(WSKBDIO_SETDEFAULTKEYREPEAT, READ, struct_wskbd_keyrepeat_data_sz); | ||
| 528 | _(WSKBDIO_GETDEFAULTKEYREPEAT, WRITE, struct_wskbd_keyrepeat_data_sz); | ||
| 529 | _(WSKBDIO_SETLEDS, READ, sizeof(int)); | ||
| 530 | _(WSKBDIO_GETLEDS, WRITE, sizeof(int)); | ||
| 531 | _(WSKBDIO_GETMAP, READWRITE, struct_wskbd_map_data_sz); | ||
| 532 | _(WSKBDIO_SETMAP, READ, struct_wskbd_map_data_sz); | ||
| 533 | _(WSKBDIO_GETENCODING, WRITE, sizeof(int)); | ||
| 534 | _(WSKBDIO_SETENCODING, READ, sizeof(int)); | ||
| 535 | _(WSKBDIO_SETMODE, READ, sizeof(int)); | ||
| 536 | _(WSKBDIO_GETMODE, WRITE, sizeof(int)); | ||
| 537 | _(WSKBDIO_SETKEYCLICK, READ, sizeof(int)); | ||
| 538 | _(WSKBDIO_GETKEYCLICK, WRITE, sizeof(int)); | ||
| 539 | _(WSKBDIO_GETSCROLL, WRITE, struct_wskbd_scroll_data_sz); | ||
| 540 | _(WSKBDIO_SETSCROLL, READ, struct_wskbd_scroll_data_sz); | ||
| 541 | _(WSKBDIO_SETVERSION, READ, sizeof(int)); | ||
| 542 | _(WSMOUSEIO_GTYPE, WRITE, sizeof(unsigned int)); | ||
| 543 | _(WSMOUSEIO_SRES, READ, sizeof(unsigned int)); | ||
| 544 | _(WSMOUSEIO_SSCALE, READ, sizeof(unsigned int)); | ||
| 545 | _(WSMOUSEIO_SRATE, READ, sizeof(unsigned int)); | ||
| 546 | _(WSMOUSEIO_SCALIBCOORDS, READ, struct_wsmouse_calibcoords_sz); | ||
| 547 | _(WSMOUSEIO_GCALIBCOORDS, WRITE, struct_wsmouse_calibcoords_sz); | ||
| 548 | _(WSMOUSEIO_GETID, READWRITE, struct_wsmouse_id_sz); | ||
| 549 | _(WSMOUSEIO_GETREPEAT, WRITE, struct_wsmouse_repeat_sz); | ||
| 550 | _(WSMOUSEIO_SETREPEAT, READ, struct_wsmouse_repeat_sz); | ||
| 551 | _(WSMOUSEIO_SETVERSION, READ, sizeof(int)); | ||
| 552 | _(WSDISPLAYIO_GTYPE, WRITE, sizeof(unsigned int)); | ||
| 553 | _(WSDISPLAYIO_GINFO, WRITE, struct_wsdisplay_fbinfo_sz); | ||
| 554 | _(WSDISPLAYIO_GETCMAP, READ, struct_wsdisplay_cmap_sz); | ||
| 555 | _(WSDISPLAYIO_PUTCMAP, READ, struct_wsdisplay_cmap_sz); | ||
| 556 | _(WSDISPLAYIO_GVIDEO, WRITE, sizeof(unsigned int)); | ||
| 557 | _(WSDISPLAYIO_SVIDEO, READ, sizeof(unsigned int)); | ||
| 558 | _(WSDISPLAYIO_GCURPOS, WRITE, struct_wsdisplay_curpos_sz); | ||
| 559 | _(WSDISPLAYIO_SCURPOS, READ, struct_wsdisplay_curpos_sz); | ||
| 560 | _(WSDISPLAYIO_GCURMAX, WRITE, struct_wsdisplay_curpos_sz); | ||
| 561 | _(WSDISPLAYIO_GCURSOR, READWRITE, struct_wsdisplay_cursor_sz); | ||
| 562 | _(WSDISPLAYIO_SCURSOR, READ, struct_wsdisplay_cursor_sz); | ||
| 563 | _(WSDISPLAYIO_GMODE, WRITE, sizeof(unsigned int)); | ||
| 564 | _(WSDISPLAYIO_SMODE, READ, sizeof(unsigned int)); | ||
| 565 | _(WSDISPLAYIO_LDFONT, READ, struct_wsdisplay_font_sz); | ||
| 566 | _(WSDISPLAYIO_ADDSCREEN, READ, struct_wsdisplay_addscreendata_sz); | ||
| 567 | _(WSDISPLAYIO_DELSCREEN, READ, struct_wsdisplay_delscreendata_sz); | ||
| 568 | _(WSDISPLAYIO_SFONT, READ, struct_wsdisplay_usefontdata_sz); | ||
| 569 | _(_O_WSDISPLAYIO_SETKEYBOARD, READWRITE, struct_wsdisplay_kbddata_sz); | ||
| 570 | _(WSDISPLAYIO_GETPARAM, READWRITE, struct_wsdisplay_param_sz); | ||
| 571 | _(WSDISPLAYIO_SETPARAM, READWRITE, struct_wsdisplay_param_sz); | ||
| 572 | _(WSDISPLAYIO_GETACTIVESCREEN, WRITE, sizeof(int)); | ||
| 573 | _(WSDISPLAYIO_GETWSCHAR, READWRITE, struct_wsdisplay_char_sz); | ||
| 574 | _(WSDISPLAYIO_PUTWSCHAR, READWRITE, struct_wsdisplay_char_sz); | ||
| 575 | _(WSDISPLAYIO_DGSCROLL, WRITE, struct_wsdisplay_scroll_data_sz); | ||
| 576 | _(WSDISPLAYIO_DSSCROLL, READ, struct_wsdisplay_scroll_data_sz); | ||
| 577 | _(WSDISPLAYIO_GMSGATTRS, WRITE, struct_wsdisplay_msgattrs_sz); | ||
| 578 | _(WSDISPLAYIO_SMSGATTRS, READ, struct_wsdisplay_msgattrs_sz); | ||
| 579 | _(WSDISPLAYIO_GBORDER, WRITE, sizeof(int)); | ||
| 580 | _(WSDISPLAYIO_SBORDER, READ, sizeof(int)); | ||
| 581 | _(WSDISPLAYIO_SSPLASH, READ, sizeof(int)); | ||
| 582 | _(WSDISPLAYIO_SPROGRESS, READ, sizeof(int)); | ||
| 583 | _(WSDISPLAYIO_LINEBYTES, WRITE, sizeof(unsigned int)); | ||
| 584 | _(WSDISPLAYIO_SETVERSION, READ, sizeof(int)); | ||
| 585 | _(WSMUXIO_ADD_DEVICE, READ, struct_wsmux_device_sz); | ||
| 586 | _(WSMUXIO_REMOVE_DEVICE, READ, struct_wsmux_device_sz); | ||
| 587 | _(WSMUXIO_LIST_DEVICES, READWRITE, struct_wsmux_device_list_sz); | ||
| 588 | _(WSMUXIO_INJECTEVENT, READ, struct_wscons_event_sz); | ||
| 589 | _(WSDISPLAYIO_GET_BUSID, WRITE, struct_wsdisplayio_bus_id_sz); | ||
| 590 | _(WSDISPLAYIO_GET_EDID, READWRITE, struct_wsdisplayio_edid_info_sz); | ||
| 591 | _(WSDISPLAYIO_SET_POLLING, READ, sizeof(int)); | ||
| 592 | _(WSDISPLAYIO_GET_FBINFO, READWRITE, struct_wsdisplayio_fbinfo_sz); | ||
| 593 | _(WSDISPLAYIO_DOBLIT, READWRITE, struct_wsdisplayio_blit_sz); | ||
| 594 | _(WSDISPLAYIO_WAITBLIT, READWRITE, struct_wsdisplayio_blit_sz); | ||
| 595 | /* Entries from file: dev/biovar.h */ | ||
| 596 | _(BIOCLOCATE, READWRITE, struct_bio_locate_sz); | ||
| 597 | _(BIOCINQ, READWRITE, struct_bioc_inq_sz); | ||
| 598 | _(BIOCDISK_NOVOL, READWRITE, struct_bioc_disk_sz); | ||
| 599 | _(BIOCDISK, READWRITE, struct_bioc_disk_sz); | ||
| 600 | _(BIOCVOL, READWRITE, struct_bioc_vol_sz); | ||
| 601 | _(BIOCALARM, READWRITE, struct_bioc_alarm_sz); | ||
| 602 | _(BIOCBLINK, READWRITE, struct_bioc_blink_sz); | ||
| 603 | _(BIOCSETSTATE, READWRITE, struct_bioc_setstate_sz); | ||
| 604 | _(BIOCVOLOPS, READWRITE, struct_bioc_volops_sz); | ||
| 605 | /* Entries from file: dev/md.h */ | ||
| 606 | _(MD_GETCONF, WRITE, struct_md_conf_sz); | ||
| 607 | _(MD_SETCONF, READ, struct_md_conf_sz); | ||
| 608 | /* Entries from file: dev/ccdvar.h */ | ||
| 609 | _(CCDIOCSET, READWRITE, struct_ccd_ioctl_sz); | ||
| 610 | _(CCDIOCCLR, READ, struct_ccd_ioctl_sz); | ||
| 611 | /* Entries from file: dev/cgdvar.h */ | ||
| 612 | _(CGDIOCSET, READWRITE, struct_cgd_ioctl_sz); | ||
| 613 | _(CGDIOCCLR, READ, struct_cgd_ioctl_sz); | ||
| 614 | _(CGDIOCGET, READWRITE, struct_cgd_user_sz); | ||
| 615 | /* Entries from file: dev/fssvar.h */ | ||
| 616 | _(FSSIOCSET, READ, struct_fss_set_sz); | ||
| 617 | _(FSSIOCGET, WRITE, struct_fss_get_sz); | ||
| 618 | _(FSSIOCCLR, NONE, 0); | ||
| 619 | _(FSSIOFSET, READ, sizeof(int)); | ||
| 620 | _(FSSIOFGET, WRITE, sizeof(int)); | ||
| 621 | /* Entries from file: dev/bluetooth/btdev.h */ | ||
| 622 | _(BTDEV_ATTACH, READ, struct_plistref_sz); | ||
| 623 | _(BTDEV_DETACH, READ, struct_plistref_sz); | ||
| 624 | /* Entries from file: dev/bluetooth/btsco.h */ | ||
| 625 | _(BTSCO_GETINFO, WRITE, struct_btsco_info_sz); | ||
| 626 | /* Entries from file: dev/kttcpio.h */ | ||
| 627 | _(KTTCP_IO_SEND, READWRITE, struct_kttcp_io_args_sz); | ||
| 628 | _(KTTCP_IO_RECV, READWRITE, struct_kttcp_io_args_sz); | ||
| 629 | /* Entries from file: dev/lockstat.h */ | ||
| 630 | _(IOC_LOCKSTAT_GVERSION, WRITE, sizeof(int)); | ||
| 631 | _(IOC_LOCKSTAT_ENABLE, READ, struct_lsenable_sz); | ||
| 632 | _(IOC_LOCKSTAT_DISABLE, WRITE, struct_lsdisable_sz); | ||
| 633 | /* Entries from file: dev/vndvar.h */ | ||
| 634 | _(VNDIOCSET, READWRITE, struct_vnd_ioctl_sz); | ||
| 635 | _(VNDIOCCLR, READ, struct_vnd_ioctl_sz); | ||
| 636 | _(VNDIOCGET, READWRITE, struct_vnd_user_sz); | ||
| 637 | /* Entries from file: dev/spkrio.h */ | ||
| 638 | _(SPKRTONE, READ, struct_tone_sz); | ||
| 639 | _(SPKRTUNE, NONE, 0); | ||
| 640 | _(SPKRGETVOL, WRITE, sizeof(unsigned int)); | ||
| 641 | _(SPKRSETVOL, READ, sizeof(unsigned int)); | ||
| 642 | #if defined(__x86_64__) | ||
| 643 | /* Entries from file: dev/nvmm/nvmm_ioctl.h */ | ||
| 644 | _(NVMM_IOC_CAPABILITY, WRITE, struct_nvmm_ioc_capability_sz); | ||
| 645 | _(NVMM_IOC_MACHINE_CREATE, READWRITE, struct_nvmm_ioc_machine_create_sz); | ||
| 646 | _(NVMM_IOC_MACHINE_DESTROY, READ, struct_nvmm_ioc_machine_destroy_sz); | ||
| 647 | _(NVMM_IOC_MACHINE_CONFIGURE, READ, struct_nvmm_ioc_machine_configure_sz); | ||
| 648 | _(NVMM_IOC_VCPU_CREATE, READ, struct_nvmm_ioc_vcpu_create_sz); | ||
| 649 | _(NVMM_IOC_VCPU_DESTROY, READ, struct_nvmm_ioc_vcpu_destroy_sz); | ||
| 650 | _(NVMM_IOC_VCPU_CONFIGURE, READ, struct_nvmm_ioc_vcpu_configure_sz); | ||
| 651 | _(NVMM_IOC_VCPU_SETSTATE, READ, struct_nvmm_ioc_vcpu_setstate_sz); | ||
| 652 | _(NVMM_IOC_VCPU_GETSTATE, READ, struct_nvmm_ioc_vcpu_getstate_sz); | ||
| 653 | _(NVMM_IOC_VCPU_INJECT, READ, struct_nvmm_ioc_vcpu_inject_sz); | ||
| 654 | _(NVMM_IOC_VCPU_RUN, READWRITE, struct_nvmm_ioc_vcpu_run_sz); | ||
| 655 | _(NVMM_IOC_GPA_MAP, READ, struct_nvmm_ioc_gpa_map_sz); | ||
| 656 | _(NVMM_IOC_GPA_UNMAP, READ, struct_nvmm_ioc_gpa_unmap_sz); | ||
| 657 | _(NVMM_IOC_HVA_MAP, READ, struct_nvmm_ioc_hva_map_sz); | ||
| 658 | _(NVMM_IOC_HVA_UNMAP, READ, struct_nvmm_ioc_hva_unmap_sz); | ||
| 659 | _(NVMM_IOC_CTL, READ, struct_nvmm_ioc_ctl_sz); | ||
| 660 | #endif | ||
| 661 | /* Entries from file: dev/spi/spi_io.h */ | ||
| 662 | _(SPI_IOCTL_CONFIGURE, READ, struct_spi_ioctl_configure_sz); | ||
| 663 | _(SPI_IOCTL_TRANSFER, READ, struct_spi_ioctl_transfer_sz); | ||
| 664 | /* Entries from file: fs/autofs/autofs_ioctl.h */ | ||
| 665 | _(AUTOFSREQUEST, WRITE, struct_autofs_daemon_request_sz); | ||
| 666 | _(AUTOFSDONE, READ, struct_autofs_daemon_done_sz); | ||
| 667 | /* Entries from file: net/bpf.h */ | ||
| 668 | _(BIOCGBLEN, WRITE, sizeof(unsigned int)); | ||
| 669 | _(BIOCSBLEN, READWRITE, sizeof(unsigned int)); | ||
| 670 | _(BIOCSETF, READ, struct_bpf_program_sz); | ||
| 671 | _(BIOCFLUSH, NONE, 0); | ||
| 672 | _(BIOCPROMISC, NONE, 0); | ||
| 673 | _(BIOCGDLT, WRITE, sizeof(unsigned int)); | ||
| 674 | _(BIOCGETIF, WRITE, struct_ifreq_sz); | ||
| 675 | _(BIOCSETIF, READ, struct_ifreq_sz); | ||
| 676 | _(BIOCGSTATS, WRITE, struct_bpf_stat_sz); | ||
| 677 | _(BIOCGSTATSOLD, WRITE, struct_bpf_stat_old_sz); | ||
| 678 | _(BIOCIMMEDIATE, READ, sizeof(unsigned int)); | ||
| 679 | _(BIOCVERSION, WRITE, struct_bpf_version_sz); | ||
| 680 | _(BIOCSTCPF, READ, struct_bpf_program_sz); | ||
| 681 | _(BIOCSUDPF, READ, struct_bpf_program_sz); | ||
| 682 | _(BIOCGHDRCMPLT, WRITE, sizeof(unsigned int)); | ||
| 683 | _(BIOCSHDRCMPLT, READ, sizeof(unsigned int)); | ||
| 684 | _(BIOCSDLT, READ, sizeof(unsigned int)); | ||
| 685 | _(BIOCGDLTLIST, READWRITE, struct_bpf_dltlist_sz); | ||
| 686 | _(BIOCGDIRECTION, WRITE, sizeof(unsigned int)); | ||
| 687 | _(BIOCSDIRECTION, READ, sizeof(unsigned int)); | ||
| 688 | _(BIOCSRTIMEOUT, READ, struct_timeval_sz); | ||
| 689 | _(BIOCGRTIMEOUT, WRITE, struct_timeval_sz); | ||
| 690 | _(BIOCGFEEDBACK, WRITE, sizeof(unsigned int)); | ||
| 691 | _(BIOCSFEEDBACK, READ, sizeof(unsigned int)); | ||
| 692 | /* Entries from file: net/if_gre.h */ | ||
| 693 | _(GRESADDRS, READ, struct_ifreq_sz); | ||
| 694 | _(GRESADDRD, READ, struct_ifreq_sz); | ||
| 695 | _(GREGADDRS, READWRITE, struct_ifreq_sz); | ||
| 696 | _(GREGADDRD, READWRITE, struct_ifreq_sz); | ||
| 697 | _(GRESPROTO, READ, struct_ifreq_sz); | ||
| 698 | _(GREGPROTO, READWRITE, struct_ifreq_sz); | ||
| 699 | _(GRESSOCK, READ, struct_ifreq_sz); | ||
| 700 | _(GREDSOCK, READ, struct_ifreq_sz); | ||
| 701 | /* Entries from file: net/if_ppp.h */ | ||
| 702 | _(PPPIOCGRAWIN, WRITE, struct_ppp_rawin_sz); | ||
| 703 | _(PPPIOCGFLAGS, WRITE, sizeof(int)); | ||
| 704 | _(PPPIOCSFLAGS, READ, sizeof(int)); | ||
| 705 | _(PPPIOCGASYNCMAP, WRITE, sizeof(int)); | ||
| 706 | _(PPPIOCSASYNCMAP, READ, sizeof(int)); | ||
| 707 | _(PPPIOCGUNIT, WRITE, sizeof(int)); | ||
| 708 | _(PPPIOCGRASYNCMAP, WRITE, sizeof(int)); | ||
| 709 | _(PPPIOCSRASYNCMAP, READ, sizeof(int)); | ||
| 710 | _(PPPIOCGMRU, WRITE, sizeof(int)); | ||
| 711 | _(PPPIOCSMRU, READ, sizeof(int)); | ||
| 712 | _(PPPIOCSMAXCID, READ, sizeof(int)); | ||
| 713 | _(PPPIOCGXASYNCMAP, WRITE, (8 * sizeof(u32))); | ||
| 714 | _(PPPIOCSXASYNCMAP, READ, (8 * sizeof(u32))); | ||
| 715 | _(PPPIOCXFERUNIT, NONE, 0); | ||
| 716 | _(PPPIOCSCOMPRESS, READ, struct_ppp_option_data_sz); | ||
| 717 | _(PPPIOCGNPMODE, READWRITE, struct_npioctl_sz); | ||
| 718 | _(PPPIOCSNPMODE, READ, struct_npioctl_sz); | ||
| 719 | _(PPPIOCGIDLE, WRITE, struct_ppp_idle_sz); | ||
| 720 | _(PPPIOCGMTU, WRITE, sizeof(int)); | ||
| 721 | _(PPPIOCSMTU, READ, sizeof(int)); | ||
| 722 | _(SIOCGPPPSTATS, READWRITE, struct_ifpppstatsreq_sz); | ||
| 723 | _(SIOCGPPPCSTATS, READWRITE, struct_ifpppcstatsreq_sz); | ||
| 724 | /* Entries from file: net/npf.h */ | ||
| 725 | _(IOC_NPF_VERSION, WRITE, sizeof(int)); | ||
| 726 | _(IOC_NPF_SWITCH, READ, sizeof(int)); | ||
| 727 | _(IOC_NPF_LOAD, READWRITE, struct_nvlist_ref_sz); | ||
| 728 | _(IOC_NPF_TABLE, READ, struct_npf_ioctl_table_sz); | ||
| 729 | _(IOC_NPF_STATS, READ, sizeof(uptr)); | ||
| 730 | _(IOC_NPF_SAVE, WRITE, struct_nvlist_ref_sz); | ||
| 731 | _(IOC_NPF_RULE, READWRITE, struct_nvlist_ref_sz); | ||
| 732 | _(IOC_NPF_CONN_LOOKUP, READWRITE, struct_nvlist_ref_sz); | ||
| 733 | _(IOC_NPF_TABLE_REPLACE, READWRITE, struct_nvlist_ref_sz); | ||
| 734 | /* Entries from file: net/if_pppoe.h */ | ||
| 735 | _(PPPOESETPARMS, READ, struct_pppoediscparms_sz); | ||
| 736 | _(PPPOEGETPARMS, READWRITE, struct_pppoediscparms_sz); | ||
| 737 | _(PPPOEGETSESSION, READWRITE, struct_pppoeconnectionstate_sz); | ||
| 738 | /* Entries from file: net/if_sppp.h */ | ||
| 739 | _(SPPPGETAUTHCFG, READWRITE, struct_spppauthcfg_sz); | ||
| 740 | _(SPPPSETAUTHCFG, READ, struct_spppauthcfg_sz); | ||
| 741 | _(SPPPGETLCPCFG, READWRITE, struct_sppplcpcfg_sz); | ||
| 742 | _(SPPPSETLCPCFG, READ, struct_sppplcpcfg_sz); | ||
| 743 | _(SPPPGETSTATUS, READWRITE, struct_spppstatus_sz); | ||
| 744 | _(SPPPGETSTATUSNCP, READWRITE, struct_spppstatusncp_sz); | ||
| 745 | _(SPPPGETIDLETO, READWRITE, struct_spppidletimeout_sz); | ||
| 746 | _(SPPPSETIDLETO, READ, struct_spppidletimeout_sz); | ||
| 747 | _(SPPPGETAUTHFAILURES, READWRITE, struct_spppauthfailurestats_sz); | ||
| 748 | _(SPPPSETAUTHFAILURE, READ, struct_spppauthfailuresettings_sz); | ||
| 749 | _(SPPPSETDNSOPTS, READ, struct_spppdnssettings_sz); | ||
| 750 | _(SPPPGETDNSOPTS, READWRITE, struct_spppdnssettings_sz); | ||
| 751 | _(SPPPGETDNSADDRS, READWRITE, struct_spppdnsaddrs_sz); | ||
| 752 | _(SPPPSETKEEPALIVE, READ, struct_spppkeepalivesettings_sz); | ||
| 753 | _(SPPPGETKEEPALIVE, READWRITE, struct_spppkeepalivesettings_sz); | ||
| 754 | /* Entries from file: net/if_srt.h */ | ||
| 755 | _(SRT_GETNRT, WRITE, sizeof(unsigned int)); | ||
| 756 | _(SRT_GETRT, READWRITE, struct_srt_rt_sz); | ||
| 757 | _(SRT_SETRT, READ, struct_srt_rt_sz); | ||
| 758 | _(SRT_DELRT, READ, sizeof(unsigned int)); | ||
| 759 | _(SRT_SFLAGS, READ, sizeof(unsigned int)); | ||
| 760 | _(SRT_GFLAGS, WRITE, sizeof(unsigned int)); | ||
| 761 | _(SRT_SGFLAGS, READWRITE, sizeof(unsigned int)); | ||
| 762 | _(SRT_DEBUG, READ, sizeof(uptr)); | ||
| 763 | /* Entries from file: net/if_tap.h */ | ||
| 764 | _(TAPGIFNAME, WRITE, struct_ifreq_sz); | ||
| 765 | /* Entries from file: net/if_tun.h */ | ||
| 766 | _(TUNSDEBUG, READ, sizeof(int)); | ||
| 767 | _(TUNGDEBUG, WRITE, sizeof(int)); | ||
| 768 | _(TUNSIFMODE, READ, sizeof(int)); | ||
| 769 | _(TUNSIFHEAD, READ, sizeof(int)); | ||
| 770 | _(TUNGIFHEAD, WRITE, sizeof(int)); | ||
| 771 | /* Entries from file: net/pfvar.h */ | ||
| 772 | _(DIOCSTART, NONE, 0); | ||
| 773 | _(DIOCSTOP, NONE, 0); | ||
| 774 | _(DIOCADDRULE, READWRITE, struct_pfioc_rule_sz); | ||
| 775 | _(DIOCGETRULES, READWRITE, struct_pfioc_rule_sz); | ||
| 776 | _(DIOCGETRULE, READWRITE, struct_pfioc_rule_sz); | ||
| 777 | _(DIOCSETLCK, READWRITE, sizeof(u32)); | ||
| 778 | _(DIOCCLRSTATES, READWRITE, struct_pfioc_state_kill_sz); | ||
| 779 | _(DIOCGETSTATE, READWRITE, struct_pfioc_state_sz); | ||
| 780 | _(DIOCSETSTATUSIF, READWRITE, struct_pfioc_if_sz); | ||
| 781 | _(DIOCGETSTATUS, READWRITE, struct_pf_status_sz); | ||
| 782 | _(DIOCCLRSTATUS, NONE, 0); | ||
| 783 | _(DIOCNATLOOK, READWRITE, struct_pfioc_natlook_sz); | ||
| 784 | _(DIOCSETDEBUG, READWRITE, sizeof(u32)); | ||
| 785 | _(DIOCGETSTATES, READWRITE, struct_pfioc_states_sz); | ||
| 786 | _(DIOCCHANGERULE, READWRITE, struct_pfioc_rule_sz); | ||
| 787 | _(DIOCSETTIMEOUT, READWRITE, struct_pfioc_tm_sz); | ||
| 788 | _(DIOCGETTIMEOUT, READWRITE, struct_pfioc_tm_sz); | ||
| 789 | _(DIOCADDSTATE, READWRITE, struct_pfioc_state_sz); | ||
| 790 | _(DIOCCLRRULECTRS, NONE, 0); | ||
| 791 | _(DIOCGETLIMIT, READWRITE, struct_pfioc_limit_sz); | ||
| 792 | _(DIOCSETLIMIT, READWRITE, struct_pfioc_limit_sz); | ||
| 793 | _(DIOCKILLSTATES, READWRITE, struct_pfioc_state_kill_sz); | ||
| 794 | _(DIOCSTARTALTQ, NONE, 0); | ||
| 795 | _(DIOCSTOPALTQ, NONE, 0); | ||
| 796 | _(DIOCADDALTQ, READWRITE, struct_pfioc_altq_sz); | ||
| 797 | _(DIOCGETALTQS, READWRITE, struct_pfioc_altq_sz); | ||
| 798 | _(DIOCGETALTQ, READWRITE, struct_pfioc_altq_sz); | ||
| 799 | _(DIOCCHANGEALTQ, READWRITE, struct_pfioc_altq_sz); | ||
| 800 | _(DIOCGETQSTATS, READWRITE, struct_pfioc_qstats_sz); | ||
| 801 | _(DIOCBEGINADDRS, READWRITE, struct_pfioc_pooladdr_sz); | ||
| 802 | _(DIOCADDADDR, READWRITE, struct_pfioc_pooladdr_sz); | ||
| 803 | _(DIOCGETADDRS, READWRITE, struct_pfioc_pooladdr_sz); | ||
| 804 | _(DIOCGETADDR, READWRITE, struct_pfioc_pooladdr_sz); | ||
| 805 | _(DIOCCHANGEADDR, READWRITE, struct_pfioc_pooladdr_sz); | ||
| 806 | _(DIOCADDSTATES, READWRITE, struct_pfioc_states_sz); | ||
| 807 | _(DIOCGETRULESETS, READWRITE, struct_pfioc_ruleset_sz); | ||
| 808 | _(DIOCGETRULESET, READWRITE, struct_pfioc_ruleset_sz); | ||
| 809 | _(DIOCRCLRTABLES, READWRITE, struct_pfioc_table_sz); | ||
| 810 | _(DIOCRADDTABLES, READWRITE, struct_pfioc_table_sz); | ||
| 811 | _(DIOCRDELTABLES, READWRITE, struct_pfioc_table_sz); | ||
| 812 | _(DIOCRGETTABLES, READWRITE, struct_pfioc_table_sz); | ||
| 813 | _(DIOCRGETTSTATS, READWRITE, struct_pfioc_table_sz); | ||
| 814 | _(DIOCRCLRTSTATS, READWRITE, struct_pfioc_table_sz); | ||
| 815 | _(DIOCRCLRADDRS, READWRITE, struct_pfioc_table_sz); | ||
| 816 | _(DIOCRADDADDRS, READWRITE, struct_pfioc_table_sz); | ||
| 817 | _(DIOCRDELADDRS, READWRITE, struct_pfioc_table_sz); | ||
| 818 | _(DIOCRSETADDRS, READWRITE, struct_pfioc_table_sz); | ||
| 819 | _(DIOCRGETADDRS, READWRITE, struct_pfioc_table_sz); | ||
| 820 | _(DIOCRGETASTATS, READWRITE, struct_pfioc_table_sz); | ||
| 821 | _(DIOCRCLRASTATS, READWRITE, struct_pfioc_table_sz); | ||
| 822 | _(DIOCRTSTADDRS, READWRITE, struct_pfioc_table_sz); | ||
| 823 | _(DIOCRSETTFLAGS, READWRITE, struct_pfioc_table_sz); | ||
| 824 | _(DIOCRINADEFINE, READWRITE, struct_pfioc_table_sz); | ||
| 825 | _(DIOCOSFPFLUSH, NONE, 0); | ||
| 826 | _(DIOCOSFPADD, READWRITE, struct_pf_osfp_ioctl_sz); | ||
| 827 | _(DIOCOSFPGET, READWRITE, struct_pf_osfp_ioctl_sz); | ||
| 828 | _(DIOCXBEGIN, READWRITE, struct_pfioc_trans_sz); | ||
| 829 | _(DIOCXCOMMIT, READWRITE, struct_pfioc_trans_sz); | ||
| 830 | _(DIOCXROLLBACK, READWRITE, struct_pfioc_trans_sz); | ||
| 831 | _(DIOCGETSRCNODES, READWRITE, struct_pfioc_src_nodes_sz); | ||
| 832 | _(DIOCCLRSRCNODES, NONE, 0); | ||
| 833 | _(DIOCSETHOSTID, READWRITE, sizeof(u32)); | ||
| 834 | _(DIOCIGETIFACES, READWRITE, struct_pfioc_iface_sz); | ||
| 835 | _(DIOCSETIFFLAG, READWRITE, struct_pfioc_iface_sz); | ||
| 836 | _(DIOCCLRIFFLAG, READWRITE, struct_pfioc_iface_sz); | ||
| 837 | _(DIOCKILLSRCNODES, READWRITE, struct_pfioc_src_node_kill_sz); | ||
| 838 | /* Entries from file: netbt/hci.h */ | ||
| 839 | _(SIOCGBTINFO, READWRITE, struct_btreq_sz); | ||
| 840 | _(SIOCGBTINFOA, READWRITE, struct_btreq_sz); | ||
| 841 | _(SIOCNBTINFO, READWRITE, struct_btreq_sz); | ||
| 842 | _(SIOCSBTFLAGS, READWRITE, struct_btreq_sz); | ||
| 843 | _(SIOCSBTPOLICY, READWRITE, struct_btreq_sz); | ||
| 844 | _(SIOCSBTPTYPE, READWRITE, struct_btreq_sz); | ||
| 845 | _(SIOCGBTSTATS, READWRITE, struct_btreq_sz); | ||
| 846 | _(SIOCZBTSTATS, READWRITE, struct_btreq_sz); | ||
| 847 | _(SIOCBTDUMP, READ, struct_btreq_sz); | ||
| 848 | _(SIOCSBTSCOMTU, READWRITE, struct_btreq_sz); | ||
| 849 | _(SIOCGBTFEAT, READWRITE, struct_btreq_sz); | ||
| 850 | /* Entries from file: netinet/ip_nat.h */ | ||
| 851 | _(SIOCADNAT, READ, struct_ipfobj_sz); | ||
| 852 | _(SIOCRMNAT, READ, struct_ipfobj_sz); | ||
| 853 | _(SIOCGNATS, READWRITE, struct_ipfobj_sz); | ||
| 854 | _(SIOCGNATL, READWRITE, struct_ipfobj_sz); | ||
| 855 | _(SIOCPURGENAT, READWRITE, struct_ipfobj_sz); | ||
| 856 | /* Entries from file: netinet/sctp_uio.h */ | ||
| 857 | _(SIOCCONNECTX, READWRITE, struct_sctp_connectx_addrs_sz); | ||
| 858 | _(SIOCCONNECTXDEL, READWRITE, struct_sctp_connectx_addrs_sz); | ||
| 859 | /* Entries from file: netinet6/in6_var.h */ | ||
| 860 | _(SIOCSIFINFO_FLAGS, READWRITE, struct_in6_ndireq_sz); | ||
| 861 | _(SIOCAADDRCTL_POLICY, READ, struct_in6_addrpolicy_sz); | ||
| 862 | _(SIOCDADDRCTL_POLICY, READ, struct_in6_addrpolicy_sz); | ||
| 863 | /* Entries from file: netsmb/smb_dev.h */ | ||
| 864 | _(SMBIOC_OPENSESSION, READ, struct_smbioc_ossn_sz); | ||
| 865 | _(SMBIOC_OPENSHARE, READ, struct_smbioc_oshare_sz); | ||
| 866 | _(SMBIOC_REQUEST, READWRITE, struct_smbioc_rq_sz); | ||
| 867 | _(SMBIOC_SETFLAGS, READ, struct_smbioc_flags_sz); | ||
| 868 | _(SMBIOC_LOOKUP, READ, struct_smbioc_lookup_sz); | ||
| 869 | _(SMBIOC_READ, READWRITE, struct_smbioc_rw_sz); | ||
| 870 | _(SMBIOC_WRITE, READWRITE, struct_smbioc_rw_sz); | ||
| 871 | /* Entries from file: sys/agpio.h */ | ||
| 872 | _(AGPIOC_INFO, WRITE, struct__agp_info_sz); | ||
| 873 | _(AGPIOC_ACQUIRE, NONE, 0); | ||
| 874 | _(AGPIOC_RELEASE, NONE, 0); | ||
| 875 | _(AGPIOC_SETUP, READ, struct__agp_setup_sz); | ||
| 876 | _(AGPIOC_ALLOCATE, READWRITE, struct__agp_allocate_sz); | ||
| 877 | _(AGPIOC_DEALLOCATE, READ, sizeof(int)); | ||
| 878 | _(AGPIOC_BIND, READ, struct__agp_bind_sz); | ||
| 879 | _(AGPIOC_UNBIND, READ, struct__agp_unbind_sz); | ||
| 880 | /* Entries from file: sys/audioio.h */ | ||
| 881 | _(AUDIO_GETINFO, WRITE, struct_audio_info_sz); | ||
| 882 | _(AUDIO_SETINFO, READWRITE, struct_audio_info_sz); | ||
| 883 | _(AUDIO_DRAIN, NONE, 0); | ||
| 884 | _(AUDIO_FLUSH, NONE, 0); | ||
| 885 | _(AUDIO_WSEEK, WRITE, sizeof(unsigned long)); | ||
| 886 | _(AUDIO_RERROR, WRITE, sizeof(int)); | ||
| 887 | _(AUDIO_GETDEV, WRITE, struct_audio_device_sz); | ||
| 888 | _(AUDIO_GETENC, READWRITE, struct_audio_encoding_sz); | ||
| 889 | _(AUDIO_GETFD, WRITE, sizeof(int)); | ||
| 890 | _(AUDIO_SETFD, READWRITE, sizeof(int)); | ||
| 891 | _(AUDIO_PERROR, WRITE, sizeof(int)); | ||
| 892 | _(AUDIO_GETIOFFS, WRITE, struct_audio_offset_sz); | ||
| 893 | _(AUDIO_GETOOFFS, WRITE, struct_audio_offset_sz); | ||
| 894 | _(AUDIO_GETPROPS, WRITE, sizeof(int)); | ||
| 895 | _(AUDIO_GETBUFINFO, WRITE, struct_audio_info_sz); | ||
| 896 | _(AUDIO_SETCHAN, READ, sizeof(int)); | ||
| 897 | _(AUDIO_GETCHAN, WRITE, sizeof(int)); | ||
| 898 | _(AUDIO_QUERYFORMAT, READWRITE, struct_audio_format_query_sz); | ||
| 899 | _(AUDIO_GETFORMAT, WRITE, struct_audio_info_sz); | ||
| 900 | _(AUDIO_SETFORMAT, READ, struct_audio_info_sz); | ||
| 901 | _(AUDIO_MIXER_READ, READWRITE, struct_mixer_ctrl_sz); | ||
| 902 | _(AUDIO_MIXER_WRITE, READWRITE, struct_mixer_ctrl_sz); | ||
| 903 | _(AUDIO_MIXER_DEVINFO, READWRITE, struct_mixer_devinfo_sz); | ||
| 904 | /* Entries from file: sys/ataio.h */ | ||
| 905 | _(ATAIOCCOMMAND, READWRITE, struct_atareq_sz); | ||
| 906 | _(ATABUSIOSCAN, READ, struct_atabusioscan_args_sz); | ||
| 907 | _(ATABUSIORESET, NONE, 0); | ||
| 908 | _(ATABUSIODETACH, READ, struct_atabusiodetach_args_sz); | ||
| 909 | /* Entries from file: sys/cdio.h */ | ||
| 910 | _(CDIOCPLAYTRACKS, READ, struct_ioc_play_track_sz); | ||
| 911 | _(CDIOCPLAYBLOCKS, READ, struct_ioc_play_blocks_sz); | ||
| 912 | _(CDIOCREADSUBCHANNEL, READWRITE, struct_ioc_read_subchannel_sz); | ||
| 913 | _(CDIOREADTOCHEADER, WRITE, struct_ioc_toc_header_sz); | ||
| 914 | _(CDIOREADTOCENTRIES, READWRITE, struct_ioc_read_toc_entry_sz); | ||
| 915 | _(CDIOREADMSADDR, READWRITE, sizeof(int)); | ||
| 916 | _(CDIOCSETPATCH, READ, struct_ioc_patch_sz); | ||
| 917 | _(CDIOCGETVOL, WRITE, struct_ioc_vol_sz); | ||
| 918 | _(CDIOCSETVOL, READ, struct_ioc_vol_sz); | ||
| 919 | _(CDIOCSETMONO, NONE, 0); | ||
| 920 | _(CDIOCSETSTEREO, NONE, 0); | ||
| 921 | _(CDIOCSETMUTE, NONE, 0); | ||
| 922 | _(CDIOCSETLEFT, NONE, 0); | ||
| 923 | _(CDIOCSETRIGHT, NONE, 0); | ||
| 924 | _(CDIOCSETDEBUG, NONE, 0); | ||
| 925 | _(CDIOCCLRDEBUG, NONE, 0); | ||
| 926 | _(CDIOCPAUSE, NONE, 0); | ||
| 927 | _(CDIOCRESUME, NONE, 0); | ||
| 928 | _(CDIOCRESET, NONE, 0); | ||
| 929 | _(CDIOCSTART, NONE, 0); | ||
| 930 | _(CDIOCSTOP, NONE, 0); | ||
| 931 | _(CDIOCEJECT, NONE, 0); | ||
| 932 | _(CDIOCALLOW, NONE, 0); | ||
| 933 | _(CDIOCPREVENT, NONE, 0); | ||
| 934 | _(CDIOCCLOSE, NONE, 0); | ||
| 935 | _(CDIOCPLAYMSF, READ, struct_ioc_play_msf_sz); | ||
| 936 | _(CDIOCLOADUNLOAD, READ, struct_ioc_load_unload_sz); | ||
| 937 | /* Entries from file: sys/chio.h */ | ||
| 938 | _(CHIOMOVE, READ, struct_changer_move_request_sz); | ||
| 939 | _(CHIOEXCHANGE, READ, struct_changer_exchange_request_sz); | ||
| 940 | _(CHIOPOSITION, READ, struct_changer_position_request_sz); | ||
| 941 | _(CHIOSPICKER, READ, sizeof(int)); | ||
| 942 | _(CHIOGPARAMS, WRITE, struct_changer_params_sz); | ||
| 943 | _(CHIOIELEM, NONE, 0); | ||
| 944 | _(OCHIOGSTATUS, READ, struct_ochanger_element_status_request_sz); | ||
| 945 | _(CHIOGSTATUS, READ, struct_changer_element_status_request_sz); | ||
| 946 | _(CHIOSVOLTAG, READ, struct_changer_set_voltag_request_sz); | ||
| 947 | /* Entries from file: sys/clockctl.h */ | ||
| 948 | _(CLOCKCTL_SETTIMEOFDAY, READ, struct_clockctl_settimeofday_sz); | ||
| 949 | _(CLOCKCTL_ADJTIME, READWRITE, struct_clockctl_adjtime_sz); | ||
| 950 | _(CLOCKCTL_CLOCK_SETTIME, READ, struct_clockctl_clock_settime_sz); | ||
| 951 | _(CLOCKCTL_NTP_ADJTIME, READWRITE, struct_clockctl_ntp_adjtime_sz); | ||
| 952 | /* Entries from file: sys/cpuio.h */ | ||
| 953 | _(IOC_CPU_SETSTATE, READ, struct_cpustate_sz); | ||
| 954 | _(IOC_CPU_GETSTATE, READWRITE, struct_cpustate_sz); | ||
| 955 | _(IOC_CPU_GETCOUNT, WRITE, sizeof(int)); | ||
| 956 | _(IOC_CPU_MAPID, READWRITE, sizeof(int)); | ||
| 957 | _(IOC_CPU_UCODE_GET_VERSION, READWRITE, struct_cpu_ucode_version_sz); | ||
| 958 | _(IOC_CPU_UCODE_APPLY, READ, struct_cpu_ucode_sz); | ||
| 959 | /* Entries from file: sys/dkio.h */ | ||
| 960 | _(DIOCGDINFO, WRITE, struct_disklabel_sz); | ||
| 961 | _(DIOCSDINFO, READ, struct_disklabel_sz); | ||
| 962 | _(DIOCWDINFO, READ, 0); | ||
| 963 | _(DIOCRFORMAT, READWRITE, struct_format_op_sz); | ||
| 964 | _(DIOCWFORMAT, READWRITE, struct_format_op_sz); | ||
| 965 | _(DIOCSSTEP, READ, sizeof(int)); | ||
| 966 | _(DIOCSRETRIES, READ, sizeof(int)); | ||
| 967 | _(DIOCKLABEL, READ, sizeof(int)); | ||
| 968 | _(DIOCWLABEL, READ, sizeof(int)); | ||
| 969 | _(DIOCSBAD, READ, struct_dkbad_sz); | ||
| 970 | _(DIOCEJECT, READ, sizeof(int)); | ||
| 971 | _(ODIOCEJECT, NONE, 0); | ||
| 972 | _(DIOCLOCK, READ, sizeof(int)); | ||
| 973 | _(DIOCGDEFLABEL, WRITE, struct_disklabel_sz); | ||
| 974 | _(DIOCCLRLABEL, NONE, 0); | ||
| 975 | _(DIOCGCACHE, WRITE, sizeof(int)); | ||
| 976 | _(DIOCSCACHE, READ, sizeof(int)); | ||
| 977 | _(DIOCCACHESYNC, READ, sizeof(int)); | ||
| 978 | _(DIOCBSLIST, READWRITE, struct_disk_badsecinfo_sz); | ||
| 979 | _(DIOCBSFLUSH, NONE, 0); | ||
| 980 | _(DIOCAWEDGE, READWRITE, struct_dkwedge_info_sz); | ||
| 981 | _(DIOCGWEDGEINFO, WRITE, struct_dkwedge_info_sz); | ||
| 982 | _(DIOCDWEDGE, READ, struct_dkwedge_info_sz); | ||
| 983 | _(DIOCLWEDGES, READWRITE, struct_dkwedge_list_sz); | ||
| 984 | _(DIOCGSTRATEGY, WRITE, struct_disk_strategy_sz); | ||
| 985 | _(DIOCSSTRATEGY, READ, struct_disk_strategy_sz); | ||
| 986 | _(DIOCGDISKINFO, WRITE, struct_plistref_sz); | ||
| 987 | _(DIOCTUR, WRITE, sizeof(int)); | ||
| 988 | _(DIOCMWEDGES, WRITE, sizeof(int)); | ||
| 989 | _(DIOCGSECTORSIZE, WRITE, sizeof(unsigned int)); | ||
| 990 | _(DIOCGMEDIASIZE, WRITE, sizeof(uptr)); | ||
| 991 | _(DIOCRMWEDGES, WRITE, sizeof(int)); | ||
| 992 | /* Entries from file: sys/drvctlio.h */ | ||
| 993 | _(DRVDETACHDEV, READ, struct_devdetachargs_sz); | ||
| 994 | _(DRVRESCANBUS, READ, struct_devrescanargs_sz); | ||
| 995 | _(DRVCTLCOMMAND, READWRITE, struct_plistref_sz); | ||
| 996 | _(DRVRESUMEDEV, READ, struct_devpmargs_sz); | ||
| 997 | _(DRVLISTDEV, READWRITE, struct_devlistargs_sz); | ||
| 998 | _(DRVGETEVENT, WRITE, struct_plistref_sz); | ||
| 999 | _(DRVSUSPENDDEV, READ, struct_devpmargs_sz); | ||
| 1000 | /* Entries from file: sys/dvdio.h */ | ||
| 1001 | _(DVD_READ_STRUCT, READWRITE, union_dvd_struct_sz); | ||
| 1002 | _(DVD_WRITE_STRUCT, READWRITE, union_dvd_struct_sz); | ||
| 1003 | _(DVD_AUTH, READWRITE, union_dvd_authinfo_sz); | ||
| 1004 | /* Entries from file: sys/envsys.h */ | ||
| 1005 | _(ENVSYS_GETDICTIONARY, READWRITE, struct_plistref_sz); | ||
| 1006 | _(ENVSYS_SETDICTIONARY, READWRITE, struct_plistref_sz); | ||
| 1007 | _(ENVSYS_REMOVEPROPS, READWRITE, struct_plistref_sz); | ||
| 1008 | _(ENVSYS_GTREDATA, READWRITE, struct_envsys_tre_data_sz); | ||
| 1009 | _(ENVSYS_GTREINFO, READWRITE, struct_envsys_basic_info_sz); | ||
| 1010 | /* Entries from file: sys/event.h */ | ||
| 1011 | _(KFILTER_BYFILTER, READWRITE, struct_kfilter_mapping_sz); | ||
| 1012 | _(KFILTER_BYNAME, READWRITE, struct_kfilter_mapping_sz); | ||
| 1013 | /* Entries from file: sys/fdio.h */ | ||
| 1014 | _(FDIOCGETOPTS, WRITE, 0); | ||
| 1015 | _(FDIOCSETOPTS, READ, sizeof(int)); | ||
| 1016 | _(FDIOCSETFORMAT, READ, struct_fdformat_parms_sz); | ||
| 1017 | _(FDIOCGETFORMAT, WRITE, struct_fdformat_parms_sz); | ||
| 1018 | _(FDIOCFORMAT_TRACK, READ, struct_fdformat_cmd_sz); | ||
| 1019 | /* Entries from file: sys/filio.h */ | ||
| 1020 | _(FIOCLEX, NONE, 0); | ||
| 1021 | _(FIONCLEX, NONE, 0); | ||
| 1022 | _(FIOSEEKDATA, READWRITE, sizeof(uptr)); | ||
| 1023 | _(FIOSEEKHOLE, READWRITE, sizeof(uptr)); | ||
| 1024 | _(FIONREAD, WRITE, sizeof(int)); | ||
| 1025 | _(FIONBIO, READ, sizeof(int)); | ||
| 1026 | _(FIOASYNC, READ, sizeof(int)); | ||
| 1027 | _(FIOSETOWN, READ, sizeof(int)); | ||
| 1028 | _(FIOGETOWN, WRITE, sizeof(int)); | ||
| 1029 | _(OFIOGETBMAP, READWRITE, sizeof(u32)); | ||
| 1030 | _(FIOGETBMAP, READWRITE, sizeof(u64)); | ||
| 1031 | _(FIONWRITE, WRITE, sizeof(int)); | ||
| 1032 | _(FIONSPACE, WRITE, sizeof(int)); | ||
| 1033 | /* Entries from file: sys/gpio.h */ | ||
| 1034 | _(GPIOINFO, WRITE, struct_gpio_info_sz); | ||
| 1035 | _(GPIOSET, READWRITE, struct_gpio_set_sz); | ||
| 1036 | _(GPIOUNSET, READWRITE, struct_gpio_set_sz); | ||
| 1037 | _(GPIOREAD, READWRITE, struct_gpio_req_sz); | ||
| 1038 | _(GPIOWRITE, READWRITE, struct_gpio_req_sz); | ||
| 1039 | _(GPIOTOGGLE, READWRITE, struct_gpio_req_sz); | ||
| 1040 | _(GPIOATTACH, READWRITE, struct_gpio_attach_sz); | ||
| 1041 | /* Entries from file: sys/ioctl.h */ | ||
| 1042 | _(PTIOCNETBSD, READ, struct_ioctl_pt_sz); | ||
| 1043 | _(PTIOCSUNOS, READ, struct_ioctl_pt_sz); | ||
| 1044 | _(PTIOCLINUX, READ, struct_ioctl_pt_sz); | ||
| 1045 | _(PTIOCFREEBSD, READ, struct_ioctl_pt_sz); | ||
| 1046 | _(PTIOCULTRIX, READ, struct_ioctl_pt_sz); | ||
| 1047 | /* Entries from file: sys/ioctl_compat.h */ | ||
| 1048 | _(TIOCHPCL, NONE, 0); | ||
| 1049 | _(TIOCGETP, WRITE, struct_sgttyb_sz); | ||
| 1050 | _(TIOCSETP, READ, struct_sgttyb_sz); | ||
| 1051 | _(TIOCSETN, READ, 0); | ||
| 1052 | _(TIOCSETC, READ, struct_tchars_sz); | ||
| 1053 | _(TIOCGETC, WRITE, struct_tchars_sz); | ||
| 1054 | _(TIOCLBIS, READ, sizeof(int)); | ||
| 1055 | _(TIOCLBIC, READ, sizeof(int)); | ||
| 1056 | _(TIOCLSET, READ, sizeof(int)); | ||
| 1057 | _(TIOCLGET, WRITE, sizeof(int)); | ||
| 1058 | _(TIOCSLTC, READ, struct_ltchars_sz); | ||
| 1059 | _(TIOCGLTC, WRITE, struct_ltchars_sz); | ||
| 1060 | _(OTIOCCONS, NONE, 0); | ||
| 1061 | /* Entries from file: sys/joystick.h */ | ||
| 1062 | _(JOY_SETTIMEOUT, READ, sizeof(int)); | ||
| 1063 | _(JOY_GETTIMEOUT, WRITE, sizeof(int)); | ||
| 1064 | _(JOY_SET_X_OFFSET, READ, sizeof(int)); | ||
| 1065 | _(JOY_SET_Y_OFFSET, READ, sizeof(int)); | ||
| 1066 | _(JOY_GET_Y_OFFSET, WRITE, sizeof(int)); | ||
| 1067 | /* Entries from file: sys/ksyms.h */ | ||
| 1068 | _(OKIOCGSYMBOL, READ, struct_ksyms_ogsymbol_sz); | ||
| 1069 | _(OKIOCGVALUE, READ, struct_ksyms_ogsymbol_sz); | ||
| 1070 | _(KIOCGSIZE, WRITE, sizeof(int)); | ||
| 1071 | _(KIOCGVALUE, READWRITE, struct_ksyms_gvalue_sz); | ||
| 1072 | _(KIOCGSYMBOL, READWRITE, struct_ksyms_gsymbol_sz); | ||
| 1073 | /* Entries from file: sys/lua.h */ | ||
| 1074 | _(LUAINFO, READWRITE, struct_lua_info_sz); | ||
| 1075 | _(LUACREATE, READWRITE, struct_lua_create_sz); | ||
| 1076 | _(LUADESTROY, READWRITE, struct_lua_create_sz); | ||
| 1077 | _(LUAREQUIRE, READWRITE, struct_lua_require_sz); | ||
| 1078 | _(LUALOAD, READWRITE, struct_lua_load_sz); | ||
| 1079 | /* Entries from file: sys/midiio.h */ | ||
| 1080 | _(MIDI_PRETIME, READWRITE, sizeof(int)); | ||
| 1081 | _(MIDI_MPUMODE, READWRITE, sizeof(int)); | ||
| 1082 | _(MIDI_MPUCMD, READWRITE, struct_mpu_command_rec_sz); | ||
| 1083 | _(SEQUENCER_RESET, NONE, 0); | ||
| 1084 | _(SEQUENCER_SYNC, NONE, 0); | ||
| 1085 | _(SEQUENCER_INFO, READWRITE, struct_synth_info_sz); | ||
| 1086 | _(SEQUENCER_CTRLRATE, READWRITE, sizeof(int)); | ||
| 1087 | _(SEQUENCER_GETOUTCOUNT, WRITE, sizeof(int)); | ||
| 1088 | _(SEQUENCER_GETINCOUNT, WRITE, sizeof(int)); | ||
| 1089 | _(SEQUENCER_RESETSAMPLES, READ, sizeof(int)); | ||
| 1090 | _(SEQUENCER_NRSYNTHS, WRITE, sizeof(int)); | ||
| 1091 | _(SEQUENCER_NRMIDIS, WRITE, sizeof(int)); | ||
| 1092 | _(SEQUENCER_THRESHOLD, READ, sizeof(int)); | ||
| 1093 | _(SEQUENCER_MEMAVL, READWRITE, sizeof(int)); | ||
| 1094 | _(SEQUENCER_PANIC, NONE, 0); | ||
| 1095 | _(SEQUENCER_OUTOFBAND, READ, struct_seq_event_rec_sz); | ||
| 1096 | _(SEQUENCER_GETTIME, WRITE, sizeof(int)); | ||
| 1097 | _(SEQUENCER_TMR_TIMEBASE, READWRITE, sizeof(int)); | ||
| 1098 | _(SEQUENCER_TMR_START, NONE, 0); | ||
| 1099 | _(SEQUENCER_TMR_STOP, NONE, 0); | ||
| 1100 | _(SEQUENCER_TMR_CONTINUE, NONE, 0); | ||
| 1101 | _(SEQUENCER_TMR_TEMPO, READWRITE, sizeof(int)); | ||
| 1102 | _(SEQUENCER_TMR_SOURCE, READWRITE, sizeof(int)); | ||
| 1103 | _(SEQUENCER_TMR_METRONOME, READ, sizeof(int)); | ||
| 1104 | _(SEQUENCER_TMR_SELECT, READ, sizeof(int)); | ||
| 1105 | /* Entries from file: sys/mtio.h */ | ||
| 1106 | _(MTIOCTOP, READ, struct_mtop_sz); | ||
| 1107 | _(MTIOCGET, WRITE, struct_mtget_sz); | ||
| 1108 | _(MTIOCIEOT, NONE, 0); | ||
| 1109 | _(MTIOCEEOT, NONE, 0); | ||
| 1110 | _(MTIOCRDSPOS, WRITE, sizeof(u32)); | ||
| 1111 | _(MTIOCRDHPOS, WRITE, sizeof(u32)); | ||
| 1112 | _(MTIOCSLOCATE, READ, sizeof(u32)); | ||
| 1113 | _(MTIOCHLOCATE, READ, sizeof(u32)); | ||
| 1114 | /* Entries from file: sys/power.h */ | ||
| 1115 | _(POWER_EVENT_RECVDICT, READWRITE, struct_plistref_sz); | ||
| 1116 | _(POWER_IOC_GET_TYPE, WRITE, struct_power_type_sz); | ||
| 1117 | /* Entries from file: sys/radioio.h */ | ||
| 1118 | _(RIOCGINFO, WRITE, struct_radio_info_sz); | ||
| 1119 | _(RIOCSINFO, READWRITE, struct_radio_info_sz); | ||
| 1120 | _(RIOCSSRCH, READ, sizeof(int)); | ||
| 1121 | /* Entries from file: sys/rndio.h */ | ||
| 1122 | _(RNDGETENTCNT, WRITE, sizeof(u32)); | ||
| 1123 | _(RNDGETSRCNUM, READWRITE, struct_rndstat_sz); | ||
| 1124 | _(RNDGETSRCNAME, READWRITE, struct_rndstat_name_sz); | ||
| 1125 | _(RNDCTL, READ, struct_rndctl_sz); | ||
| 1126 | _(RNDADDDATA, READ, struct_rnddata_sz); | ||
| 1127 | _(RNDGETPOOLSTAT, WRITE, struct_rndpoolstat_sz); | ||
| 1128 | _(RNDGETESTNUM, READWRITE, struct_rndstat_est_sz); | ||
| 1129 | _(RNDGETESTNAME, READWRITE, struct_rndstat_est_name_sz); | ||
| 1130 | /* Entries from file: sys/scanio.h */ | ||
| 1131 | _(SCIOCGET, WRITE, struct_scan_io_sz); | ||
| 1132 | _(SCIOCSET, READ, struct_scan_io_sz); | ||
| 1133 | _(SCIOCRESTART, NONE, 0); | ||
| 1134 | /* Entries from file: sys/scsiio.h */ | ||
| 1135 | _(SCIOCCOMMAND, READWRITE, struct_scsireq_sz); | ||
| 1136 | _(SCIOCDEBUG, READ, sizeof(int)); | ||
| 1137 | _(SCIOCIDENTIFY, WRITE, struct_scsi_addr_sz); | ||
| 1138 | _(OSCIOCIDENTIFY, WRITE, struct_oscsi_addr_sz); | ||
| 1139 | _(SCIOCDECONFIG, NONE, 0); | ||
| 1140 | _(SCIOCRECONFIG, NONE, 0); | ||
| 1141 | _(SCIOCRESET, NONE, 0); | ||
| 1142 | _(SCBUSIOSCAN, READ, struct_scbusioscan_args_sz); | ||
| 1143 | _(SCBUSIORESET, NONE, 0); | ||
| 1144 | _(SCBUSIODETACH, READ, struct_scbusiodetach_args_sz); | ||
| 1145 | _(SCBUSACCEL, READ, struct_scbusaccel_args_sz); | ||
| 1146 | /* Entries from file: sys/sockio.h */ | ||
| 1147 | _(SIOCSHIWAT, READ, sizeof(int)); | ||
| 1148 | _(SIOCGHIWAT, WRITE, sizeof(int)); | ||
| 1149 | _(SIOCSLOWAT, READ, sizeof(int)); | ||
| 1150 | _(SIOCGLOWAT, WRITE, sizeof(int)); | ||
| 1151 | _(SIOCATMARK, WRITE, sizeof(int)); | ||
| 1152 | _(SIOCSPGRP, READ, sizeof(int)); | ||
| 1153 | _(SIOCGPGRP, WRITE, sizeof(int)); | ||
| 1154 | _(SIOCPEELOFF, READWRITE, sizeof(int)); | ||
| 1155 | _(SIOCADDRT, READ, struct_ortentry_sz); | ||
| 1156 | _(SIOCDELRT, READ, struct_ortentry_sz); | ||
| 1157 | _(SIOCSIFADDR, READ, struct_ifreq_sz); | ||
| 1158 | _(SIOCGIFADDR, READWRITE, struct_ifreq_sz); | ||
| 1159 | _(SIOCSIFDSTADDR, READ, struct_ifreq_sz); | ||
| 1160 | _(SIOCGIFDSTADDR, READWRITE, struct_ifreq_sz); | ||
| 1161 | _(SIOCSIFFLAGS, READ, struct_ifreq_sz); | ||
| 1162 | _(SIOCGIFFLAGS, READWRITE, struct_ifreq_sz); | ||
| 1163 | _(SIOCGIFBRDADDR, READWRITE, struct_ifreq_sz); | ||
| 1164 | _(SIOCSIFBRDADDR, READ, struct_ifreq_sz); | ||
| 1165 | _(SIOCGIFCONF, READWRITE, struct_ifconf_sz); | ||
| 1166 | _(SIOCGIFNETMASK, READWRITE, struct_ifreq_sz); | ||
| 1167 | _(SIOCSIFNETMASK, READ, struct_ifreq_sz); | ||
| 1168 | _(SIOCGIFMETRIC, READWRITE, struct_ifreq_sz); | ||
| 1169 | _(SIOCSIFMETRIC, READ, struct_ifreq_sz); | ||
| 1170 | _(SIOCDIFADDR, READ, struct_ifreq_sz); | ||
| 1171 | _(SIOCAIFADDR, READ, struct_ifaliasreq_sz); | ||
| 1172 | _(SIOCGIFALIAS, READWRITE, struct_ifaliasreq_sz); | ||
| 1173 | _(SIOCGIFAFLAG_IN, READWRITE, struct_ifreq_sz); | ||
| 1174 | _(SIOCALIFADDR, READ, struct_if_laddrreq_sz); | ||
| 1175 | _(SIOCGLIFADDR, READWRITE, struct_if_laddrreq_sz); | ||
| 1176 | _(SIOCDLIFADDR, READ, struct_if_laddrreq_sz); | ||
| 1177 | _(SIOCSIFADDRPREF, READ, struct_if_addrprefreq_sz); | ||
| 1178 | _(SIOCGIFADDRPREF, READWRITE, struct_if_addrprefreq_sz); | ||
| 1179 | _(SIOCADDMULTI, READ, struct_ifreq_sz); | ||
| 1180 | _(SIOCDELMULTI, READ, struct_ifreq_sz); | ||
| 1181 | _(SIOCGETVIFCNT, READWRITE, struct_sioc_vif_req_sz); | ||
| 1182 | _(SIOCGETSGCNT, READWRITE, struct_sioc_sg_req_sz); | ||
| 1183 | _(SIOCSIFMEDIA, READWRITE, struct_ifreq_sz); | ||
| 1184 | _(SIOCGIFMEDIA, READWRITE, struct_ifmediareq_sz); | ||
| 1185 | _(SIOCSIFGENERIC, READ, struct_ifreq_sz); | ||
| 1186 | _(SIOCGIFGENERIC, READWRITE, struct_ifreq_sz); | ||
| 1187 | _(SIOCSIFPHYADDR, READ, struct_ifaliasreq_sz); | ||
| 1188 | _(SIOCGIFPSRCADDR, READWRITE, struct_ifreq_sz); | ||
| 1189 | _(SIOCGIFPDSTADDR, READWRITE, struct_ifreq_sz); | ||
| 1190 | _(SIOCDIFPHYADDR, READ, struct_ifreq_sz); | ||
| 1191 | _(SIOCSLIFPHYADDR, READ, struct_if_laddrreq_sz); | ||
| 1192 | _(SIOCGLIFPHYADDR, READWRITE, struct_if_laddrreq_sz); | ||
| 1193 | _(SIOCSIFMTU, READ, struct_ifreq_sz); | ||
| 1194 | _(SIOCGIFMTU, READWRITE, struct_ifreq_sz); | ||
| 1195 | _(SIOCSDRVSPEC, READ, struct_ifdrv_sz); | ||
| 1196 | _(SIOCGDRVSPEC, READWRITE, struct_ifdrv_sz); | ||
| 1197 | _(SIOCIFCREATE, READ, struct_ifreq_sz); | ||
| 1198 | _(SIOCIFDESTROY, READ, struct_ifreq_sz); | ||
| 1199 | _(SIOCIFGCLONERS, READWRITE, struct_if_clonereq_sz); | ||
| 1200 | _(SIOCGIFDLT, READWRITE, struct_ifreq_sz); | ||
| 1201 | _(SIOCGIFCAP, READWRITE, struct_ifcapreq_sz); | ||
| 1202 | _(SIOCSIFCAP, READ, struct_ifcapreq_sz); | ||
| 1203 | _(SIOCSVH, READWRITE, struct_ifreq_sz); | ||
| 1204 | _(SIOCGVH, READWRITE, struct_ifreq_sz); | ||
| 1205 | _(SIOCINITIFADDR, READWRITE, struct_ifaddr_sz); | ||
| 1206 | _(SIOCGIFDATA, READWRITE, struct_ifdatareq_sz); | ||
| 1207 | _(SIOCZIFDATA, READWRITE, struct_ifdatareq_sz); | ||
| 1208 | _(SIOCGLINKSTR, READWRITE, struct_ifdrv_sz); | ||
| 1209 | _(SIOCSLINKSTR, READ, struct_ifdrv_sz); | ||
| 1210 | _(SIOCGETHERCAP, READWRITE, struct_eccapreq_sz); | ||
| 1211 | _(SIOCGIFINDEX, READWRITE, struct_ifreq_sz); | ||
| 1212 | _(SIOCSETHERCAP, READ, struct_eccapreq_sz); | ||
| 1213 | _(SIOCSIFDESCR, READ, struct_ifreq_sz); | ||
| 1214 | _(SIOCGIFDESCR, READWRITE, struct_ifreq_sz); | ||
| 1215 | _(SIOCGUMBINFO, READWRITE, struct_ifreq_sz); | ||
| 1216 | _(SIOCSUMBPARAM, READ, struct_ifreq_sz); | ||
| 1217 | _(SIOCGUMBPARAM, READWRITE, struct_ifreq_sz); | ||
| 1218 | _(SIOCSETPFSYNC, READ, struct_ifreq_sz); | ||
| 1219 | _(SIOCGETPFSYNC, READWRITE, struct_ifreq_sz); | ||
| 1220 | /* Entries from file: sys/timepps.h */ | ||
| 1221 | _(PPS_IOC_CREATE, NONE, 0); | ||
| 1222 | _(PPS_IOC_DESTROY, NONE, 0); | ||
| 1223 | _(PPS_IOC_SETPARAMS, READ, struct_pps_params_sz); | ||
| 1224 | _(PPS_IOC_GETPARAMS, WRITE, struct_pps_params_sz); | ||
| 1225 | _(PPS_IOC_GETCAP, WRITE, sizeof(int)); | ||
| 1226 | _(PPS_IOC_FETCH, READWRITE, struct_pps_info_sz); | ||
| 1227 | _(PPS_IOC_KCBIND, READ, sizeof(int)); | ||
| 1228 | /* Entries from file: sys/ttycom.h */ | ||
| 1229 | _(TIOCEXCL, NONE, 0); | ||
| 1230 | _(TIOCNXCL, NONE, 0); | ||
| 1231 | _(TIOCFLUSH, READ, sizeof(int)); | ||
| 1232 | _(TIOCGETA, WRITE, struct_termios_sz); | ||
| 1233 | _(TIOCSETA, READ, struct_termios_sz); | ||
| 1234 | _(TIOCSETAW, READ, 0); | ||
| 1235 | _(TIOCSETAF, READ, 0); | ||
| 1236 | _(TIOCGETD, WRITE, sizeof(int)); | ||
| 1237 | _(TIOCSETD, READ, sizeof(int)); | ||
| 1238 | _(TIOCGLINED, WRITE, (32 * sizeof(char))); | ||
| 1239 | _(TIOCSLINED, READ, (32 * sizeof(char))); | ||
| 1240 | _(TIOCSBRK, NONE, 0); | ||
| 1241 | _(TIOCCBRK, NONE, 0); | ||
| 1242 | _(TIOCSDTR, NONE, 0); | ||
| 1243 | _(TIOCCDTR, NONE, 0); | ||
| 1244 | _(TIOCGPGRP, WRITE, sizeof(int)); | ||
| 1245 | _(TIOCSPGRP, READ, sizeof(int)); | ||
| 1246 | _(TIOCOUTQ, WRITE, sizeof(int)); | ||
| 1247 | _(TIOCSTI, READ, sizeof(char)); | ||
| 1248 | _(TIOCNOTTY, NONE, 0); | ||
| 1249 | _(TIOCPKT, READ, sizeof(int)); | ||
| 1250 | _(TIOCSTOP, NONE, 0); | ||
| 1251 | _(TIOCSTART, NONE, 0); | ||
| 1252 | _(TIOCMSET, READ, sizeof(int)); | ||
| 1253 | _(TIOCMBIS, READ, sizeof(int)); | ||
| 1254 | _(TIOCMBIC, READ, sizeof(int)); | ||
| 1255 | _(TIOCMGET, WRITE, sizeof(int)); | ||
| 1256 | _(TIOCREMOTE, READ, sizeof(int)); | ||
| 1257 | _(TIOCGWINSZ, WRITE, struct_winsize_sz); | ||
| 1258 | _(TIOCSWINSZ, READ, struct_winsize_sz); | ||
| 1259 | _(TIOCUCNTL, READ, sizeof(int)); | ||
| 1260 | _(TIOCSTAT, READ, sizeof(int)); | ||
| 1261 | _(TIOCGSID, WRITE, sizeof(int)); | ||
| 1262 | _(TIOCCONS, READ, sizeof(int)); | ||
| 1263 | _(TIOCSCTTY, NONE, 0); | ||
| 1264 | _(TIOCEXT, READ, sizeof(int)); | ||
| 1265 | _(TIOCSIG, NONE, 0); | ||
| 1266 | _(TIOCDRAIN, NONE, 0); | ||
| 1267 | _(TIOCGFLAGS, WRITE, sizeof(int)); | ||
| 1268 | _(TIOCSFLAGS, READ, sizeof(int)); | ||
| 1269 | _(TIOCDCDTIMESTAMP, WRITE, struct_timeval_sz); | ||
| 1270 | _(TIOCRCVFRAME, READ, sizeof(uptr)); | ||
| 1271 | _(TIOCXMTFRAME, READ, sizeof(uptr)); | ||
| 1272 | _(TIOCPTMGET, WRITE, struct_ptmget_sz); | ||
| 1273 | _(TIOCGRANTPT, NONE, 0); | ||
| 1274 | _(TIOCPTSNAME, WRITE, struct_ptmget_sz); | ||
| 1275 | _(TIOCSQSIZE, READ, sizeof(int)); | ||
| 1276 | _(TIOCGQSIZE, WRITE, sizeof(int)); | ||
| 1277 | /* Entries from file: sys/verified_exec.h */ | ||
| 1278 | _(VERIEXEC_LOAD, READ, struct_plistref_sz); | ||
| 1279 | _(VERIEXEC_TABLESIZE, READ, struct_plistref_sz); | ||
| 1280 | _(VERIEXEC_DELETE, READ, struct_plistref_sz); | ||
| 1281 | _(VERIEXEC_QUERY, READWRITE, struct_plistref_sz); | ||
| 1282 | _(VERIEXEC_DUMP, WRITE, struct_plistref_sz); | ||
| 1283 | _(VERIEXEC_FLUSH, NONE, 0); | ||
| 1284 | /* Entries from file: sys/videoio.h */ | ||
| 1285 | _(VIDIOC_QUERYCAP, WRITE, struct_v4l2_capability_sz); | ||
| 1286 | _(VIDIOC_RESERVED, NONE, 0); | ||
| 1287 | _(VIDIOC_ENUM_FMT, READWRITE, struct_v4l2_fmtdesc_sz); | ||
| 1288 | _(VIDIOC_G_FMT, READWRITE, struct_v4l2_format_sz); | ||
| 1289 | _(VIDIOC_S_FMT, READWRITE, struct_v4l2_format_sz); | ||
| 1290 | _(VIDIOC_REQBUFS, READWRITE, struct_v4l2_requestbuffers_sz); | ||
| 1291 | _(VIDIOC_QUERYBUF, READWRITE, struct_v4l2_buffer_sz); | ||
| 1292 | _(VIDIOC_G_FBUF, WRITE, struct_v4l2_framebuffer_sz); | ||
| 1293 | _(VIDIOC_S_FBUF, READ, struct_v4l2_framebuffer_sz); | ||
| 1294 | _(VIDIOC_OVERLAY, READ, sizeof(int)); | ||
| 1295 | _(VIDIOC_QBUF, READWRITE, struct_v4l2_buffer_sz); | ||
| 1296 | _(VIDIOC_DQBUF, READWRITE, struct_v4l2_buffer_sz); | ||
| 1297 | _(VIDIOC_STREAMON, READ, sizeof(int)); | ||
| 1298 | _(VIDIOC_STREAMOFF, READ, sizeof(int)); | ||
| 1299 | _(VIDIOC_G_PARM, READWRITE, struct_v4l2_streamparm_sz); | ||
| 1300 | _(VIDIOC_S_PARM, READWRITE, struct_v4l2_streamparm_sz); | ||
| 1301 | _(VIDIOC_G_STD, WRITE, sizeof(u64)); | ||
| 1302 | _(VIDIOC_S_STD, READ, sizeof(u64)); | ||
| 1303 | _(VIDIOC_ENUMSTD, READWRITE, struct_v4l2_standard_sz); | ||
| 1304 | _(VIDIOC_ENUMINPUT, READWRITE, struct_v4l2_input_sz); | ||
| 1305 | _(VIDIOC_G_CTRL, READWRITE, struct_v4l2_control_sz); | ||
| 1306 | _(VIDIOC_S_CTRL, READWRITE, struct_v4l2_control_sz); | ||
| 1307 | _(VIDIOC_G_TUNER, READWRITE, struct_v4l2_tuner_sz); | ||
| 1308 | _(VIDIOC_S_TUNER, READ, struct_v4l2_tuner_sz); | ||
| 1309 | _(VIDIOC_G_AUDIO, WRITE, struct_v4l2_audio_sz); | ||
| 1310 | _(VIDIOC_S_AUDIO, READ, struct_v4l2_audio_sz); | ||
| 1311 | _(VIDIOC_QUERYCTRL, READWRITE, struct_v4l2_queryctrl_sz); | ||
| 1312 | _(VIDIOC_QUERYMENU, READWRITE, struct_v4l2_querymenu_sz); | ||
| 1313 | _(VIDIOC_G_INPUT, WRITE, sizeof(int)); | ||
| 1314 | _(VIDIOC_S_INPUT, READWRITE, sizeof(int)); | ||
| 1315 | _(VIDIOC_G_OUTPUT, WRITE, sizeof(int)); | ||
| 1316 | _(VIDIOC_S_OUTPUT, READWRITE, sizeof(int)); | ||
| 1317 | _(VIDIOC_ENUMOUTPUT, READWRITE, struct_v4l2_output_sz); | ||
| 1318 | _(VIDIOC_G_AUDOUT, WRITE, struct_v4l2_audioout_sz); | ||
| 1319 | _(VIDIOC_S_AUDOUT, READ, struct_v4l2_audioout_sz); | ||
| 1320 | _(VIDIOC_G_MODULATOR, READWRITE, struct_v4l2_modulator_sz); | ||
| 1321 | _(VIDIOC_S_MODULATOR, READ, struct_v4l2_modulator_sz); | ||
| 1322 | _(VIDIOC_G_FREQUENCY, READWRITE, struct_v4l2_frequency_sz); | ||
| 1323 | _(VIDIOC_S_FREQUENCY, READ, struct_v4l2_frequency_sz); | ||
| 1324 | _(VIDIOC_CROPCAP, READWRITE, struct_v4l2_cropcap_sz); | ||
| 1325 | _(VIDIOC_G_CROP, READWRITE, struct_v4l2_crop_sz); | ||
| 1326 | _(VIDIOC_S_CROP, READ, struct_v4l2_crop_sz); | ||
| 1327 | _(VIDIOC_G_JPEGCOMP, WRITE, struct_v4l2_jpegcompression_sz); | ||
| 1328 | _(VIDIOC_S_JPEGCOMP, READ, struct_v4l2_jpegcompression_sz); | ||
| 1329 | _(VIDIOC_QUERYSTD, WRITE, sizeof(u64)); | ||
| 1330 | _(VIDIOC_TRY_FMT, READWRITE, struct_v4l2_format_sz); | ||
| 1331 | _(VIDIOC_ENUMAUDIO, READWRITE, struct_v4l2_audio_sz); | ||
| 1332 | _(VIDIOC_ENUMAUDOUT, READWRITE, struct_v4l2_audioout_sz); | ||
| 1333 | _(VIDIOC_G_PRIORITY, WRITE, enum_v4l2_priority_sz); | ||
| 1334 | _(VIDIOC_S_PRIORITY, READ, enum_v4l2_priority_sz); | ||
| 1335 | _(VIDIOC_ENUM_FRAMESIZES, READWRITE, struct_v4l2_frmsizeenum_sz); | ||
| 1336 | _(VIDIOC_ENUM_FRAMEINTERVALS, READWRITE, struct_v4l2_frmivalenum_sz); | ||
| 1337 | /* Entries from file: sys/wdog.h */ | ||
| 1338 | _(WDOGIOC_GMODE, READWRITE, struct_wdog_mode_sz); | ||
| 1339 | _(WDOGIOC_SMODE, READ, struct_wdog_mode_sz); | ||
| 1340 | _(WDOGIOC_WHICH, WRITE, struct_wdog_mode_sz); | ||
| 1341 | _(WDOGIOC_TICKLE, NONE, 0); | ||
| 1342 | _(WDOGIOC_GTICKLER, WRITE, sizeof(int)); | ||
| 1343 | _(WDOGIOC_GWDOGS, READWRITE, struct_wdog_conf_sz); | ||
| 1344 | /* Entries from file: sys/kcov.h */ | ||
| 1345 | _(KCOV_IOC_SETBUFSIZE, READ, sizeof(u64)); | ||
| 1346 | _(KCOV_IOC_ENABLE, READ, sizeof(int)); | ||
| 1347 | _(KCOV_IOC_DISABLE, NONE, 0); | ||
| 1348 | /* Entries from file: sys/ipmi.h */ | ||
| 1349 | _(IPMICTL_RECEIVE_MSG_TRUNC, READWRITE, struct_ipmi_recv_sz); | ||
| 1350 | _(IPMICTL_RECEIVE_MSG, READWRITE, struct_ipmi_recv_sz); | ||
| 1351 | _(IPMICTL_SEND_COMMAND, READ, struct_ipmi_req_sz); | ||
| 1352 | _(IPMICTL_REGISTER_FOR_CMD, READ, struct_ipmi_cmdspec_sz); | ||
| 1353 | _(IPMICTL_UNREGISTER_FOR_CMD, READ, struct_ipmi_cmdspec_sz); | ||
| 1354 | _(IPMICTL_SET_GETS_EVENTS_CMD, READ, sizeof(int)); | ||
| 1355 | _(IPMICTL_SET_MY_ADDRESS_CMD, READ, sizeof(unsigned int)); | ||
| 1356 | _(IPMICTL_GET_MY_ADDRESS_CMD, WRITE, sizeof(unsigned int)); | ||
| 1357 | _(IPMICTL_SET_MY_LUN_CMD, READ, sizeof(unsigned int)); | ||
| 1358 | _(IPMICTL_GET_MY_LUN_CMD, WRITE, sizeof(unsigned int)); | ||
| 1359 | /* Entries from file: soundcard.h */ | ||
| 1360 | _(SNDCTL_DSP_RESET, NONE, 0); | ||
| 1361 | _(SNDCTL_DSP_SYNC, NONE, 0); | ||
| 1362 | _(SNDCTL_DSP_SPEED, READWRITE, sizeof(int)); | ||
| 1363 | _(SOUND_PCM_READ_RATE, WRITE, sizeof(int)); | ||
| 1364 | _(SNDCTL_DSP_STEREO, READWRITE, sizeof(int)); | ||
| 1365 | _(SNDCTL_DSP_GETBLKSIZE, READWRITE, sizeof(int)); | ||
| 1366 | _(SNDCTL_DSP_SETFMT, READWRITE, sizeof(int)); | ||
| 1367 | _(SOUND_PCM_READ_BITS, WRITE, sizeof(int)); | ||
| 1368 | _(SNDCTL_DSP_CHANNELS, READWRITE, sizeof(int)); | ||
| 1369 | _(SOUND_PCM_READ_CHANNELS, WRITE, sizeof(int)); | ||
| 1370 | _(SOUND_PCM_WRITE_FILTER, READWRITE, sizeof(int)); | ||
| 1371 | _(SOUND_PCM_READ_FILTER, WRITE, sizeof(int)); | ||
| 1372 | _(SNDCTL_DSP_POST, NONE, 0); | ||
| 1373 | _(SNDCTL_DSP_SUBDIVIDE, READWRITE, sizeof(int)); | ||
| 1374 | _(SNDCTL_DSP_SETFRAGMENT, READWRITE, sizeof(int)); | ||
| 1375 | _(SNDCTL_DSP_GETFMTS, WRITE, sizeof(int)); | ||
| 1376 | _(SNDCTL_DSP_GETOSPACE, WRITE, struct_audio_buf_info_sz); | ||
| 1377 | _(SNDCTL_DSP_GETISPACE, WRITE, struct_audio_buf_info_sz); | ||
| 1378 | _(SNDCTL_DSP_NONBLOCK, NONE, 0); | ||
| 1379 | _(SNDCTL_DSP_GETCAPS, WRITE, sizeof(int)); | ||
| 1380 | _(SNDCTL_DSP_GETTRIGGER, WRITE, sizeof(int)); | ||
| 1381 | _(SNDCTL_DSP_SETTRIGGER, READ, sizeof(int)); | ||
| 1382 | _(SNDCTL_DSP_GETIPTR, WRITE, struct_count_info_sz); | ||
| 1383 | _(SNDCTL_DSP_GETOPTR, WRITE, struct_count_info_sz); | ||
| 1384 | _(SNDCTL_DSP_MAPINBUF, WRITE, struct_buffmem_desc_sz); | ||
| 1385 | _(SNDCTL_DSP_MAPOUTBUF, WRITE, struct_buffmem_desc_sz); | ||
| 1386 | _(SNDCTL_DSP_SETSYNCRO, NONE, 0); | ||
| 1387 | _(SNDCTL_DSP_SETDUPLEX, NONE, 0); | ||
| 1388 | _(SNDCTL_DSP_PROFILE, READ, sizeof(int)); | ||
| 1389 | _(SNDCTL_DSP_GETODELAY, WRITE, sizeof(int)); | ||
| 1390 | _(SOUND_MIXER_INFO, WRITE, struct_mixer_info_sz); | ||
| 1391 | _(SOUND_OLD_MIXER_INFO, WRITE, struct__old_mixer_info_sz); | ||
| 1392 | _(OSS_GETVERSION, WRITE, sizeof(int)); | ||
| 1393 | _(SNDCTL_SYSINFO, WRITE, struct_oss_sysinfo_sz); | ||
| 1394 | _(SNDCTL_AUDIOINFO, READWRITE, struct_oss_audioinfo_sz); | ||
| 1395 | _(SNDCTL_ENGINEINFO, READWRITE, struct_oss_audioinfo_sz); | ||
| 1396 | _(SNDCTL_DSP_GETPLAYVOL, WRITE, sizeof(unsigned int)); | ||
| 1397 | _(SNDCTL_DSP_SETPLAYVOL, READ, sizeof(unsigned int)); | ||
| 1398 | _(SNDCTL_DSP_GETRECVOL, WRITE, sizeof(unsigned int)); | ||
| 1399 | _(SNDCTL_DSP_SETRECVOL, READ, sizeof(unsigned int)); | ||
| 1400 | _(SNDCTL_DSP_SKIP, NONE, 0); | ||
| 1401 | _(SNDCTL_DSP_SILENCE, NONE, 0); | ||
| 1402 | /* Entries from file: dev/filemon/filemon.h (compat <= 9.99.26) */ | ||
| 1403 | _(FILEMON_SET_FD, READWRITE, sizeof(int)); | ||
| 1404 | _(FILEMON_SET_PID, READWRITE, sizeof(int)); | ||
| 1405 | /* Entries from file: dev/usb/urio.h (compat <= 9.99.43) */ | ||
| 1406 | _(URIO_SEND_COMMAND, READWRITE, struct_urio_command_sz); | ||
| 1407 | _(URIO_RECV_COMMAND, READWRITE, struct_urio_command_sz); | ||
| 1408 | #undef _ | ||
| 1409 | } // NOLINT | ||
| 1410 | |||
| 1411 | static bool ioctl_initialized = false; | ||
| 1412 | |||
| 1413 | struct ioctl_desc_compare { | ||
| 1414 | bool operator()(const ioctl_desc &left, const ioctl_desc &right) const { | ||
| 1415 | return left.req < right.req; | ||
| 1416 | } | ||
| 1417 | }; | ||
| 1418 | |||
| 1419 | static void ioctl_init() { | ||
| 1420 | ioctl_table_fill(); | ||
| 1421 | Sort(ioctl_table, ioctl_table_size, ioctl_desc_compare()); | ||
| 1422 | |||
| 1423 | bool bad = false; | ||
| 1424 | for (unsigned i = 0; i < ioctl_table_size - 1; ++i) { | ||
| 1425 | if (ioctl_table[i].req >= ioctl_table[i + 1].req) { | ||
| 1426 | Printf("Duplicate or unsorted ioctl request id %x >= %x (%s vs %s)\n", | ||
| 1427 | ioctl_table[i].req, ioctl_table[i + 1].req, ioctl_table[i].name, | ||
| 1428 | ioctl_table[i + 1].name); | ||
| 1429 | bad = true; | ||
| 1430 | } | ||
| 1431 | } | ||
| 1432 | |||
| 1433 | if (bad) | ||
| 1434 | Die(); | ||
| 1435 | |||
| 1436 | ioctl_initialized = true; | ||
| 1437 | } | ||
| 1438 | |||
| 1439 | static const ioctl_desc *ioctl_table_lookup(unsigned req) { | ||
| 1440 | int left = 0; | ||
| 1441 | int right = ioctl_table_size; | ||
| 1442 | while (left < right) { | ||
| 1443 | int mid = (left + right) / 2; | ||
| 1444 | if (ioctl_table[mid].req < req) | ||
| 1445 | left = mid + 1; | ||
| 1446 | else | ||
| 1447 | right = mid; | ||
| 1448 | } | ||
| 1449 | if (left == right && ioctl_table[left].req == req) | ||
| 1450 | return ioctl_table + left; | ||
| 1451 | else | ||
| 1452 | return nullptr; | ||
| 1453 | } | ||
| 1454 | |||
| 1455 | static bool ioctl_decode(unsigned req, ioctl_desc *desc) { | ||
| 1456 | CHECK(desc); | ||
| 1457 | desc->req = req; | ||
| 1458 | desc->name = "<DECODED_IOCTL>"; | ||
| 1459 | desc->size = IOC_SIZE(req); | ||
| 1460 | // Sanity check. | ||
| 1461 | if (desc->size > 0xFFFF) | ||
| 1462 | return false; | ||
| 1463 | unsigned dir = IOC_DIR(req); | ||
| 1464 | switch (dir) { | ||
| 1465 | case IOC_NONE: | ||
| 1466 | desc->type = ioctl_desc::NONE; | ||
| 1467 | break; | ||
| 1468 | case IOC_READ | IOC_WRITE: | ||
| 1469 | desc->type = ioctl_desc::READWRITE; | ||
| 1470 | break; | ||
| 1471 | case IOC_READ: | ||
| 1472 | desc->type = ioctl_desc::WRITE; | ||
| 1473 | break; | ||
| 1474 | case IOC_WRITE: | ||
| 1475 | desc->type = ioctl_desc::READ; | ||
| 1476 | break; | ||
| 1477 | default: | ||
| 1478 | return false; | ||
| 1479 | } | ||
| 1480 | // Size can be 0 iff type is NONE. | ||
| 1481 | if ((desc->type == IOC_NONE) != (desc->size == 0)) | ||
| 1482 | return false; | ||
| 1483 | // Sanity check. | ||
| 1484 | if (IOC_TYPE(req) == 0) | ||
| 1485 | return false; | ||
| 1486 | return true; | ||
| 1487 | } | ||
| 1488 | |||
| 1489 | static const ioctl_desc *ioctl_lookup(unsigned req) { | ||
| 1490 | const ioctl_desc *desc = ioctl_table_lookup(req); | ||
| 1491 | if (desc) | ||
| 1492 | return desc; | ||
| 1493 | |||
| 1494 | // Try stripping access size from the request id. | ||
| 1495 | desc = ioctl_table_lookup(req & ~(IOC_SIZEMASK << IOC_SIZESHIFT)); | ||
| 1496 | // Sanity check: requests that encode access size are either read or write and | ||
| 1497 | // have size of 0 in the table. | ||
| 1498 | if (desc && desc->size == 0 && | ||
| 1499 | (desc->type == ioctl_desc::READWRITE || desc->type == ioctl_desc::WRITE || | ||
| 1500 | desc->type == ioctl_desc::READ)) | ||
| 1501 | return desc; | ||
| 1502 | return nullptr; | ||
| 1503 | } | ||
| 1504 | |||
| 1505 | static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d, | ||
| 1506 | unsigned request, void *arg) { | ||
| 1507 | if (desc->type == ioctl_desc::READ || desc->type == ioctl_desc::READWRITE) { | ||
| 1508 | unsigned size = desc->size ? desc->size : IOC_SIZE(request); | ||
| 1509 | COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size); | ||
| 1510 | } | ||
| 1511 | if (desc->type != ioctl_desc::CUSTOM) | ||
| 1512 | return; | ||
| 1513 | if (request == IOCTL_SIOCGIFCONF) { | ||
| 1514 | struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg; | ||
| 1515 | COMMON_INTERCEPTOR_READ_RANGE(ctx, (char *)&ifc->ifc_len, | ||
| 1516 | sizeof(ifc->ifc_len)); | ||
| 1517 | } | ||
| 1518 | } | ||
| 1519 | |||
| 1520 | static void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d, | ||
| 1521 | unsigned request, void *arg) { | ||
| 1522 | if (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READWRITE) { | ||
| 1523 | // FIXME: add verbose output | ||
| 1524 | unsigned size = desc->size ? desc->size : IOC_SIZE(request); | ||
| 1525 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size); | ||
| 1526 | } | ||
| 1527 | if (desc->type != ioctl_desc::CUSTOM) | ||
| 1528 | return; | ||
| 1529 | if (request == IOCTL_SIOCGIFCONF) { | ||
| 1530 | struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg; | ||
| 1531 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifc->ifc_ifcu.ifcu_req, ifc->ifc_len); | ||
| 1532 | } | ||
| 1533 | } | ||
| 1534 | |||
| 1535 | #endif // SANITIZER_NETBSD | ||
lib/tsan/sanitizer_common/sanitizer_interface_internal.h created+118| ... | @@ -0,0 +1,118 @@ | ||
| 1 | //===-- sanitizer_interface_internal.h --------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between run-time libraries of sanitizers. | ||
| 10 | // | ||
| 11 | // This header declares the sanitizer runtime interface functions. | ||
| 12 | // The runtime library has to define these functions so the instrumented program | ||
| 13 | // could call them. | ||
| 14 | // | ||
| 15 | // See also include/sanitizer/common_interface_defs.h | ||
| 16 | //===----------------------------------------------------------------------===// | ||
| 17 | #ifndef SANITIZER_INTERFACE_INTERNAL_H | ||
| 18 | #define SANITIZER_INTERFACE_INTERNAL_H | ||
| 19 | |||
| 20 | #include "sanitizer_internal_defs.h" | ||
| 21 | |||
| 22 | extern "C" { | ||
| 23 | // Tell the tools to write their reports to "path.<pid>" instead of stderr. | ||
| 24 | // The special values are "stdout" and "stderr". | ||
| 25 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 26 | void __sanitizer_set_report_path(const char *path); | ||
| 27 | // Tell the tools to write their reports to the provided file descriptor | ||
| 28 | // (casted to void *). | ||
| 29 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 30 | void __sanitizer_set_report_fd(void *fd); | ||
| 31 | |||
| 32 | typedef struct { | ||
| 33 | int coverage_sandboxed; | ||
| 34 | __sanitizer::sptr coverage_fd; | ||
| 35 | unsigned int coverage_max_block_size; | ||
| 36 | } __sanitizer_sandbox_arguments; | ||
| 37 | |||
| 38 | // Notify the tools that the sandbox is going to be turned on. | ||
| 39 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void | ||
| 40 | __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args); | ||
| 41 | |||
| 42 | // This function is called by the tool when it has just finished reporting | ||
| 43 | // an error. 'error_summary' is a one-line string that summarizes | ||
| 44 | // the error message. This function can be overridden by the client. | ||
| 45 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 46 | void __sanitizer_report_error_summary(const char *error_summary); | ||
| 47 | |||
| 48 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump(); | ||
| 49 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( | ||
| 50 | const __sanitizer::uptr *pcs, const __sanitizer::uptr len); | ||
| 51 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage(); | ||
| 52 | |||
| 53 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(__sanitizer::u32 *guard); | ||
| 54 | |||
| 55 | // Returns 1 on the first call, then returns 0 thereafter. Called by the tool | ||
| 56 | // to ensure only one report is printed when multiple errors occur | ||
| 57 | // simultaneously. | ||
| 58 | SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_acquire_crash_state(); | ||
| 59 | |||
| 60 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 61 | void __sanitizer_annotate_contiguous_container(const void *beg, | ||
| 62 | const void *end, | ||
| 63 | const void *old_mid, | ||
| 64 | const void *new_mid); | ||
| 65 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 66 | int __sanitizer_verify_contiguous_container(const void *beg, const void *mid, | ||
| 67 | const void *end); | ||
| 68 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 69 | const void *__sanitizer_contiguous_container_find_bad_address( | ||
| 70 | const void *beg, const void *mid, const void *end); | ||
| 71 | |||
| 72 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 73 | int __sanitizer_get_module_and_offset_for_pc( | ||
| 74 | __sanitizer::uptr pc, char *module_path, | ||
| 75 | __sanitizer::uptr module_path_len, __sanitizer::uptr *pc_offset); | ||
| 76 | |||
| 77 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 78 | void __sanitizer_cov_trace_cmp(); | ||
| 79 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 80 | void __sanitizer_cov_trace_cmp1(); | ||
| 81 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 82 | void __sanitizer_cov_trace_cmp2(); | ||
| 83 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 84 | void __sanitizer_cov_trace_cmp4(); | ||
| 85 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 86 | void __sanitizer_cov_trace_cmp8(); | ||
| 87 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 88 | void __sanitizer_cov_trace_const_cmp1(); | ||
| 89 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 90 | void __sanitizer_cov_trace_const_cmp2(); | ||
| 91 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 92 | void __sanitizer_cov_trace_const_cmp4(); | ||
| 93 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 94 | void __sanitizer_cov_trace_const_cmp8(); | ||
| 95 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 96 | void __sanitizer_cov_trace_switch(); | ||
| 97 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 98 | void __sanitizer_cov_trace_div4(); | ||
| 99 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 100 | void __sanitizer_cov_trace_div8(); | ||
| 101 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 102 | void __sanitizer_cov_trace_gep(); | ||
| 103 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 104 | void __sanitizer_cov_trace_pc_indir(); | ||
| 105 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 106 | void __sanitizer_cov_trace_pc_guard(__sanitizer::u32*); | ||
| 107 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 108 | void __sanitizer_cov_trace_pc_guard_init(__sanitizer::u32*, | ||
| 109 | __sanitizer::u32*); | ||
| 110 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 111 | void __sanitizer_cov_8bit_counters_init(); | ||
| 112 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void | ||
| 113 | __sanitizer_cov_bool_flag_init(); | ||
| 114 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void | ||
| 115 | __sanitizer_cov_pcs_init(); | ||
| 116 | } // extern "C" | ||
| 117 | |||
| 118 | #endif // SANITIZER_INTERFACE_INTERNAL_H | ||
lib/tsan/sanitizer_common/sanitizer_internal_defs.h created+459| ... | @@ -0,0 +1,459 @@ | ||
| 1 | //===-- sanitizer_internal_defs.h -------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer. | ||
| 10 | // It contains macro used in run-time libraries code. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_DEFS_H | ||
| 13 | #define SANITIZER_DEFS_H | ||
| 14 | |||
| 15 | #include "sanitizer_platform.h" | ||
| 16 | |||
| 17 | #ifndef SANITIZER_DEBUG | ||
| 18 | # define SANITIZER_DEBUG 0 | ||
| 19 | #endif | ||
| 20 | |||
| 21 | #define SANITIZER_STRINGIFY_(S) #S | ||
| 22 | #define SANITIZER_STRINGIFY(S) SANITIZER_STRINGIFY_(S) | ||
| 23 | |||
| 24 | // Only use SANITIZER_*ATTRIBUTE* before the function return type! | ||
| 25 | #if SANITIZER_WINDOWS | ||
| 26 | #if SANITIZER_IMPORT_INTERFACE | ||
| 27 | # define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllimport) | ||
| 28 | #else | ||
| 29 | # define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllexport) | ||
| 30 | #endif | ||
| 31 | # define SANITIZER_WEAK_ATTRIBUTE | ||
| 32 | #elif SANITIZER_GO | ||
| 33 | # define SANITIZER_INTERFACE_ATTRIBUTE | ||
| 34 | # define SANITIZER_WEAK_ATTRIBUTE | ||
| 35 | #else | ||
| 36 | # define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default"))) | ||
| 37 | # define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak)) | ||
| 38 | #endif | ||
| 39 | |||
| 40 | // TLS is handled differently on different platforms | ||
| 41 | #if SANITIZER_LINUX || SANITIZER_NETBSD || \ | ||
| 42 | SANITIZER_FREEBSD || SANITIZER_OPENBSD | ||
| 43 | # define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE \ | ||
| 44 | __attribute__((tls_model("initial-exec"))) thread_local | ||
| 45 | #else | ||
| 46 | # define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE | ||
| 47 | #endif | ||
| 48 | |||
| 49 | //--------------------------- WEAK FUNCTIONS ---------------------------------// | ||
| 50 | // When working with weak functions, to simplify the code and make it more | ||
| 51 | // portable, when possible define a default implementation using this macro: | ||
| 52 | // | ||
| 53 | // SANITIZER_INTERFACE_WEAK_DEF(<return_type>, <name>, <parameter list>) | ||
| 54 | // | ||
| 55 | // For example: | ||
| 56 | // SANITIZER_INTERFACE_WEAK_DEF(bool, compare, int a, int b) { return a > b; } | ||
| 57 | // | ||
| 58 | #if SANITIZER_WINDOWS | ||
| 59 | #include "sanitizer_win_defs.h" | ||
| 60 | # define SANITIZER_INTERFACE_WEAK_DEF(ReturnType, Name, ...) \ | ||
| 61 | WIN_WEAK_EXPORT_DEF(ReturnType, Name, __VA_ARGS__) | ||
| 62 | #else | ||
| 63 | # define SANITIZER_INTERFACE_WEAK_DEF(ReturnType, Name, ...) \ | ||
| 64 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE \ | ||
| 65 | ReturnType Name(__VA_ARGS__) | ||
| 66 | #endif | ||
| 67 | |||
| 68 | // SANITIZER_SUPPORTS_WEAK_HOOKS means that we support real weak functions that | ||
| 69 | // will evaluate to a null pointer when not defined. | ||
| 70 | #ifndef SANITIZER_SUPPORTS_WEAK_HOOKS | ||
| 71 | #if (SANITIZER_LINUX || SANITIZER_SOLARIS) && !SANITIZER_GO | ||
| 72 | # define SANITIZER_SUPPORTS_WEAK_HOOKS 1 | ||
| 73 | // Before Xcode 4.5, the Darwin linker doesn't reliably support undefined | ||
| 74 | // weak symbols. Mac OS X 10.9/Darwin 13 is the first release only supported | ||
| 75 | // by Xcode >= 4.5. | ||
| 76 | #elif SANITIZER_MAC && \ | ||
| 77 | __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1090 && !SANITIZER_GO | ||
| 78 | # define SANITIZER_SUPPORTS_WEAK_HOOKS 1 | ||
| 79 | #else | ||
| 80 | # define SANITIZER_SUPPORTS_WEAK_HOOKS 0 | ||
| 81 | #endif | ||
| 82 | #endif // SANITIZER_SUPPORTS_WEAK_HOOKS | ||
| 83 | // For some weak hooks that will be called very often and we want to avoid the | ||
| 84 | // overhead of executing the default implementation when it is not necessary, | ||
| 85 | // we can use the flag SANITIZER_SUPPORTS_WEAK_HOOKS to only define the default | ||
| 86 | // implementation for platforms that doesn't support weak symbols. For example: | ||
| 87 | // | ||
| 88 | // #if !SANITIZER_SUPPORT_WEAK_HOOKS | ||
| 89 | // SANITIZER_INTERFACE_WEAK_DEF(bool, compare_hook, int a, int b) { | ||
| 90 | // return a > b; | ||
| 91 | // } | ||
| 92 | // #endif | ||
| 93 | // | ||
| 94 | // And then use it as: if (compare_hook) compare_hook(a, b); | ||
| 95 | //----------------------------------------------------------------------------// | ||
| 96 | |||
| 97 | |||
| 98 | // We can use .preinit_array section on Linux to call sanitizer initialization | ||
| 99 | // functions very early in the process startup (unless PIC macro is defined). | ||
| 100 | // | ||
| 101 | // On FreeBSD, .preinit_array functions are called with rtld_bind_lock writer | ||
| 102 | // lock held. It will lead to dead lock if unresolved PLT functions (which helds | ||
| 103 | // rtld_bind_lock reader lock) are called inside .preinit_array functions. | ||
| 104 | // | ||
| 105 | // FIXME: do we have anything like this on Mac? | ||
| 106 | #ifndef SANITIZER_CAN_USE_PREINIT_ARRAY | ||
| 107 | #if ((SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_OPENBSD || \ | ||
| 108 | SANITIZER_FUCHSIA || SANITIZER_NETBSD) && !defined(PIC) | ||
| 109 | #define SANITIZER_CAN_USE_PREINIT_ARRAY 1 | ||
| 110 | // Before Solaris 11.4, .preinit_array is fully supported only with GNU ld. | ||
| 111 | // FIXME: Check for those conditions. | ||
| 112 | #elif SANITIZER_SOLARIS && !defined(PIC) | ||
| 113 | # define SANITIZER_CAN_USE_PREINIT_ARRAY 1 | ||
| 114 | #else | ||
| 115 | # define SANITIZER_CAN_USE_PREINIT_ARRAY 0 | ||
| 116 | #endif | ||
| 117 | #endif // SANITIZER_CAN_USE_PREINIT_ARRAY | ||
| 118 | |||
| 119 | // GCC does not understand __has_feature | ||
| 120 | #if !defined(__has_feature) | ||
| 121 | # define __has_feature(x) 0 | ||
| 122 | #endif | ||
| 123 | |||
| 124 | // Older GCCs do not understand __has_attribute. | ||
| 125 | #if !defined(__has_attribute) | ||
| 126 | # define __has_attribute(x) 0 | ||
| 127 | #endif | ||
| 128 | |||
| 129 | // For portability reasons we do not include stddef.h, stdint.h or any other | ||
| 130 | // system header, but we do need some basic types that are not defined | ||
| 131 | // in a portable way by the language itself. | ||
| 132 | namespace __sanitizer { | ||
| 133 | |||
| 134 | #if defined(_WIN64) | ||
| 135 | // 64-bit Windows uses LLP64 data model. | ||
| 136 | typedef unsigned long long uptr; | ||
| 137 | typedef signed long long sptr; | ||
| 138 | #else | ||
| 139 | typedef unsigned long uptr; | ||
| 140 | typedef signed long sptr; | ||
| 141 | #endif // defined(_WIN64) | ||
| 142 | #if defined(__x86_64__) | ||
| 143 | // Since x32 uses ILP32 data model in 64-bit hardware mode, we must use | ||
| 144 | // 64-bit pointer to unwind stack frame. | ||
| 145 | typedef unsigned long long uhwptr; | ||
| 146 | #else | ||
| 147 | typedef uptr uhwptr; | ||
| 148 | #endif | ||
| 149 | typedef unsigned char u8; | ||
| 150 | typedef unsigned short u16; | ||
| 151 | typedef unsigned int u32; | ||
| 152 | typedef unsigned long long u64; | ||
| 153 | typedef signed char s8; | ||
| 154 | typedef signed short s16; | ||
| 155 | typedef signed int s32; | ||
| 156 | typedef signed long long s64; | ||
| 157 | #if SANITIZER_WINDOWS | ||
| 158 | // On Windows, files are HANDLE, which is a synonim of void*. | ||
| 159 | // Use void* to avoid including <windows.h> everywhere. | ||
| 160 | typedef void* fd_t; | ||
| 161 | typedef unsigned error_t; | ||
| 162 | #else | ||
| 163 | typedef int fd_t; | ||
| 164 | typedef int error_t; | ||
| 165 | #endif | ||
| 166 | #if SANITIZER_SOLARIS && !defined(_LP64) | ||
| 167 | typedef long pid_t; | ||
| 168 | #else | ||
| 169 | typedef int pid_t; | ||
| 170 | #endif | ||
| 171 | |||
| 172 | #if SANITIZER_FREEBSD || SANITIZER_NETBSD || \ | ||
| 173 | SANITIZER_OPENBSD || SANITIZER_MAC || \ | ||
| 174 | (SANITIZER_SOLARIS && (defined(_LP64) || _FILE_OFFSET_BITS == 64)) || \ | ||
| 175 | (SANITIZER_LINUX && defined(__x86_64__)) | ||
| 176 | typedef u64 OFF_T; | ||
| 177 | #else | ||
| 178 | typedef uptr OFF_T; | ||
| 179 | #endif | ||
| 180 | typedef u64 OFF64_T; | ||
| 181 | |||
| 182 | #if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC | ||
| 183 | typedef uptr operator_new_size_type; | ||
| 184 | #else | ||
| 185 | # if SANITIZER_OPENBSD || defined(__s390__) && !defined(__s390x__) | ||
| 186 | // Special case: 31-bit s390 has unsigned long as size_t. | ||
| 187 | typedef unsigned long operator_new_size_type; | ||
| 188 | # else | ||
| 189 | typedef u32 operator_new_size_type; | ||
| 190 | # endif | ||
| 191 | #endif | ||
| 192 | |||
| 193 | typedef u64 tid_t; | ||
| 194 | |||
| 195 | // ----------- ATTENTION ------------- | ||
| 196 | // This header should NOT include any other headers to avoid portability issues. | ||
| 197 | |||
| 198 | // Common defs. | ||
| 199 | #ifndef INLINE | ||
| 200 | #define INLINE inline | ||
| 201 | #endif | ||
| 202 | #define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE | ||
| 203 | #define SANITIZER_WEAK_DEFAULT_IMPL \ | ||
| 204 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE | ||
| 205 | #define SANITIZER_WEAK_CXX_DEFAULT_IMPL \ | ||
| 206 | extern "C++" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE | ||
| 207 | |||
| 208 | // Platform-specific defs. | ||
| 209 | #if defined(_MSC_VER) | ||
| 210 | # define ALWAYS_INLINE __forceinline | ||
| 211 | // FIXME(timurrrr): do we need this on Windows? | ||
| 212 | # define ALIAS(x) | ||
| 213 | # define ALIGNED(x) __declspec(align(x)) | ||
| 214 | # define FORMAT(f, a) | ||
| 215 | # define NOINLINE __declspec(noinline) | ||
| 216 | # define NORETURN __declspec(noreturn) | ||
| 217 | # define THREADLOCAL __declspec(thread) | ||
| 218 | # define LIKELY(x) (x) | ||
| 219 | # define UNLIKELY(x) (x) | ||
| 220 | # define PREFETCH(x) /* _mm_prefetch(x, _MM_HINT_NTA) */ (void)0 | ||
| 221 | # define WARN_UNUSED_RESULT | ||
| 222 | #else // _MSC_VER | ||
| 223 | # define ALWAYS_INLINE inline __attribute__((always_inline)) | ||
| 224 | # define ALIAS(x) __attribute__((alias(x))) | ||
| 225 | // Please only use the ALIGNED macro before the type. | ||
| 226 | // Using ALIGNED after the variable declaration is not portable! | ||
| 227 | # define ALIGNED(x) __attribute__((aligned(x))) | ||
| 228 | # define FORMAT(f, a) __attribute__((format(printf, f, a))) | ||
| 229 | # define NOINLINE __attribute__((noinline)) | ||
| 230 | # define NORETURN __attribute__((noreturn)) | ||
| 231 | # define THREADLOCAL __thread | ||
| 232 | # define LIKELY(x) __builtin_expect(!!(x), 1) | ||
| 233 | # define UNLIKELY(x) __builtin_expect(!!(x), 0) | ||
| 234 | # if defined(__i386__) || defined(__x86_64__) | ||
| 235 | // __builtin_prefetch(x) generates prefetchnt0 on x86 | ||
| 236 | # define PREFETCH(x) __asm__("prefetchnta (%0)" : : "r" (x)) | ||
| 237 | # else | ||
| 238 | # define PREFETCH(x) __builtin_prefetch(x) | ||
| 239 | # endif | ||
| 240 | # define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) | ||
| 241 | #endif // _MSC_VER | ||
| 242 | |||
| 243 | #if !defined(_MSC_VER) || defined(__clang__) | ||
| 244 | # define UNUSED __attribute__((unused)) | ||
| 245 | # define USED __attribute__((used)) | ||
| 246 | #else | ||
| 247 | # define UNUSED | ||
| 248 | # define USED | ||
| 249 | #endif | ||
| 250 | |||
| 251 | #if !defined(_MSC_VER) || defined(__clang__) || MSC_PREREQ(1900) | ||
| 252 | # define NOEXCEPT noexcept | ||
| 253 | #else | ||
| 254 | # define NOEXCEPT throw() | ||
| 255 | #endif | ||
| 256 | |||
| 257 | // Unaligned versions of basic types. | ||
| 258 | typedef ALIGNED(1) u16 uu16; | ||
| 259 | typedef ALIGNED(1) u32 uu32; | ||
| 260 | typedef ALIGNED(1) u64 uu64; | ||
| 261 | typedef ALIGNED(1) s16 us16; | ||
| 262 | typedef ALIGNED(1) s32 us32; | ||
| 263 | typedef ALIGNED(1) s64 us64; | ||
| 264 | |||
| 265 | #if SANITIZER_WINDOWS | ||
| 266 | } // namespace __sanitizer | ||
| 267 | typedef unsigned long DWORD; | ||
| 268 | namespace __sanitizer { | ||
| 269 | typedef DWORD thread_return_t; | ||
| 270 | # define THREAD_CALLING_CONV __stdcall | ||
| 271 | #else // _WIN32 | ||
| 272 | typedef void* thread_return_t; | ||
| 273 | # define THREAD_CALLING_CONV | ||
| 274 | #endif // _WIN32 | ||
| 275 | typedef thread_return_t (THREAD_CALLING_CONV *thread_callback_t)(void* arg); | ||
| 276 | |||
| 277 | // NOTE: Functions below must be defined in each run-time. | ||
| 278 | void NORETURN Die(); | ||
| 279 | |||
| 280 | void NORETURN CheckFailed(const char *file, int line, const char *cond, | ||
| 281 | u64 v1, u64 v2); | ||
| 282 | |||
| 283 | // Check macro | ||
| 284 | #define RAW_CHECK_MSG(expr, msg) do { \ | ||
| 285 | if (UNLIKELY(!(expr))) { \ | ||
| 286 | RawWrite(msg); \ | ||
| 287 | Die(); \ | ||
| 288 | } \ | ||
| 289 | } while (0) | ||
| 290 | |||
| 291 | #define RAW_CHECK(expr) RAW_CHECK_MSG(expr, #expr) | ||
| 292 | |||
| 293 | #define CHECK_IMPL(c1, op, c2) \ | ||
| 294 | do { \ | ||
| 295 | __sanitizer::u64 v1 = (__sanitizer::u64)(c1); \ | ||
| 296 | __sanitizer::u64 v2 = (__sanitizer::u64)(c2); \ | ||
| 297 | if (UNLIKELY(!(v1 op v2))) \ | ||
| 298 | __sanitizer::CheckFailed(__FILE__, __LINE__, \ | ||
| 299 | "(" #c1 ") " #op " (" #c2 ")", v1, v2); \ | ||
| 300 | } while (false) \ | ||
| 301 | /**/ | ||
| 302 | |||
| 303 | #define CHECK(a) CHECK_IMPL((a), !=, 0) | ||
| 304 | #define CHECK_EQ(a, b) CHECK_IMPL((a), ==, (b)) | ||
| 305 | #define CHECK_NE(a, b) CHECK_IMPL((a), !=, (b)) | ||
| 306 | #define CHECK_LT(a, b) CHECK_IMPL((a), <, (b)) | ||
| 307 | #define CHECK_LE(a, b) CHECK_IMPL((a), <=, (b)) | ||
| 308 | #define CHECK_GT(a, b) CHECK_IMPL((a), >, (b)) | ||
| 309 | #define CHECK_GE(a, b) CHECK_IMPL((a), >=, (b)) | ||
| 310 | |||
| 311 | #if SANITIZER_DEBUG | ||
| 312 | #define DCHECK(a) CHECK(a) | ||
| 313 | #define DCHECK_EQ(a, b) CHECK_EQ(a, b) | ||
| 314 | #define DCHECK_NE(a, b) CHECK_NE(a, b) | ||
| 315 | #define DCHECK_LT(a, b) CHECK_LT(a, b) | ||
| 316 | #define DCHECK_LE(a, b) CHECK_LE(a, b) | ||
| 317 | #define DCHECK_GT(a, b) CHECK_GT(a, b) | ||
| 318 | #define DCHECK_GE(a, b) CHECK_GE(a, b) | ||
| 319 | #else | ||
| 320 | #define DCHECK(a) | ||
| 321 | #define DCHECK_EQ(a, b) | ||
| 322 | #define DCHECK_NE(a, b) | ||
| 323 | #define DCHECK_LT(a, b) | ||
| 324 | #define DCHECK_LE(a, b) | ||
| 325 | #define DCHECK_GT(a, b) | ||
| 326 | #define DCHECK_GE(a, b) | ||
| 327 | #endif | ||
| 328 | |||
| 329 | #define UNREACHABLE(msg) do { \ | ||
| 330 | CHECK(0 && msg); \ | ||
| 331 | Die(); \ | ||
| 332 | } while (0) | ||
| 333 | |||
| 334 | #define UNIMPLEMENTED() UNREACHABLE("unimplemented") | ||
| 335 | |||
| 336 | #define COMPILER_CHECK(pred) IMPL_COMPILER_ASSERT(pred, __LINE__) | ||
| 337 | |||
| 338 | #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) | ||
| 339 | |||
| 340 | #define IMPL_PASTE(a, b) a##b | ||
| 341 | #define IMPL_COMPILER_ASSERT(pred, line) \ | ||
| 342 | typedef char IMPL_PASTE(assertion_failed_##_, line)[2*(int)(pred)-1] | ||
| 343 | |||
| 344 | // Limits for integral types. We have to redefine it in case we don't | ||
| 345 | // have stdint.h (like in Visual Studio 9). | ||
| 346 | #undef __INT64_C | ||
| 347 | #undef __UINT64_C | ||
| 348 | #if SANITIZER_WORDSIZE == 64 | ||
| 349 | # define __INT64_C(c) c ## L | ||
| 350 | # define __UINT64_C(c) c ## UL | ||
| 351 | #else | ||
| 352 | # define __INT64_C(c) c ## LL | ||
| 353 | # define __UINT64_C(c) c ## ULL | ||
| 354 | #endif // SANITIZER_WORDSIZE == 64 | ||
| 355 | #undef INT32_MIN | ||
| 356 | #define INT32_MIN (-2147483647-1) | ||
| 357 | #undef INT32_MAX | ||
| 358 | #define INT32_MAX (2147483647) | ||
| 359 | #undef UINT32_MAX | ||
| 360 | #define UINT32_MAX (4294967295U) | ||
| 361 | #undef INT64_MIN | ||
| 362 | #define INT64_MIN (-__INT64_C(9223372036854775807)-1) | ||
| 363 | #undef INT64_MAX | ||
| 364 | #define INT64_MAX (__INT64_C(9223372036854775807)) | ||
| 365 | #undef UINT64_MAX | ||
| 366 | #define UINT64_MAX (__UINT64_C(18446744073709551615)) | ||
| 367 | #undef UINTPTR_MAX | ||
| 368 | #if SANITIZER_WORDSIZE == 64 | ||
| 369 | # define UINTPTR_MAX (18446744073709551615UL) | ||
| 370 | #else | ||
| 371 | # define UINTPTR_MAX (4294967295U) | ||
| 372 | #endif // SANITIZER_WORDSIZE == 64 | ||
| 373 | |||
| 374 | enum LinkerInitialized { LINKER_INITIALIZED = 0 }; | ||
| 375 | |||
| 376 | #if !defined(_MSC_VER) || defined(__clang__) | ||
| 377 | #if SANITIZER_S390_31 | ||
| 378 | #define GET_CALLER_PC() \ | ||
| 379 | (__sanitizer::uptr) __builtin_extract_return_addr(__builtin_return_address(0)) | ||
| 380 | #else | ||
| 381 | #define GET_CALLER_PC() (__sanitizer::uptr) __builtin_return_address(0) | ||
| 382 | #endif | ||
| 383 | #define GET_CURRENT_FRAME() (__sanitizer::uptr) __builtin_frame_address(0) | ||
| 384 | inline void Trap() { | ||
| 385 | __builtin_trap(); | ||
| 386 | } | ||
| 387 | #else | ||
| 388 | extern "C" void* _ReturnAddress(void); | ||
| 389 | extern "C" void* _AddressOfReturnAddress(void); | ||
| 390 | # pragma intrinsic(_ReturnAddress) | ||
| 391 | # pragma intrinsic(_AddressOfReturnAddress) | ||
| 392 | #define GET_CALLER_PC() (__sanitizer::uptr) _ReturnAddress() | ||
| 393 | // CaptureStackBackTrace doesn't need to know BP on Windows. | ||
| 394 | #define GET_CURRENT_FRAME() \ | ||
| 395 | (((__sanitizer::uptr)_AddressOfReturnAddress()) + sizeof(__sanitizer::uptr)) | ||
| 396 | |||
| 397 | extern "C" void __ud2(void); | ||
| 398 | # pragma intrinsic(__ud2) | ||
| 399 | inline void Trap() { | ||
| 400 | __ud2(); | ||
| 401 | } | ||
| 402 | #endif | ||
| 403 | |||
| 404 | #define HANDLE_EINTR(res, f) \ | ||
| 405 | { \ | ||
| 406 | int rverrno; \ | ||
| 407 | do { \ | ||
| 408 | res = (f); \ | ||
| 409 | } while (internal_iserror(res, &rverrno) && rverrno == EINTR); \ | ||
| 410 | } | ||
| 411 | |||
| 412 | // Forces the compiler to generate a frame pointer in the function. | ||
| 413 | #define ENABLE_FRAME_POINTER \ | ||
| 414 | do { \ | ||
| 415 | volatile __sanitizer::uptr enable_fp; \ | ||
| 416 | enable_fp = GET_CURRENT_FRAME(); \ | ||
| 417 | (void)enable_fp; \ | ||
| 418 | } while (0) | ||
| 419 | |||
| 420 | } // namespace __sanitizer | ||
| 421 | |||
| 422 | namespace __asan { | ||
| 423 | using namespace __sanitizer; | ||
| 424 | } | ||
| 425 | namespace __dsan { | ||
| 426 | using namespace __sanitizer; | ||
| 427 | } | ||
| 428 | namespace __dfsan { | ||
| 429 | using namespace __sanitizer; | ||
| 430 | } | ||
| 431 | namespace __lsan { | ||
| 432 | using namespace __sanitizer; | ||
| 433 | } | ||
| 434 | namespace __msan { | ||
| 435 | using namespace __sanitizer; | ||
| 436 | } | ||
| 437 | namespace __hwasan { | ||
| 438 | using namespace __sanitizer; | ||
| 439 | } | ||
| 440 | namespace __tsan { | ||
| 441 | using namespace __sanitizer; | ||
| 442 | } | ||
| 443 | namespace __scudo { | ||
| 444 | using namespace __sanitizer; | ||
| 445 | } | ||
| 446 | namespace __ubsan { | ||
| 447 | using namespace __sanitizer; | ||
| 448 | } | ||
| 449 | namespace __xray { | ||
| 450 | using namespace __sanitizer; | ||
| 451 | } | ||
| 452 | namespace __interception { | ||
| 453 | using namespace __sanitizer; | ||
| 454 | } | ||
| 455 | namespace __hwasan { | ||
| 456 | using namespace __sanitizer; | ||
| 457 | } | ||
| 458 | |||
| 459 | #endif // SANITIZER_DEFS_H | ||
lib/tsan/sanitizer_common/sanitizer_lfstack.h created+72| ... | @@ -0,0 +1,72 @@ | ||
| 1 | //===-- sanitizer_lfstack.h -=-----------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Lock-free stack. | ||
| 10 | // Uses 32/17 bits as ABA-counter on 32/64-bit platforms. | ||
| 11 | // The memory passed to Push() must not be ever munmap'ed. | ||
| 12 | // The type T must contain T *next field. | ||
| 13 | // | ||
| 14 | //===----------------------------------------------------------------------===// | ||
| 15 | |||
| 16 | #ifndef SANITIZER_LFSTACK_H | ||
| 17 | #define SANITIZER_LFSTACK_H | ||
| 18 | |||
| 19 | #include "sanitizer_internal_defs.h" | ||
| 20 | #include "sanitizer_common.h" | ||
| 21 | #include "sanitizer_atomic.h" | ||
| 22 | |||
| 23 | namespace __sanitizer { | ||
| 24 | |||
| 25 | template<typename T> | ||
| 26 | struct LFStack { | ||
| 27 | void Clear() { | ||
| 28 | atomic_store(&head_, 0, memory_order_relaxed); | ||
| 29 | } | ||
| 30 | |||
| 31 | bool Empty() const { | ||
| 32 | return (atomic_load(&head_, memory_order_relaxed) & kPtrMask) == 0; | ||
| 33 | } | ||
| 34 | |||
| 35 | void Push(T *p) { | ||
| 36 | u64 cmp = atomic_load(&head_, memory_order_relaxed); | ||
| 37 | for (;;) { | ||
| 38 | u64 cnt = (cmp & kCounterMask) + kCounterInc; | ||
| 39 | u64 xch = (u64)(uptr)p | cnt; | ||
| 40 | p->next = (T*)(uptr)(cmp & kPtrMask); | ||
| 41 | if (atomic_compare_exchange_weak(&head_, &cmp, xch, | ||
| 42 | memory_order_release)) | ||
| 43 | break; | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | T *Pop() { | ||
| 48 | u64 cmp = atomic_load(&head_, memory_order_acquire); | ||
| 49 | for (;;) { | ||
| 50 | T *cur = (T*)(uptr)(cmp & kPtrMask); | ||
| 51 | if (!cur) | ||
| 52 | return nullptr; | ||
| 53 | T *nxt = cur->next; | ||
| 54 | u64 cnt = (cmp & kCounterMask); | ||
| 55 | u64 xch = (u64)(uptr)nxt | cnt; | ||
| 56 | if (atomic_compare_exchange_weak(&head_, &cmp, xch, | ||
| 57 | memory_order_acquire)) | ||
| 58 | return cur; | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | // private: | ||
| 63 | static const int kCounterBits = FIRST_32_SECOND_64(32, 17); | ||
| 64 | static const u64 kPtrMask = ((u64)-1) >> kCounterBits; | ||
| 65 | static const u64 kCounterMask = ~kPtrMask; | ||
| 66 | static const u64 kCounterInc = kPtrMask + 1; | ||
| 67 | |||
| 68 | atomic_uint64_t head_; | ||
| 69 | }; | ||
| 70 | } // namespace __sanitizer | ||
| 71 | |||
| 72 | #endif // SANITIZER_LFSTACK_H | ||
lib/tsan/sanitizer_common/sanitizer_libc.cpp created+280| ... | @@ -0,0 +1,280 @@ | ||
| 1 | //===-- sanitizer_libc.cpp ------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer | ||
| 10 | // run-time libraries. See sanitizer_libc.h for details. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_allocator_internal.h" | ||
| 14 | #include "sanitizer_common.h" | ||
| 15 | #include "sanitizer_libc.h" | ||
| 16 | |||
| 17 | namespace __sanitizer { | ||
| 18 | |||
| 19 | s64 internal_atoll(const char *nptr) { | ||
| 20 | return internal_simple_strtoll(nptr, nullptr, 10); | ||
| 21 | } | ||
| 22 | |||
| 23 | void *internal_memchr(const void *s, int c, uptr n) { | ||
| 24 | const char *t = (const char *)s; | ||
| 25 | for (uptr i = 0; i < n; ++i, ++t) | ||
| 26 | if (*t == c) | ||
| 27 | return reinterpret_cast<void *>(const_cast<char *>(t)); | ||
| 28 | return nullptr; | ||
| 29 | } | ||
| 30 | |||
| 31 | void *internal_memrchr(const void *s, int c, uptr n) { | ||
| 32 | const char *t = (const char *)s; | ||
| 33 | void *res = nullptr; | ||
| 34 | for (uptr i = 0; i < n; ++i, ++t) { | ||
| 35 | if (*t == c) res = reinterpret_cast<void *>(const_cast<char *>(t)); | ||
| 36 | } | ||
| 37 | return res; | ||
| 38 | } | ||
| 39 | |||
| 40 | int internal_memcmp(const void* s1, const void* s2, uptr n) { | ||
| 41 | const char *t1 = (const char *)s1; | ||
| 42 | const char *t2 = (const char *)s2; | ||
| 43 | for (uptr i = 0; i < n; ++i, ++t1, ++t2) | ||
| 44 | if (*t1 != *t2) | ||
| 45 | return *t1 < *t2 ? -1 : 1; | ||
| 46 | return 0; | ||
| 47 | } | ||
| 48 | |||
| 49 | void *internal_memcpy(void *dest, const void *src, uptr n) { | ||
| 50 | char *d = (char*)dest; | ||
| 51 | const char *s = (const char *)src; | ||
| 52 | for (uptr i = 0; i < n; ++i) | ||
| 53 | d[i] = s[i]; | ||
| 54 | return dest; | ||
| 55 | } | ||
| 56 | |||
| 57 | void *internal_memmove(void *dest, const void *src, uptr n) { | ||
| 58 | char *d = (char*)dest; | ||
| 59 | const char *s = (const char *)src; | ||
| 60 | sptr i, signed_n = (sptr)n; | ||
| 61 | CHECK_GE(signed_n, 0); | ||
| 62 | if (d < s) { | ||
| 63 | for (i = 0; i < signed_n; ++i) | ||
| 64 | d[i] = s[i]; | ||
| 65 | } else { | ||
| 66 | if (d > s && signed_n > 0) { | ||
| 67 | for (i = signed_n - 1; i >= 0; --i) { | ||
| 68 | d[i] = s[i]; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | } | ||
| 72 | return dest; | ||
| 73 | } | ||
| 74 | |||
| 75 | void *internal_memset(void* s, int c, uptr n) { | ||
| 76 | // Optimize for the most performance-critical case: | ||
| 77 | if ((reinterpret_cast<uptr>(s) % 16) == 0 && (n % 16) == 0) { | ||
| 78 | u64 *p = reinterpret_cast<u64*>(s); | ||
| 79 | u64 *e = p + n / 8; | ||
| 80 | u64 v = c; | ||
| 81 | v |= v << 8; | ||
| 82 | v |= v << 16; | ||
| 83 | v |= v << 32; | ||
| 84 | for (; p < e; p += 2) | ||
| 85 | p[0] = p[1] = v; | ||
| 86 | return s; | ||
| 87 | } | ||
| 88 | // The next line prevents Clang from making a call to memset() instead of the | ||
| 89 | // loop below. | ||
| 90 | // FIXME: building the runtime with -ffreestanding is a better idea. However | ||
| 91 | // there currently are linktime problems due to PR12396. | ||
| 92 | char volatile *t = (char*)s; | ||
| 93 | for (uptr i = 0; i < n; ++i, ++t) { | ||
| 94 | *t = c; | ||
| 95 | } | ||
| 96 | return s; | ||
| 97 | } | ||
| 98 | |||
| 99 | uptr internal_strcspn(const char *s, const char *reject) { | ||
| 100 | uptr i; | ||
| 101 | for (i = 0; s[i]; i++) { | ||
| 102 | if (internal_strchr(reject, s[i])) | ||
| 103 | return i; | ||
| 104 | } | ||
| 105 | return i; | ||
| 106 | } | ||
| 107 | |||
| 108 | char* internal_strdup(const char *s) { | ||
| 109 | uptr len = internal_strlen(s); | ||
| 110 | char *s2 = (char*)InternalAlloc(len + 1); | ||
| 111 | internal_memcpy(s2, s, len); | ||
| 112 | s2[len] = 0; | ||
| 113 | return s2; | ||
| 114 | } | ||
| 115 | |||
| 116 | int internal_strcmp(const char *s1, const char *s2) { | ||
| 117 | while (true) { | ||
| 118 | unsigned c1 = *s1; | ||
| 119 | unsigned c2 = *s2; | ||
| 120 | if (c1 != c2) return (c1 < c2) ? -1 : 1; | ||
| 121 | if (c1 == 0) break; | ||
| 122 | s1++; | ||
| 123 | s2++; | ||
| 124 | } | ||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | |||
| 128 | int internal_strncmp(const char *s1, const char *s2, uptr n) { | ||
| 129 | for (uptr i = 0; i < n; i++) { | ||
| 130 | unsigned c1 = *s1; | ||
| 131 | unsigned c2 = *s2; | ||
| 132 | if (c1 != c2) return (c1 < c2) ? -1 : 1; | ||
| 133 | if (c1 == 0) break; | ||
| 134 | s1++; | ||
| 135 | s2++; | ||
| 136 | } | ||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | char* internal_strchr(const char *s, int c) { | ||
| 141 | while (true) { | ||
| 142 | if (*s == (char)c) | ||
| 143 | return const_cast<char *>(s); | ||
| 144 | if (*s == 0) | ||
| 145 | return nullptr; | ||
| 146 | s++; | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | char *internal_strchrnul(const char *s, int c) { | ||
| 151 | char *res = internal_strchr(s, c); | ||
| 152 | if (!res) | ||
| 153 | res = const_cast<char *>(s) + internal_strlen(s); | ||
| 154 | return res; | ||
| 155 | } | ||
| 156 | |||
| 157 | char *internal_strrchr(const char *s, int c) { | ||
| 158 | const char *res = nullptr; | ||
| 159 | for (uptr i = 0; s[i]; i++) { | ||
| 160 | if (s[i] == c) res = s + i; | ||
| 161 | } | ||
| 162 | return const_cast<char *>(res); | ||
| 163 | } | ||
| 164 | |||
| 165 | uptr internal_strlen(const char *s) { | ||
| 166 | uptr i = 0; | ||
| 167 | while (s[i]) i++; | ||
| 168 | return i; | ||
| 169 | } | ||
| 170 | |||
| 171 | uptr internal_strlcat(char *dst, const char *src, uptr maxlen) { | ||
| 172 | const uptr srclen = internal_strlen(src); | ||
| 173 | const uptr dstlen = internal_strnlen(dst, maxlen); | ||
| 174 | if (dstlen == maxlen) return maxlen + srclen; | ||
| 175 | if (srclen < maxlen - dstlen) { | ||
| 176 | internal_memmove(dst + dstlen, src, srclen + 1); | ||
| 177 | } else { | ||
| 178 | internal_memmove(dst + dstlen, src, maxlen - dstlen - 1); | ||
| 179 | dst[maxlen - 1] = '\0'; | ||
| 180 | } | ||
| 181 | return dstlen + srclen; | ||
| 182 | } | ||
| 183 | |||
| 184 | char *internal_strncat(char *dst, const char *src, uptr n) { | ||
| 185 | uptr len = internal_strlen(dst); | ||
| 186 | uptr i; | ||
| 187 | for (i = 0; i < n && src[i]; i++) | ||
| 188 | dst[len + i] = src[i]; | ||
| 189 | dst[len + i] = 0; | ||
| 190 | return dst; | ||
| 191 | } | ||
| 192 | |||
| 193 | uptr internal_strlcpy(char *dst, const char *src, uptr maxlen) { | ||
| 194 | const uptr srclen = internal_strlen(src); | ||
| 195 | if (srclen < maxlen) { | ||
| 196 | internal_memmove(dst, src, srclen + 1); | ||
| 197 | } else if (maxlen != 0) { | ||
| 198 | internal_memmove(dst, src, maxlen - 1); | ||
| 199 | dst[maxlen - 1] = '\0'; | ||
| 200 | } | ||
| 201 | return srclen; | ||
| 202 | } | ||
| 203 | |||
| 204 | char *internal_strncpy(char *dst, const char *src, uptr n) { | ||
| 205 | uptr i; | ||
| 206 | for (i = 0; i < n && src[i]; i++) | ||
| 207 | dst[i] = src[i]; | ||
| 208 | internal_memset(dst + i, '\0', n - i); | ||
| 209 | return dst; | ||
| 210 | } | ||
| 211 | |||
| 212 | uptr internal_strnlen(const char *s, uptr maxlen) { | ||
| 213 | uptr i = 0; | ||
| 214 | while (i < maxlen && s[i]) i++; | ||
| 215 | return i; | ||
| 216 | } | ||
| 217 | |||
| 218 | char *internal_strstr(const char *haystack, const char *needle) { | ||
| 219 | // This is O(N^2), but we are not using it in hot places. | ||
| 220 | uptr len1 = internal_strlen(haystack); | ||
| 221 | uptr len2 = internal_strlen(needle); | ||
| 222 | if (len1 < len2) return nullptr; | ||
| 223 | for (uptr pos = 0; pos <= len1 - len2; pos++) { | ||
| 224 | if (internal_memcmp(haystack + pos, needle, len2) == 0) | ||
| 225 | return const_cast<char *>(haystack) + pos; | ||
| 226 | } | ||
| 227 | return nullptr; | ||
| 228 | } | ||
| 229 | |||
| 230 | s64 internal_simple_strtoll(const char *nptr, const char **endptr, int base) { | ||
| 231 | CHECK_EQ(base, 10); | ||
| 232 | while (IsSpace(*nptr)) nptr++; | ||
| 233 | int sgn = 1; | ||
| 234 | u64 res = 0; | ||
| 235 | bool have_digits = false; | ||
| 236 | char *old_nptr = const_cast<char *>(nptr); | ||
| 237 | if (*nptr == '+') { | ||
| 238 | sgn = 1; | ||
| 239 | nptr++; | ||
| 240 | } else if (*nptr == '-') { | ||
| 241 | sgn = -1; | ||
| 242 | nptr++; | ||
| 243 | } | ||
| 244 | while (IsDigit(*nptr)) { | ||
| 245 | res = (res <= UINT64_MAX / 10) ? res * 10 : UINT64_MAX; | ||
| 246 | int digit = ((*nptr) - '0'); | ||
| 247 | res = (res <= UINT64_MAX - digit) ? res + digit : UINT64_MAX; | ||
| 248 | have_digits = true; | ||
| 249 | nptr++; | ||
| 250 | } | ||
| 251 | if (endptr) { | ||
| 252 | *endptr = (have_digits) ? const_cast<char *>(nptr) : old_nptr; | ||
| 253 | } | ||
| 254 | if (sgn > 0) { | ||
| 255 | return (s64)(Min((u64)INT64_MAX, res)); | ||
| 256 | } else { | ||
| 257 | return (res > INT64_MAX) ? INT64_MIN : ((s64)res * -1); | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | bool mem_is_zero(const char *beg, uptr size) { | ||
| 262 | CHECK_LE(size, 1ULL << FIRST_32_SECOND_64(30, 40)); // Sanity check. | ||
| 263 | const char *end = beg + size; | ||
| 264 | uptr *aligned_beg = (uptr *)RoundUpTo((uptr)beg, sizeof(uptr)); | ||
| 265 | uptr *aligned_end = (uptr *)RoundDownTo((uptr)end, sizeof(uptr)); | ||
| 266 | uptr all = 0; | ||
| 267 | // Prologue. | ||
| 268 | for (const char *mem = beg; mem < (char*)aligned_beg && mem < end; mem++) | ||
| 269 | all |= *mem; | ||
| 270 | // Aligned loop. | ||
| 271 | for (; aligned_beg < aligned_end; aligned_beg++) | ||
| 272 | all |= *aligned_beg; | ||
| 273 | // Epilogue. | ||
| 274 | if ((char *)aligned_end >= beg) { | ||
| 275 | for (const char *mem = (char *)aligned_end; mem < end; mem++) all |= *mem; | ||
| 276 | } | ||
| 277 | return all == 0; | ||
| 278 | } | ||
| 279 | |||
| 280 | } // namespace __sanitizer | ||
lib/tsan/sanitizer_common/sanitizer_libc.h created+85| ... | @@ -0,0 +1,85 @@ | ||
| 1 | //===-- sanitizer_libc.h ----------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer | ||
| 10 | // run-time libraries. | ||
| 11 | // These tools can not use some of the libc functions directly because those | ||
| 12 | // functions are intercepted. Instead, we implement a tiny subset of libc here. | ||
| 13 | // FIXME: Some of functions declared in this file are in fact POSIX, not libc. | ||
| 14 | //===----------------------------------------------------------------------===// | ||
| 15 | |||
| 16 | #ifndef SANITIZER_LIBC_H | ||
| 17 | #define SANITIZER_LIBC_H | ||
| 18 | |||
| 19 | // ----------- ATTENTION ------------- | ||
| 20 | // This header should NOT include any other headers from sanitizer runtime. | ||
| 21 | #include "sanitizer_internal_defs.h" | ||
| 22 | |||
| 23 | namespace __sanitizer { | ||
| 24 | |||
| 25 | // internal_X() is a custom implementation of X() for use in RTL. | ||
| 26 | |||
| 27 | // String functions | ||
| 28 | s64 internal_atoll(const char *nptr); | ||
| 29 | void *internal_memchr(const void *s, int c, uptr n); | ||
| 30 | void *internal_memrchr(const void *s, int c, uptr n); | ||
| 31 | int internal_memcmp(const void* s1, const void* s2, uptr n); | ||
| 32 | void *internal_memcpy(void *dest, const void *src, uptr n); | ||
| 33 | void *internal_memmove(void *dest, const void *src, uptr n); | ||
| 34 | // Should not be used in performance-critical places. | ||
| 35 | void *internal_memset(void *s, int c, uptr n); | ||
| 36 | char* internal_strchr(const char *s, int c); | ||
| 37 | char *internal_strchrnul(const char *s, int c); | ||
| 38 | int internal_strcmp(const char *s1, const char *s2); | ||
| 39 | uptr internal_strcspn(const char *s, const char *reject); | ||
| 40 | char *internal_strdup(const char *s); | ||
| 41 | uptr internal_strlen(const char *s); | ||
| 42 | uptr internal_strlcat(char *dst, const char *src, uptr maxlen); | ||
| 43 | char *internal_strncat(char *dst, const char *src, uptr n); | ||
| 44 | int internal_strncmp(const char *s1, const char *s2, uptr n); | ||
| 45 | uptr internal_strlcpy(char *dst, const char *src, uptr maxlen); | ||
| 46 | char *internal_strncpy(char *dst, const char *src, uptr n); | ||
| 47 | uptr internal_strnlen(const char *s, uptr maxlen); | ||
| 48 | char *internal_strrchr(const char *s, int c); | ||
| 49 | char *internal_strstr(const char *haystack, const char *needle); | ||
| 50 | // Works only for base=10 and doesn't set errno. | ||
| 51 | s64 internal_simple_strtoll(const char *nptr, const char **endptr, int base); | ||
| 52 | int internal_snprintf(char *buffer, uptr length, const char *format, ...); | ||
| 53 | |||
| 54 | // Return true if all bytes in [mem, mem+size) are zero. | ||
| 55 | // Optimized for the case when the result is true. | ||
| 56 | bool mem_is_zero(const char *mem, uptr size); | ||
| 57 | |||
| 58 | // I/O | ||
| 59 | // Define these as macros so we can use them in linker initialized global | ||
| 60 | // structs without dynamic initialization. | ||
| 61 | #define kInvalidFd ((fd_t)-1) | ||
| 62 | #define kStdinFd ((fd_t)0) | ||
| 63 | #define kStdoutFd ((fd_t)1) | ||
| 64 | #define kStderrFd ((fd_t)2) | ||
| 65 | |||
| 66 | uptr internal_ftruncate(fd_t fd, uptr size); | ||
| 67 | |||
| 68 | // OS | ||
| 69 | void NORETURN internal__exit(int exitcode); | ||
| 70 | unsigned int internal_sleep(unsigned int seconds); | ||
| 71 | |||
| 72 | uptr internal_getpid(); | ||
| 73 | uptr internal_getppid(); | ||
| 74 | |||
| 75 | int internal_dlinfo(void *handle, int request, void *p); | ||
| 76 | |||
| 77 | // Threading | ||
| 78 | uptr internal_sched_yield(); | ||
| 79 | |||
| 80 | // Error handling | ||
| 81 | bool internal_iserror(uptr retval, int *rverrno = nullptr); | ||
| 82 | |||
| 83 | } // namespace __sanitizer | ||
| 84 | |||
| 85 | #endif // SANITIZER_LIBC_H | ||
lib/tsan/sanitizer_common/sanitizer_libignore.cpp created+129| ... | @@ -0,0 +1,129 @@ | ||
| 1 | //===-- sanitizer_libignore.cpp -------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | |||
| 9 | #include "sanitizer_platform.h" | ||
| 10 | |||
| 11 | #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \ | ||
| 12 | SANITIZER_NETBSD || SANITIZER_OPENBSD | ||
| 13 | |||
| 14 | #include "sanitizer_libignore.h" | ||
| 15 | #include "sanitizer_flags.h" | ||
| 16 | #include "sanitizer_posix.h" | ||
| 17 | #include "sanitizer_procmaps.h" | ||
| 18 | |||
| 19 | namespace __sanitizer { | ||
| 20 | |||
| 21 | LibIgnore::LibIgnore(LinkerInitialized) { | ||
| 22 | } | ||
| 23 | |||
| 24 | void LibIgnore::AddIgnoredLibrary(const char *name_templ) { | ||
| 25 | BlockingMutexLock lock(&mutex_); | ||
| 26 | if (count_ >= kMaxLibs) { | ||
| 27 | Report("%s: too many ignored libraries (max: %d)\n", SanitizerToolName, | ||
| 28 | kMaxLibs); | ||
| 29 | Die(); | ||
| 30 | } | ||
| 31 | Lib *lib = &libs_[count_++]; | ||
| 32 | lib->templ = internal_strdup(name_templ); | ||
| 33 | lib->name = nullptr; | ||
| 34 | lib->real_name = nullptr; | ||
| 35 | lib->loaded = false; | ||
| 36 | } | ||
| 37 | |||
| 38 | void LibIgnore::OnLibraryLoaded(const char *name) { | ||
| 39 | BlockingMutexLock lock(&mutex_); | ||
| 40 | // Try to match suppressions with symlink target. | ||
| 41 | InternalScopedString buf(kMaxPathLength); | ||
| 42 | if (name && internal_readlink(name, buf.data(), buf.size() - 1) > 0 && | ||
| 43 | buf[0]) { | ||
| 44 | for (uptr i = 0; i < count_; i++) { | ||
| 45 | Lib *lib = &libs_[i]; | ||
| 46 | if (!lib->loaded && (!lib->real_name) && | ||
| 47 | TemplateMatch(lib->templ, name)) | ||
| 48 | lib->real_name = internal_strdup(buf.data()); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | // Scan suppressions list and find newly loaded and unloaded libraries. | ||
| 53 | ListOfModules modules; | ||
| 54 | modules.init(); | ||
| 55 | for (uptr i = 0; i < count_; i++) { | ||
| 56 | Lib *lib = &libs_[i]; | ||
| 57 | bool loaded = false; | ||
| 58 | for (const auto &mod : modules) { | ||
| 59 | for (const auto &range : mod.ranges()) { | ||
| 60 | if (!range.executable) | ||
| 61 | continue; | ||
| 62 | if (!TemplateMatch(lib->templ, mod.full_name()) && | ||
| 63 | !(lib->real_name && | ||
| 64 | internal_strcmp(lib->real_name, mod.full_name()) == 0)) | ||
| 65 | continue; | ||
| 66 | if (loaded) { | ||
| 67 | Report("%s: called_from_lib suppression '%s' is matched against" | ||
| 68 | " 2 libraries: '%s' and '%s'\n", | ||
| 69 | SanitizerToolName, lib->templ, lib->name, mod.full_name()); | ||
| 70 | Die(); | ||
| 71 | } | ||
| 72 | loaded = true; | ||
| 73 | if (lib->loaded) | ||
| 74 | continue; | ||
| 75 | VReport(1, | ||
| 76 | "Matched called_from_lib suppression '%s' against library" | ||
| 77 | " '%s'\n", | ||
| 78 | lib->templ, mod.full_name()); | ||
| 79 | lib->loaded = true; | ||
| 80 | lib->name = internal_strdup(mod.full_name()); | ||
| 81 | const uptr idx = | ||
| 82 | atomic_load(&ignored_ranges_count_, memory_order_relaxed); | ||
| 83 | CHECK_LT(idx, ARRAY_SIZE(ignored_code_ranges_)); | ||
| 84 | ignored_code_ranges_[idx].begin = range.beg; | ||
| 85 | ignored_code_ranges_[idx].end = range.end; | ||
| 86 | atomic_store(&ignored_ranges_count_, idx + 1, memory_order_release); | ||
| 87 | break; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | if (lib->loaded && !loaded) { | ||
| 91 | Report("%s: library '%s' that was matched against called_from_lib" | ||
| 92 | " suppression '%s' is unloaded\n", | ||
| 93 | SanitizerToolName, lib->name, lib->templ); | ||
| 94 | Die(); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | // Track instrumented ranges. | ||
| 99 | if (track_instrumented_libs_) { | ||
| 100 | for (const auto &mod : modules) { | ||
| 101 | if (!mod.instrumented()) | ||
| 102 | continue; | ||
| 103 | for (const auto &range : mod.ranges()) { | ||
| 104 | if (!range.executable) | ||
| 105 | continue; | ||
| 106 | if (IsPcInstrumented(range.beg) && IsPcInstrumented(range.end - 1)) | ||
| 107 | continue; | ||
| 108 | VReport(1, "Adding instrumented range %p-%p from library '%s'\n", | ||
| 109 | range.beg, range.end, mod.full_name()); | ||
| 110 | const uptr idx = | ||
| 111 | atomic_load(&instrumented_ranges_count_, memory_order_relaxed); | ||
| 112 | CHECK_LT(idx, ARRAY_SIZE(instrumented_code_ranges_)); | ||
| 113 | instrumented_code_ranges_[idx].begin = range.beg; | ||
| 114 | instrumented_code_ranges_[idx].end = range.end; | ||
| 115 | atomic_store(&instrumented_ranges_count_, idx + 1, | ||
| 116 | memory_order_release); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | void LibIgnore::OnLibraryUnloaded() { | ||
| 123 | OnLibraryLoaded(nullptr); | ||
| 124 | } | ||
| 125 | |||
| 126 | } // namespace __sanitizer | ||
| 127 | |||
| 128 | #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || | ||
| 129 | // SANITIZER_NETBSD | ||
lib/tsan/sanitizer_common/sanitizer_libignore.h created+115| ... | @@ -0,0 +1,115 @@ | ||
| 1 | //===-- sanitizer_libignore.h -----------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // LibIgnore allows to ignore all interceptors called from a particular set | ||
| 10 | // of dynamic libraries. LibIgnore can be initialized with several templates | ||
| 11 | // of names of libraries to be ignored. It finds code ranges for the libraries; | ||
| 12 | // and checks whether the provided PC value belongs to the code ranges. | ||
| 13 | // | ||
| 14 | //===----------------------------------------------------------------------===// | ||
| 15 | |||
| 16 | #ifndef SANITIZER_LIBIGNORE_H | ||
| 17 | #define SANITIZER_LIBIGNORE_H | ||
| 18 | |||
| 19 | #include "sanitizer_internal_defs.h" | ||
| 20 | #include "sanitizer_common.h" | ||
| 21 | #include "sanitizer_atomic.h" | ||
| 22 | #include "sanitizer_mutex.h" | ||
| 23 | |||
| 24 | namespace __sanitizer { | ||
| 25 | |||
| 26 | class LibIgnore { | ||
| 27 | public: | ||
| 28 | explicit LibIgnore(LinkerInitialized); | ||
| 29 | |||
| 30 | // Must be called during initialization. | ||
| 31 | void AddIgnoredLibrary(const char *name_templ); | ||
| 32 | void IgnoreNoninstrumentedModules(bool enable) { | ||
| 33 | track_instrumented_libs_ = enable; | ||
| 34 | } | ||
| 35 | |||
| 36 | // Must be called after a new dynamic library is loaded. | ||
| 37 | void OnLibraryLoaded(const char *name); | ||
| 38 | |||
| 39 | // Must be called after a dynamic library is unloaded. | ||
| 40 | void OnLibraryUnloaded(); | ||
| 41 | |||
| 42 | // Checks whether the provided PC belongs to one of the ignored libraries or | ||
| 43 | // the PC should be ignored because it belongs to an non-instrumented module | ||
| 44 | // (when ignore_noninstrumented_modules=1). Also returns true via | ||
| 45 | // "pc_in_ignored_lib" if the PC is in an ignored library, false otherwise. | ||
| 46 | bool IsIgnored(uptr pc, bool *pc_in_ignored_lib) const; | ||
| 47 | |||
| 48 | // Checks whether the provided PC belongs to an instrumented module. | ||
| 49 | bool IsPcInstrumented(uptr pc) const; | ||
| 50 | |||
| 51 | private: | ||
| 52 | struct Lib { | ||
| 53 | char *templ; | ||
| 54 | char *name; | ||
| 55 | char *real_name; // target of symlink | ||
| 56 | bool loaded; | ||
| 57 | }; | ||
| 58 | |||
| 59 | struct LibCodeRange { | ||
| 60 | uptr begin; | ||
| 61 | uptr end; | ||
| 62 | }; | ||
| 63 | |||
| 64 | inline bool IsInRange(uptr pc, const LibCodeRange &range) const { | ||
| 65 | return (pc >= range.begin && pc < range.end); | ||
| 66 | } | ||
| 67 | |||
| 68 | static const uptr kMaxIgnoredRanges = 128; | ||
| 69 | static const uptr kMaxInstrumentedRanges = 1024; | ||
| 70 | static const uptr kMaxLibs = 1024; | ||
| 71 | |||
| 72 | // Hot part: | ||
| 73 | atomic_uintptr_t ignored_ranges_count_; | ||
| 74 | LibCodeRange ignored_code_ranges_[kMaxIgnoredRanges]; | ||
| 75 | |||
| 76 | atomic_uintptr_t instrumented_ranges_count_; | ||
| 77 | LibCodeRange instrumented_code_ranges_[kMaxInstrumentedRanges]; | ||
| 78 | |||
| 79 | // Cold part: | ||
| 80 | BlockingMutex mutex_; | ||
| 81 | uptr count_; | ||
| 82 | Lib libs_[kMaxLibs]; | ||
| 83 | bool track_instrumented_libs_; | ||
| 84 | |||
| 85 | // Disallow copying of LibIgnore objects. | ||
| 86 | LibIgnore(const LibIgnore&); // not implemented | ||
| 87 | void operator = (const LibIgnore&); // not implemented | ||
| 88 | }; | ||
| 89 | |||
| 90 | inline bool LibIgnore::IsIgnored(uptr pc, bool *pc_in_ignored_lib) const { | ||
| 91 | const uptr n = atomic_load(&ignored_ranges_count_, memory_order_acquire); | ||
| 92 | for (uptr i = 0; i < n; i++) { | ||
| 93 | if (IsInRange(pc, ignored_code_ranges_[i])) { | ||
| 94 | *pc_in_ignored_lib = true; | ||
| 95 | return true; | ||
| 96 | } | ||
| 97 | } | ||
| 98 | *pc_in_ignored_lib = false; | ||
| 99 | if (track_instrumented_libs_ && !IsPcInstrumented(pc)) | ||
| 100 | return true; | ||
| 101 | return false; | ||
| 102 | } | ||
| 103 | |||
| 104 | inline bool LibIgnore::IsPcInstrumented(uptr pc) const { | ||
| 105 | const uptr n = atomic_load(&instrumented_ranges_count_, memory_order_acquire); | ||
| 106 | for (uptr i = 0; i < n; i++) { | ||
| 107 | if (IsInRange(pc, instrumented_code_ranges_[i])) | ||
| 108 | return true; | ||
| 109 | } | ||
| 110 | return false; | ||
| 111 | } | ||
| 112 | |||
| 113 | } // namespace __sanitizer | ||
| 114 | |||
| 115 | #endif // SANITIZER_LIBIGNORE_H | ||
lib/tsan/sanitizer_common/sanitizer_linux.cpp created+2269| ... | @@ -0,0 +1,2269 @@ | ||
| 1 | //===-- sanitizer_linux.cpp -----------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer | ||
| 10 | // run-time libraries and implements linux-specific functions from | ||
| 11 | // sanitizer_libc.h. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_platform.h" | ||
| 15 | |||
| 16 | #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ | ||
| 17 | SANITIZER_OPENBSD || SANITIZER_SOLARIS | ||
| 18 | |||
| 19 | #include "sanitizer_common.h" | ||
| 20 | #include "sanitizer_flags.h" | ||
| 21 | #include "sanitizer_getauxval.h" | ||
| 22 | #include "sanitizer_internal_defs.h" | ||
| 23 | #include "sanitizer_libc.h" | ||
| 24 | #include "sanitizer_linux.h" | ||
| 25 | #include "sanitizer_mutex.h" | ||
| 26 | #include "sanitizer_placement_new.h" | ||
| 27 | #include "sanitizer_procmaps.h" | ||
| 28 | |||
| 29 | #if SANITIZER_LINUX && !SANITIZER_GO | ||
| 30 | #include <asm/param.h> | ||
| 31 | #endif | ||
| 32 | |||
| 33 | // For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat' | ||
| 34 | // format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To | ||
| 35 | // access stat from asm/stat.h, without conflicting with definition in | ||
| 36 | // sys/stat.h, we use this trick. | ||
| 37 | #if defined(__mips64) | ||
| 38 | #include <asm/unistd.h> | ||
| 39 | #include <sys/types.h> | ||
| 40 | #define stat kernel_stat | ||
| 41 | #include <asm/stat.h> | ||
| 42 | #undef stat | ||
| 43 | #endif | ||
| 44 | |||
| 45 | #include <dlfcn.h> | ||
| 46 | #include <errno.h> | ||
| 47 | #include <fcntl.h> | ||
| 48 | #include <link.h> | ||
| 49 | #include <pthread.h> | ||
| 50 | #include <sched.h> | ||
| 51 | #include <signal.h> | ||
| 52 | #include <sys/mman.h> | ||
| 53 | #include <sys/param.h> | ||
| 54 | #if !SANITIZER_SOLARIS | ||
| 55 | #include <sys/ptrace.h> | ||
| 56 | #endif | ||
| 57 | #include <sys/resource.h> | ||
| 58 | #include <sys/stat.h> | ||
| 59 | #include <sys/syscall.h> | ||
| 60 | #include <sys/time.h> | ||
| 61 | #include <sys/types.h> | ||
| 62 | #if !SANITIZER_OPENBSD | ||
| 63 | #include <ucontext.h> | ||
| 64 | #endif | ||
| 65 | #if SANITIZER_OPENBSD | ||
| 66 | #include <sys/futex.h> | ||
| 67 | #include <sys/sysctl.h> | ||
| 68 | #endif | ||
| 69 | #include <unistd.h> | ||
| 70 | |||
| 71 | #if SANITIZER_LINUX | ||
| 72 | #include <sys/utsname.h> | ||
| 73 | #endif | ||
| 74 | |||
| 75 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 76 | #include <sys/personality.h> | ||
| 77 | #endif | ||
| 78 | |||
| 79 | #if SANITIZER_FREEBSD | ||
| 80 | #include <sys/exec.h> | ||
| 81 | #include <sys/sysctl.h> | ||
| 82 | #include <machine/atomic.h> | ||
| 83 | extern "C" { | ||
| 84 | // <sys/umtx.h> must be included after <errno.h> and <sys/types.h> on | ||
| 85 | // FreeBSD 9.2 and 10.0. | ||
| 86 | #include <sys/umtx.h> | ||
| 87 | } | ||
| 88 | #include <sys/thr.h> | ||
| 89 | #endif // SANITIZER_FREEBSD | ||
| 90 | |||
| 91 | #if SANITIZER_NETBSD | ||
| 92 | #include <limits.h> // For NAME_MAX | ||
| 93 | #include <sys/sysctl.h> | ||
| 94 | #include <sys/exec.h> | ||
| 95 | extern struct ps_strings *__ps_strings; | ||
| 96 | #endif // SANITIZER_NETBSD | ||
| 97 | |||
| 98 | #if SANITIZER_SOLARIS | ||
| 99 | #include <stdlib.h> | ||
| 100 | #include <thread.h> | ||
| 101 | #define environ _environ | ||
| 102 | #endif | ||
| 103 | |||
| 104 | extern char **environ; | ||
| 105 | |||
| 106 | #if SANITIZER_LINUX | ||
| 107 | // <linux/time.h> | ||
| 108 | struct kernel_timeval { | ||
| 109 | long tv_sec; | ||
| 110 | long tv_usec; | ||
| 111 | }; | ||
| 112 | |||
| 113 | // <linux/futex.h> is broken on some linux distributions. | ||
| 114 | const int FUTEX_WAIT = 0; | ||
| 115 | const int FUTEX_WAKE = 1; | ||
| 116 | const int FUTEX_PRIVATE_FLAG = 128; | ||
| 117 | const int FUTEX_WAIT_PRIVATE = FUTEX_WAIT | FUTEX_PRIVATE_FLAG; | ||
| 118 | const int FUTEX_WAKE_PRIVATE = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; | ||
| 119 | #endif // SANITIZER_LINUX | ||
| 120 | |||
| 121 | // Are we using 32-bit or 64-bit Linux syscalls? | ||
| 122 | // x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32 | ||
| 123 | // but it still needs to use 64-bit syscalls. | ||
| 124 | #if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \ | ||
| 125 | SANITIZER_WORDSIZE == 64) | ||
| 126 | # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1 | ||
| 127 | #else | ||
| 128 | # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0 | ||
| 129 | #endif | ||
| 130 | |||
| 131 | // Note : FreeBSD had implemented both | ||
| 132 | // Linux and OpenBSD apis, available from | ||
| 133 | // future 12.x version most likely | ||
| 134 | #if SANITIZER_LINUX && defined(__NR_getrandom) | ||
| 135 | # if !defined(GRND_NONBLOCK) | ||
| 136 | # define GRND_NONBLOCK 1 | ||
| 137 | # endif | ||
| 138 | # define SANITIZER_USE_GETRANDOM 1 | ||
| 139 | #else | ||
| 140 | # define SANITIZER_USE_GETRANDOM 0 | ||
| 141 | #endif // SANITIZER_LINUX && defined(__NR_getrandom) | ||
| 142 | |||
| 143 | #if SANITIZER_OPENBSD | ||
| 144 | # define SANITIZER_USE_GETENTROPY 1 | ||
| 145 | #else | ||
| 146 | # if SANITIZER_FREEBSD && __FreeBSD_version >= 1200000 | ||
| 147 | # define SANITIZER_USE_GETENTROPY 1 | ||
| 148 | # else | ||
| 149 | # define SANITIZER_USE_GETENTROPY 0 | ||
| 150 | # endif | ||
| 151 | #endif // SANITIZER_USE_GETENTROPY | ||
| 152 | |||
| 153 | namespace __sanitizer { | ||
| 154 | |||
| 155 | #if SANITIZER_LINUX && defined(__x86_64__) | ||
| 156 | #include "sanitizer_syscall_linux_x86_64.inc" | ||
| 157 | #elif SANITIZER_LINUX && defined(__aarch64__) | ||
| 158 | #include "sanitizer_syscall_linux_aarch64.inc" | ||
| 159 | #elif SANITIZER_LINUX && defined(__arm__) | ||
| 160 | #include "sanitizer_syscall_linux_arm.inc" | ||
| 161 | #else | ||
| 162 | #include "sanitizer_syscall_generic.inc" | ||
| 163 | #endif | ||
| 164 | |||
| 165 | // --------------- sanitizer_libc.h | ||
| 166 | #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD | ||
| 167 | #if !SANITIZER_S390 && !SANITIZER_OPENBSD | ||
| 168 | uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, | ||
| 169 | u64 offset) { | ||
| 170 | #if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS | ||
| 171 | return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd, | ||
| 172 | offset); | ||
| 173 | #else | ||
| 174 | // mmap2 specifies file offset in 4096-byte units. | ||
| 175 | CHECK(IsAligned(offset, 4096)); | ||
| 176 | return internal_syscall(SYSCALL(mmap2), addr, length, prot, flags, fd, | ||
| 177 | offset / 4096); | ||
| 178 | #endif | ||
| 179 | } | ||
| 180 | #endif // !SANITIZER_S390 && !SANITIZER_OPENBSD | ||
| 181 | |||
| 182 | #if !SANITIZER_OPENBSD | ||
| 183 | uptr internal_munmap(void *addr, uptr length) { | ||
| 184 | return internal_syscall(SYSCALL(munmap), (uptr)addr, length); | ||
| 185 | } | ||
| 186 | |||
| 187 | int internal_mprotect(void *addr, uptr length, int prot) { | ||
| 188 | return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot); | ||
| 189 | } | ||
| 190 | #endif | ||
| 191 | |||
| 192 | uptr internal_close(fd_t fd) { | ||
| 193 | return internal_syscall(SYSCALL(close), fd); | ||
| 194 | } | ||
| 195 | |||
| 196 | uptr internal_open(const char *filename, int flags) { | ||
| 197 | #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS | ||
| 198 | return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags); | ||
| 199 | #else | ||
| 200 | return internal_syscall(SYSCALL(open), (uptr)filename, flags); | ||
| 201 | #endif | ||
| 202 | } | ||
| 203 | |||
| 204 | uptr internal_open(const char *filename, int flags, u32 mode) { | ||
| 205 | #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS | ||
| 206 | return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags, | ||
| 207 | mode); | ||
| 208 | #else | ||
| 209 | return internal_syscall(SYSCALL(open), (uptr)filename, flags, mode); | ||
| 210 | #endif | ||
| 211 | } | ||
| 212 | |||
| 213 | uptr internal_read(fd_t fd, void *buf, uptr count) { | ||
| 214 | sptr res; | ||
| 215 | HANDLE_EINTR(res, | ||
| 216 | (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, count)); | ||
| 217 | return res; | ||
| 218 | } | ||
| 219 | |||
| 220 | uptr internal_write(fd_t fd, const void *buf, uptr count) { | ||
| 221 | sptr res; | ||
| 222 | HANDLE_EINTR(res, | ||
| 223 | (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf, count)); | ||
| 224 | return res; | ||
| 225 | } | ||
| 226 | |||
| 227 | uptr internal_ftruncate(fd_t fd, uptr size) { | ||
| 228 | sptr res; | ||
| 229 | HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, | ||
| 230 | (OFF_T)size)); | ||
| 231 | return res; | ||
| 232 | } | ||
| 233 | |||
| 234 | #if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX | ||
| 235 | static void stat64_to_stat(struct stat64 *in, struct stat *out) { | ||
| 236 | internal_memset(out, 0, sizeof(*out)); | ||
| 237 | out->st_dev = in->st_dev; | ||
| 238 | out->st_ino = in->st_ino; | ||
| 239 | out->st_mode = in->st_mode; | ||
| 240 | out->st_nlink = in->st_nlink; | ||
| 241 | out->st_uid = in->st_uid; | ||
| 242 | out->st_gid = in->st_gid; | ||
| 243 | out->st_rdev = in->st_rdev; | ||
| 244 | out->st_size = in->st_size; | ||
| 245 | out->st_blksize = in->st_blksize; | ||
| 246 | out->st_blocks = in->st_blocks; | ||
| 247 | out->st_atime = in->st_atime; | ||
| 248 | out->st_mtime = in->st_mtime; | ||
| 249 | out->st_ctime = in->st_ctime; | ||
| 250 | } | ||
| 251 | #endif | ||
| 252 | |||
| 253 | #if defined(__mips64) | ||
| 254 | // Undefine compatibility macros from <sys/stat.h> | ||
| 255 | // so that they would not clash with the kernel_stat | ||
| 256 | // st_[a|m|c]time fields | ||
| 257 | #undef st_atime | ||
| 258 | #undef st_mtime | ||
| 259 | #undef st_ctime | ||
| 260 | #if defined(SANITIZER_ANDROID) | ||
| 261 | // Bionic sys/stat.h defines additional macros | ||
| 262 | // for compatibility with the old NDKs and | ||
| 263 | // they clash with the kernel_stat structure | ||
| 264 | // st_[a|m|c]time_nsec fields. | ||
| 265 | #undef st_atime_nsec | ||
| 266 | #undef st_mtime_nsec | ||
| 267 | #undef st_ctime_nsec | ||
| 268 | #endif | ||
| 269 | static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { | ||
| 270 | internal_memset(out, 0, sizeof(*out)); | ||
| 271 | out->st_dev = in->st_dev; | ||
| 272 | out->st_ino = in->st_ino; | ||
| 273 | out->st_mode = in->st_mode; | ||
| 274 | out->st_nlink = in->st_nlink; | ||
| 275 | out->st_uid = in->st_uid; | ||
| 276 | out->st_gid = in->st_gid; | ||
| 277 | out->st_rdev = in->st_rdev; | ||
| 278 | out->st_size = in->st_size; | ||
| 279 | out->st_blksize = in->st_blksize; | ||
| 280 | out->st_blocks = in->st_blocks; | ||
| 281 | #if defined(__USE_MISC) || \ | ||
| 282 | defined(__USE_XOPEN2K8) || \ | ||
| 283 | defined(SANITIZER_ANDROID) | ||
| 284 | out->st_atim.tv_sec = in->st_atime; | ||
| 285 | out->st_atim.tv_nsec = in->st_atime_nsec; | ||
| 286 | out->st_mtim.tv_sec = in->st_mtime; | ||
| 287 | out->st_mtim.tv_nsec = in->st_mtime_nsec; | ||
| 288 | out->st_ctim.tv_sec = in->st_ctime; | ||
| 289 | out->st_ctim.tv_nsec = in->st_ctime_nsec; | ||
| 290 | #else | ||
| 291 | out->st_atime = in->st_atime; | ||
| 292 | out->st_atimensec = in->st_atime_nsec; | ||
| 293 | out->st_mtime = in->st_mtime; | ||
| 294 | out->st_mtimensec = in->st_mtime_nsec; | ||
| 295 | out->st_ctime = in->st_ctime; | ||
| 296 | out->st_atimensec = in->st_ctime_nsec; | ||
| 297 | #endif | ||
| 298 | } | ||
| 299 | #endif | ||
| 300 | |||
| 301 | uptr internal_stat(const char *path, void *buf) { | ||
| 302 | #if SANITIZER_FREEBSD || SANITIZER_OPENBSD | ||
| 303 | return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0); | ||
| 304 | #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS | ||
| 305 | return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, | ||
| 306 | 0); | ||
| 307 | #elif SANITIZER_LINUX_USES_64BIT_SYSCALLS | ||
| 308 | # if defined(__mips64) | ||
| 309 | // For mips64, stat syscall fills buffer in the format of kernel_stat | ||
| 310 | struct kernel_stat kbuf; | ||
| 311 | int res = internal_syscall(SYSCALL(stat), path, &kbuf); | ||
| 312 | kernel_stat_to_stat(&kbuf, (struct stat *)buf); | ||
| 313 | return res; | ||
| 314 | # else | ||
| 315 | return internal_syscall(SYSCALL(stat), (uptr)path, (uptr)buf); | ||
| 316 | # endif | ||
| 317 | #else | ||
| 318 | struct stat64 buf64; | ||
| 319 | int res = internal_syscall(SYSCALL(stat64), path, &buf64); | ||
| 320 | stat64_to_stat(&buf64, (struct stat *)buf); | ||
| 321 | return res; | ||
| 322 | #endif | ||
| 323 | } | ||
| 324 | |||
| 325 | uptr internal_lstat(const char *path, void *buf) { | ||
| 326 | #if SANITIZER_FREEBSD || SANITIZER_OPENBSD | ||
| 327 | return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, | ||
| 328 | AT_SYMLINK_NOFOLLOW); | ||
| 329 | #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS | ||
| 330 | return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, | ||
| 331 | AT_SYMLINK_NOFOLLOW); | ||
| 332 | #elif SANITIZER_LINUX_USES_64BIT_SYSCALLS | ||
| 333 | # if SANITIZER_MIPS64 | ||
| 334 | // For mips64, lstat syscall fills buffer in the format of kernel_stat | ||
| 335 | struct kernel_stat kbuf; | ||
| 336 | int res = internal_syscall(SYSCALL(lstat), path, &kbuf); | ||
| 337 | kernel_stat_to_stat(&kbuf, (struct stat *)buf); | ||
| 338 | return res; | ||
| 339 | # else | ||
| 340 | return internal_syscall(SYSCALL(lstat), (uptr)path, (uptr)buf); | ||
| 341 | # endif | ||
| 342 | #else | ||
| 343 | struct stat64 buf64; | ||
| 344 | int res = internal_syscall(SYSCALL(lstat64), path, &buf64); | ||
| 345 | stat64_to_stat(&buf64, (struct stat *)buf); | ||
| 346 | return res; | ||
| 347 | #endif | ||
| 348 | } | ||
| 349 | |||
| 350 | uptr internal_fstat(fd_t fd, void *buf) { | ||
| 351 | #if SANITIZER_FREEBSD || SANITIZER_OPENBSD || \ | ||
| 352 | SANITIZER_LINUX_USES_64BIT_SYSCALLS | ||
| 353 | #if SANITIZER_MIPS64 && !SANITIZER_OPENBSD | ||
| 354 | // For mips64, fstat syscall fills buffer in the format of kernel_stat | ||
| 355 | struct kernel_stat kbuf; | ||
| 356 | int res = internal_syscall(SYSCALL(fstat), fd, &kbuf); | ||
| 357 | kernel_stat_to_stat(&kbuf, (struct stat *)buf); | ||
| 358 | return res; | ||
| 359 | # else | ||
| 360 | return internal_syscall(SYSCALL(fstat), fd, (uptr)buf); | ||
| 361 | # endif | ||
| 362 | #else | ||
| 363 | struct stat64 buf64; | ||
| 364 | int res = internal_syscall(SYSCALL(fstat64), fd, &buf64); | ||
| 365 | stat64_to_stat(&buf64, (struct stat *)buf); | ||
| 366 | return res; | ||
| 367 | #endif | ||
| 368 | } | ||
| 369 | |||
| 370 | uptr internal_filesize(fd_t fd) { | ||
| 371 | struct stat st; | ||
| 372 | if (internal_fstat(fd, &st)) | ||
| 373 | return -1; | ||
| 374 | return (uptr)st.st_size; | ||
| 375 | } | ||
| 376 | |||
| 377 | uptr internal_dup(int oldfd) { | ||
| 378 | return internal_syscall(SYSCALL(dup), oldfd); | ||
| 379 | } | ||
| 380 | |||
| 381 | uptr internal_dup2(int oldfd, int newfd) { | ||
| 382 | #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS | ||
| 383 | return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0); | ||
| 384 | #else | ||
| 385 | return internal_syscall(SYSCALL(dup2), oldfd, newfd); | ||
| 386 | #endif | ||
| 387 | } | ||
| 388 | |||
| 389 | uptr internal_readlink(const char *path, char *buf, uptr bufsize) { | ||
| 390 | #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS | ||
| 391 | return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, | ||
| 392 | bufsize); | ||
| 393 | #elif SANITIZER_OPENBSD | ||
| 394 | return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, | ||
| 395 | bufsize); | ||
| 396 | #else | ||
| 397 | return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize); | ||
| 398 | #endif | ||
| 399 | } | ||
| 400 | |||
| 401 | uptr internal_unlink(const char *path) { | ||
| 402 | #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD | ||
| 403 | return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0); | ||
| 404 | #else | ||
| 405 | return internal_syscall(SYSCALL(unlink), (uptr)path); | ||
| 406 | #endif | ||
| 407 | } | ||
| 408 | |||
| 409 | uptr internal_rename(const char *oldpath, const char *newpath) { | ||
| 410 | #if defined(__riscv) | ||
| 411 | return internal_syscall(SYSCALL(renameat2), AT_FDCWD, (uptr)oldpath, AT_FDCWD, | ||
| 412 | (uptr)newpath, 0); | ||
| 413 | #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD | ||
| 414 | return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD, | ||
| 415 | (uptr)newpath); | ||
| 416 | #else | ||
| 417 | return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath); | ||
| 418 | #endif | ||
| 419 | } | ||
| 420 | |||
| 421 | uptr internal_sched_yield() { | ||
| 422 | return internal_syscall(SYSCALL(sched_yield)); | ||
| 423 | } | ||
| 424 | |||
| 425 | void internal__exit(int exitcode) { | ||
| 426 | #if SANITIZER_FREEBSD || SANITIZER_OPENBSD | ||
| 427 | internal_syscall(SYSCALL(exit), exitcode); | ||
| 428 | #else | ||
| 429 | internal_syscall(SYSCALL(exit_group), exitcode); | ||
| 430 | #endif | ||
| 431 | Die(); // Unreachable. | ||
| 432 | } | ||
| 433 | |||
| 434 | unsigned int internal_sleep(unsigned int seconds) { | ||
| 435 | struct timespec ts; | ||
| 436 | ts.tv_sec = seconds; | ||
| 437 | ts.tv_nsec = 0; | ||
| 438 | int res = internal_syscall(SYSCALL(nanosleep), &ts, &ts); | ||
| 439 | if (res) return ts.tv_sec; | ||
| 440 | return 0; | ||
| 441 | } | ||
| 442 | |||
| 443 | uptr internal_execve(const char *filename, char *const argv[], | ||
| 444 | char *const envp[]) { | ||
| 445 | return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv, | ||
| 446 | (uptr)envp); | ||
| 447 | } | ||
| 448 | #endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD | ||
| 449 | |||
| 450 | // ----------------- sanitizer_common.h | ||
| 451 | bool FileExists(const char *filename) { | ||
| 452 | if (ShouldMockFailureToOpen(filename)) | ||
| 453 | return false; | ||
| 454 | struct stat st; | ||
| 455 | #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS | ||
| 456 | if (internal_syscall(SYSCALL(newfstatat), AT_FDCWD, filename, &st, 0)) | ||
| 457 | #else | ||
| 458 | if (internal_stat(filename, &st)) | ||
| 459 | #endif | ||
| 460 | return false; | ||
| 461 | // Sanity check: filename is a regular file. | ||
| 462 | return S_ISREG(st.st_mode); | ||
| 463 | } | ||
| 464 | |||
| 465 | #if !SANITIZER_NETBSD | ||
| 466 | tid_t GetTid() { | ||
| 467 | #if SANITIZER_FREEBSD | ||
| 468 | long Tid; | ||
| 469 | thr_self(&Tid); | ||
| 470 | return Tid; | ||
| 471 | #elif SANITIZER_OPENBSD | ||
| 472 | return internal_syscall(SYSCALL(getthrid)); | ||
| 473 | #elif SANITIZER_SOLARIS | ||
| 474 | return thr_self(); | ||
| 475 | #else | ||
| 476 | return internal_syscall(SYSCALL(gettid)); | ||
| 477 | #endif | ||
| 478 | } | ||
| 479 | |||
| 480 | int TgKill(pid_t pid, tid_t tid, int sig) { | ||
| 481 | #if SANITIZER_LINUX | ||
| 482 | return internal_syscall(SYSCALL(tgkill), pid, tid, sig); | ||
| 483 | #elif SANITIZER_FREEBSD | ||
| 484 | return internal_syscall(SYSCALL(thr_kill2), pid, tid, sig); | ||
| 485 | #elif SANITIZER_OPENBSD | ||
| 486 | (void)pid; | ||
| 487 | return internal_syscall(SYSCALL(thrkill), tid, sig, nullptr); | ||
| 488 | #elif SANITIZER_SOLARIS | ||
| 489 | (void)pid; | ||
| 490 | return thr_kill(tid, sig); | ||
| 491 | #endif | ||
| 492 | } | ||
| 493 | #endif | ||
| 494 | |||
| 495 | #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD | ||
| 496 | u64 NanoTime() { | ||
| 497 | #if SANITIZER_FREEBSD || SANITIZER_OPENBSD | ||
| 498 | timeval tv; | ||
| 499 | #else | ||
| 500 | kernel_timeval tv; | ||
| 501 | #endif | ||
| 502 | internal_memset(&tv, 0, sizeof(tv)); | ||
| 503 | internal_syscall(SYSCALL(gettimeofday), &tv, 0); | ||
| 504 | return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000; | ||
| 505 | } | ||
| 506 | |||
| 507 | uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { | ||
| 508 | return internal_syscall(SYSCALL(clock_gettime), clk_id, tp); | ||
| 509 | } | ||
| 510 | #endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD | ||
| 511 | |||
| 512 | // Like getenv, but reads env directly from /proc (on Linux) or parses the | ||
| 513 | // 'environ' array (on some others) and does not use libc. This function | ||
| 514 | // should be called first inside __asan_init. | ||
| 515 | const char *GetEnv(const char *name) { | ||
| 516 | #if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD || \ | ||
| 517 | SANITIZER_SOLARIS | ||
| 518 | if (::environ != 0) { | ||
| 519 | uptr NameLen = internal_strlen(name); | ||
| 520 | for (char **Env = ::environ; *Env != 0; Env++) { | ||
| 521 | if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=') | ||
| 522 | return (*Env) + NameLen + 1; | ||
| 523 | } | ||
| 524 | } | ||
| 525 | return 0; // Not found. | ||
| 526 | #elif SANITIZER_LINUX | ||
| 527 | static char *environ; | ||
| 528 | static uptr len; | ||
| 529 | static bool inited; | ||
| 530 | if (!inited) { | ||
| 531 | inited = true; | ||
| 532 | uptr environ_size; | ||
| 533 | if (!ReadFileToBuffer("/proc/self/environ", &environ, &environ_size, &len)) | ||
| 534 | environ = nullptr; | ||
| 535 | } | ||
| 536 | if (!environ || len == 0) return nullptr; | ||
| 537 | uptr namelen = internal_strlen(name); | ||
| 538 | const char *p = environ; | ||
| 539 | while (*p != '\0') { // will happen at the \0\0 that terminates the buffer | ||
| 540 | // proc file has the format NAME=value\0NAME=value\0NAME=value\0... | ||
| 541 | const char* endp = | ||
| 542 | (char*)internal_memchr(p, '\0', len - (p - environ)); | ||
| 543 | if (!endp) // this entry isn't NUL terminated | ||
| 544 | return nullptr; | ||
| 545 | else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match. | ||
| 546 | return p + namelen + 1; // point after = | ||
| 547 | p = endp + 1; | ||
| 548 | } | ||
| 549 | return nullptr; // Not found. | ||
| 550 | #else | ||
| 551 | #error "Unsupported platform" | ||
| 552 | #endif | ||
| 553 | } | ||
| 554 | |||
| 555 | #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD && \ | ||
| 556 | !SANITIZER_GO | ||
| 557 | extern "C" { | ||
| 558 | SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end; | ||
| 559 | } | ||
| 560 | #endif | ||
| 561 | |||
| 562 | #if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && \ | ||
| 563 | !SANITIZER_OPENBSD | ||
| 564 | static void ReadNullSepFileToArray(const char *path, char ***arr, | ||
| 565 | int arr_size) { | ||
| 566 | char *buff; | ||
| 567 | uptr buff_size; | ||
| 568 | uptr buff_len; | ||
| 569 | *arr = (char **)MmapOrDie(arr_size * sizeof(char *), "NullSepFileArray"); | ||
| 570 | if (!ReadFileToBuffer(path, &buff, &buff_size, &buff_len, 1024 * 1024)) { | ||
| 571 | (*arr)[0] = nullptr; | ||
| 572 | return; | ||
| 573 | } | ||
| 574 | (*arr)[0] = buff; | ||
| 575 | int count, i; | ||
| 576 | for (count = 1, i = 1; ; i++) { | ||
| 577 | if (buff[i] == 0) { | ||
| 578 | if (buff[i+1] == 0) break; | ||
| 579 | (*arr)[count] = &buff[i+1]; | ||
| 580 | CHECK_LE(count, arr_size - 1); // FIXME: make this more flexible. | ||
| 581 | count++; | ||
| 582 | } | ||
| 583 | } | ||
| 584 | (*arr)[count] = nullptr; | ||
| 585 | } | ||
| 586 | #endif | ||
| 587 | |||
| 588 | #if !SANITIZER_OPENBSD | ||
| 589 | static void GetArgsAndEnv(char ***argv, char ***envp) { | ||
| 590 | #if SANITIZER_FREEBSD | ||
| 591 | // On FreeBSD, retrieving the argument and environment arrays is done via the | ||
| 592 | // kern.ps_strings sysctl, which returns a pointer to a structure containing | ||
| 593 | // this information. See also <sys/exec.h>. | ||
| 594 | ps_strings *pss; | ||
| 595 | uptr sz = sizeof(pss); | ||
| 596 | if (internal_sysctlbyname("kern.ps_strings", &pss, &sz, NULL, 0) == -1) { | ||
| 597 | Printf("sysctl kern.ps_strings failed\n"); | ||
| 598 | Die(); | ||
| 599 | } | ||
| 600 | *argv = pss->ps_argvstr; | ||
| 601 | *envp = pss->ps_envstr; | ||
| 602 | #elif SANITIZER_NETBSD | ||
| 603 | *argv = __ps_strings->ps_argvstr; | ||
| 604 | *envp = __ps_strings->ps_envstr; | ||
| 605 | #else // SANITIZER_FREEBSD | ||
| 606 | #if !SANITIZER_GO | ||
| 607 | if (&__libc_stack_end) { | ||
| 608 | uptr* stack_end = (uptr*)__libc_stack_end; | ||
| 609 | // Normally argc can be obtained from *stack_end, however, on ARM glibc's | ||
| 610 | // _start clobbers it: | ||
| 611 | // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/arm/start.S;hb=refs/heads/release/2.31/master#l75 | ||
| 612 | // Do not special-case ARM and infer argc from argv everywhere. | ||
| 613 | int argc = 0; | ||
| 614 | while (stack_end[argc + 1]) argc++; | ||
| 615 | *argv = (char**)(stack_end + 1); | ||
| 616 | *envp = (char**)(stack_end + argc + 2); | ||
| 617 | } else { | ||
| 618 | #endif // !SANITIZER_GO | ||
| 619 | static const int kMaxArgv = 2000, kMaxEnvp = 2000; | ||
| 620 | ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv); | ||
| 621 | ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp); | ||
| 622 | #if !SANITIZER_GO | ||
| 623 | } | ||
| 624 | #endif // !SANITIZER_GO | ||
| 625 | #endif // SANITIZER_FREEBSD | ||
| 626 | } | ||
| 627 | |||
| 628 | char **GetArgv() { | ||
| 629 | char **argv, **envp; | ||
| 630 | GetArgsAndEnv(&argv, &envp); | ||
| 631 | return argv; | ||
| 632 | } | ||
| 633 | |||
| 634 | char **GetEnviron() { | ||
| 635 | char **argv, **envp; | ||
| 636 | GetArgsAndEnv(&argv, &envp); | ||
| 637 | return envp; | ||
| 638 | } | ||
| 639 | |||
| 640 | #endif // !SANITIZER_OPENBSD | ||
| 641 | |||
| 642 | #if !SANITIZER_SOLARIS | ||
| 643 | enum MutexState { | ||
| 644 | MtxUnlocked = 0, | ||
| 645 | MtxLocked = 1, | ||
| 646 | MtxSleeping = 2 | ||
| 647 | }; | ||
| 648 | |||
| 649 | BlockingMutex::BlockingMutex() { | ||
| 650 | internal_memset(this, 0, sizeof(*this)); | ||
| 651 | } | ||
| 652 | |||
| 653 | void BlockingMutex::Lock() { | ||
| 654 | CHECK_EQ(owner_, 0); | ||
| 655 | atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_); | ||
| 656 | if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked) | ||
| 657 | return; | ||
| 658 | while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) { | ||
| 659 | #if SANITIZER_FREEBSD | ||
| 660 | _umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0); | ||
| 661 | #elif SANITIZER_NETBSD | ||
| 662 | sched_yield(); /* No userspace futex-like synchronization */ | ||
| 663 | #else | ||
| 664 | internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT_PRIVATE, MtxSleeping, | ||
| 665 | 0, 0, 0); | ||
| 666 | #endif | ||
| 667 | } | ||
| 668 | } | ||
| 669 | |||
| 670 | void BlockingMutex::Unlock() { | ||
| 671 | atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_); | ||
| 672 | u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release); | ||
| 673 | CHECK_NE(v, MtxUnlocked); | ||
| 674 | if (v == MtxSleeping) { | ||
| 675 | #if SANITIZER_FREEBSD | ||
| 676 | _umtx_op(m, UMTX_OP_WAKE, 1, 0, 0); | ||
| 677 | #elif SANITIZER_NETBSD | ||
| 678 | /* No userspace futex-like synchronization */ | ||
| 679 | #else | ||
| 680 | internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE_PRIVATE, 1, 0, 0, 0); | ||
| 681 | #endif | ||
| 682 | } | ||
| 683 | } | ||
| 684 | |||
| 685 | void BlockingMutex::CheckLocked() { | ||
| 686 | atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_); | ||
| 687 | CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed)); | ||
| 688 | } | ||
| 689 | #endif // !SANITIZER_SOLARIS | ||
| 690 | |||
| 691 | // ----------------- sanitizer_linux.h | ||
| 692 | // The actual size of this structure is specified by d_reclen. | ||
| 693 | // Note that getdents64 uses a different structure format. We only provide the | ||
| 694 | // 32-bit syscall here. | ||
| 695 | #if SANITIZER_NETBSD | ||
| 696 | // Not used | ||
| 697 | #elif SANITIZER_OPENBSD | ||
| 698 | // struct dirent is different for Linux and us. At this moment, we use only | ||
| 699 | // d_fileno (Linux call this d_ino), d_reclen, and d_name. | ||
| 700 | struct linux_dirent { | ||
| 701 | u64 d_ino; // d_fileno | ||
| 702 | u16 d_reclen; | ||
| 703 | u16 d_namlen; // not used | ||
| 704 | u8 d_type; // not used | ||
| 705 | char d_name[NAME_MAX + 1]; | ||
| 706 | }; | ||
| 707 | #else | ||
| 708 | struct linux_dirent { | ||
| 709 | #if SANITIZER_X32 || defined(__aarch64__) | ||
| 710 | u64 d_ino; | ||
| 711 | u64 d_off; | ||
| 712 | #else | ||
| 713 | unsigned long d_ino; | ||
| 714 | unsigned long d_off; | ||
| 715 | #endif | ||
| 716 | unsigned short d_reclen; | ||
| 717 | #ifdef __aarch64__ | ||
| 718 | unsigned char d_type; | ||
| 719 | #endif | ||
| 720 | char d_name[256]; | ||
| 721 | }; | ||
| 722 | #endif | ||
| 723 | |||
| 724 | #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD | ||
| 725 | // Syscall wrappers. | ||
| 726 | uptr internal_ptrace(int request, int pid, void *addr, void *data) { | ||
| 727 | return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr, | ||
| 728 | (uptr)data); | ||
| 729 | } | ||
| 730 | |||
| 731 | uptr internal_waitpid(int pid, int *status, int options) { | ||
| 732 | return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options, | ||
| 733 | 0 /* rusage */); | ||
| 734 | } | ||
| 735 | |||
| 736 | uptr internal_getpid() { | ||
| 737 | return internal_syscall(SYSCALL(getpid)); | ||
| 738 | } | ||
| 739 | |||
| 740 | uptr internal_getppid() { | ||
| 741 | return internal_syscall(SYSCALL(getppid)); | ||
| 742 | } | ||
| 743 | |||
| 744 | int internal_dlinfo(void *handle, int request, void *p) { | ||
| 745 | #if SANITIZER_FREEBSD | ||
| 746 | return dlinfo(handle, request, p); | ||
| 747 | #else | ||
| 748 | UNIMPLEMENTED(); | ||
| 749 | #endif | ||
| 750 | } | ||
| 751 | |||
| 752 | uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { | ||
| 753 | #if SANITIZER_FREEBSD | ||
| 754 | return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL); | ||
| 755 | #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS | ||
| 756 | return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count); | ||
| 757 | #else | ||
| 758 | return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count); | ||
| 759 | #endif | ||
| 760 | } | ||
| 761 | |||
| 762 | uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { | ||
| 763 | return internal_syscall(SYSCALL(lseek), fd, offset, whence); | ||
| 764 | } | ||
| 765 | |||
| 766 | #if SANITIZER_LINUX | ||
| 767 | uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { | ||
| 768 | return internal_syscall(SYSCALL(prctl), option, arg2, arg3, arg4, arg5); | ||
| 769 | } | ||
| 770 | #endif | ||
| 771 | |||
| 772 | uptr internal_sigaltstack(const void *ss, void *oss) { | ||
| 773 | return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss); | ||
| 774 | } | ||
| 775 | |||
| 776 | int internal_fork() { | ||
| 777 | #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS | ||
| 778 | return internal_syscall(SYSCALL(clone), SIGCHLD, 0); | ||
| 779 | #else | ||
| 780 | return internal_syscall(SYSCALL(fork)); | ||
| 781 | #endif | ||
| 782 | } | ||
| 783 | |||
| 784 | #if SANITIZER_FREEBSD || SANITIZER_OPENBSD | ||
| 785 | int internal_sysctl(const int *name, unsigned int namelen, void *oldp, | ||
| 786 | uptr *oldlenp, const void *newp, uptr newlen) { | ||
| 787 | #if SANITIZER_OPENBSD | ||
| 788 | return sysctl(name, namelen, oldp, (size_t *)oldlenp, (void *)newp, | ||
| 789 | (size_t)newlen); | ||
| 790 | #else | ||
| 791 | return internal_syscall(SYSCALL(__sysctl), name, namelen, oldp, | ||
| 792 | (size_t *)oldlenp, newp, (size_t)newlen); | ||
| 793 | #endif | ||
| 794 | } | ||
| 795 | |||
| 796 | #if SANITIZER_FREEBSD | ||
| 797 | int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, | ||
| 798 | const void *newp, uptr newlen) { | ||
| 799 | static decltype(sysctlbyname) *real = nullptr; | ||
| 800 | if (!real) | ||
| 801 | real = (decltype(sysctlbyname) *)dlsym(RTLD_NEXT, "sysctlbyname"); | ||
| 802 | CHECK(real); | ||
| 803 | return real(sname, oldp, (size_t *)oldlenp, newp, (size_t)newlen); | ||
| 804 | } | ||
| 805 | #endif | ||
| 806 | #endif | ||
| 807 | |||
| 808 | #if SANITIZER_LINUX | ||
| 809 | #define SA_RESTORER 0x04000000 | ||
| 810 | // Doesn't set sa_restorer if the caller did not set it, so use with caution | ||
| 811 | //(see below). | ||
| 812 | int internal_sigaction_norestorer(int signum, const void *act, void *oldact) { | ||
| 813 | __sanitizer_kernel_sigaction_t k_act, k_oldact; | ||
| 814 | internal_memset(&k_act, 0, sizeof(__sanitizer_kernel_sigaction_t)); | ||
| 815 | internal_memset(&k_oldact, 0, sizeof(__sanitizer_kernel_sigaction_t)); | ||
| 816 | const __sanitizer_sigaction *u_act = (const __sanitizer_sigaction *)act; | ||
| 817 | __sanitizer_sigaction *u_oldact = (__sanitizer_sigaction *)oldact; | ||
| 818 | if (u_act) { | ||
| 819 | k_act.handler = u_act->handler; | ||
| 820 | k_act.sigaction = u_act->sigaction; | ||
| 821 | internal_memcpy(&k_act.sa_mask, &u_act->sa_mask, | ||
| 822 | sizeof(__sanitizer_kernel_sigset_t)); | ||
| 823 | // Without SA_RESTORER kernel ignores the calls (probably returns EINVAL). | ||
| 824 | k_act.sa_flags = u_act->sa_flags | SA_RESTORER; | ||
| 825 | // FIXME: most often sa_restorer is unset, however the kernel requires it | ||
| 826 | // to point to a valid signal restorer that calls the rt_sigreturn syscall. | ||
| 827 | // If sa_restorer passed to the kernel is NULL, the program may crash upon | ||
| 828 | // signal delivery or fail to unwind the stack in the signal handler. | ||
| 829 | // libc implementation of sigaction() passes its own restorer to | ||
| 830 | // rt_sigaction, so we need to do the same (we'll need to reimplement the | ||
| 831 | // restorers; for x86_64 the restorer address can be obtained from | ||
| 832 | // oldact->sa_restorer upon a call to sigaction(xxx, NULL, oldact). | ||
| 833 | #if !SANITIZER_ANDROID || !SANITIZER_MIPS32 | ||
| 834 | k_act.sa_restorer = u_act->sa_restorer; | ||
| 835 | #endif | ||
| 836 | } | ||
| 837 | |||
| 838 | uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum, | ||
| 839 | (uptr)(u_act ? &k_act : nullptr), | ||
| 840 | (uptr)(u_oldact ? &k_oldact : nullptr), | ||
| 841 | (uptr)sizeof(__sanitizer_kernel_sigset_t)); | ||
| 842 | |||
| 843 | if ((result == 0) && u_oldact) { | ||
| 844 | u_oldact->handler = k_oldact.handler; | ||
| 845 | u_oldact->sigaction = k_oldact.sigaction; | ||
| 846 | internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask, | ||
| 847 | sizeof(__sanitizer_kernel_sigset_t)); | ||
| 848 | u_oldact->sa_flags = k_oldact.sa_flags; | ||
| 849 | #if !SANITIZER_ANDROID || !SANITIZER_MIPS32 | ||
| 850 | u_oldact->sa_restorer = k_oldact.sa_restorer; | ||
| 851 | #endif | ||
| 852 | } | ||
| 853 | return result; | ||
| 854 | } | ||
| 855 | #endif // SANITIZER_LINUX | ||
| 856 | |||
| 857 | uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, | ||
| 858 | __sanitizer_sigset_t *oldset) { | ||
| 859 | #if SANITIZER_FREEBSD || SANITIZER_OPENBSD | ||
| 860 | return internal_syscall(SYSCALL(sigprocmask), how, set, oldset); | ||
| 861 | #else | ||
| 862 | __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; | ||
| 863 | __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset; | ||
| 864 | return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how, (uptr)k_set, | ||
| 865 | (uptr)k_oldset, sizeof(__sanitizer_kernel_sigset_t)); | ||
| 866 | #endif | ||
| 867 | } | ||
| 868 | |||
| 869 | void internal_sigfillset(__sanitizer_sigset_t *set) { | ||
| 870 | internal_memset(set, 0xff, sizeof(*set)); | ||
| 871 | } | ||
| 872 | |||
| 873 | void internal_sigemptyset(__sanitizer_sigset_t *set) { | ||
| 874 | internal_memset(set, 0, sizeof(*set)); | ||
| 875 | } | ||
| 876 | |||
| 877 | #if SANITIZER_LINUX | ||
| 878 | void internal_sigdelset(__sanitizer_sigset_t *set, int signum) { | ||
| 879 | signum -= 1; | ||
| 880 | CHECK_GE(signum, 0); | ||
| 881 | CHECK_LT(signum, sizeof(*set) * 8); | ||
| 882 | __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; | ||
| 883 | const uptr idx = signum / (sizeof(k_set->sig[0]) * 8); | ||
| 884 | const uptr bit = signum % (sizeof(k_set->sig[0]) * 8); | ||
| 885 | k_set->sig[idx] &= ~(1 << bit); | ||
| 886 | } | ||
| 887 | |||
| 888 | bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { | ||
| 889 | signum -= 1; | ||
| 890 | CHECK_GE(signum, 0); | ||
| 891 | CHECK_LT(signum, sizeof(*set) * 8); | ||
| 892 | __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; | ||
| 893 | const uptr idx = signum / (sizeof(k_set->sig[0]) * 8); | ||
| 894 | const uptr bit = signum % (sizeof(k_set->sig[0]) * 8); | ||
| 895 | return k_set->sig[idx] & (1 << bit); | ||
| 896 | } | ||
| 897 | #elif SANITIZER_FREEBSD | ||
| 898 | void internal_sigdelset(__sanitizer_sigset_t *set, int signum) { | ||
| 899 | sigset_t *rset = reinterpret_cast<sigset_t *>(set); | ||
| 900 | sigdelset(rset, signum); | ||
| 901 | } | ||
| 902 | |||
| 903 | bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { | ||
| 904 | sigset_t *rset = reinterpret_cast<sigset_t *>(set); | ||
| 905 | return sigismember(rset, signum); | ||
| 906 | } | ||
| 907 | #endif | ||
| 908 | #endif // !SANITIZER_SOLARIS | ||
| 909 | |||
| 910 | #if !SANITIZER_NETBSD | ||
| 911 | // ThreadLister implementation. | ||
| 912 | ThreadLister::ThreadLister(pid_t pid) : pid_(pid), buffer_(4096) { | ||
| 913 | char task_directory_path[80]; | ||
| 914 | internal_snprintf(task_directory_path, sizeof(task_directory_path), | ||
| 915 | "/proc/%d/task/", pid); | ||
| 916 | descriptor_ = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY); | ||
| 917 | if (internal_iserror(descriptor_)) { | ||
| 918 | Report("Can't open /proc/%d/task for reading.\n", pid); | ||
| 919 | } | ||
| 920 | } | ||
| 921 | |||
| 922 | ThreadLister::Result ThreadLister::ListThreads( | ||
| 923 | InternalMmapVector<tid_t> *threads) { | ||
| 924 | if (internal_iserror(descriptor_)) | ||
| 925 | return Error; | ||
| 926 | internal_lseek(descriptor_, 0, SEEK_SET); | ||
| 927 | threads->clear(); | ||
| 928 | |||
| 929 | Result result = Ok; | ||
| 930 | for (bool first_read = true;; first_read = false) { | ||
| 931 | // Resize to max capacity if it was downsized by IsAlive. | ||
| 932 | buffer_.resize(buffer_.capacity()); | ||
| 933 | CHECK_GE(buffer_.size(), 4096); | ||
| 934 | uptr read = internal_getdents( | ||
| 935 | descriptor_, (struct linux_dirent *)buffer_.data(), buffer_.size()); | ||
| 936 | if (!read) | ||
| 937 | return result; | ||
| 938 | if (internal_iserror(read)) { | ||
| 939 | Report("Can't read directory entries from /proc/%d/task.\n", pid_); | ||
| 940 | return Error; | ||
| 941 | } | ||
| 942 | |||
| 943 | for (uptr begin = (uptr)buffer_.data(), end = begin + read; begin < end;) { | ||
| 944 | struct linux_dirent *entry = (struct linux_dirent *)begin; | ||
| 945 | begin += entry->d_reclen; | ||
| 946 | if (entry->d_ino == 1) { | ||
| 947 | // Inode 1 is for bad blocks and also can be a reason for early return. | ||
| 948 | // Should be emitted if kernel tried to output terminating thread. | ||
| 949 | // See proc_task_readdir implementation in Linux. | ||
| 950 | result = Incomplete; | ||
| 951 | } | ||
| 952 | if (entry->d_ino && *entry->d_name >= '0' && *entry->d_name <= '9') | ||
| 953 | threads->push_back(internal_atoll(entry->d_name)); | ||
| 954 | } | ||
| 955 | |||
| 956 | // Now we are going to detect short-read or early EOF. In such cases Linux | ||
| 957 | // can return inconsistent list with missing alive threads. | ||
| 958 | // Code will just remember that the list can be incomplete but it will | ||
| 959 | // continue reads to return as much as possible. | ||
| 960 | if (!first_read) { | ||
| 961 | // The first one was a short-read by definition. | ||
| 962 | result = Incomplete; | ||
| 963 | } else if (read > buffer_.size() - 1024) { | ||
| 964 | // Read was close to the buffer size. So double the size and assume the | ||
| 965 | // worst. | ||
| 966 | buffer_.resize(buffer_.size() * 2); | ||
| 967 | result = Incomplete; | ||
| 968 | } else if (!threads->empty() && !IsAlive(threads->back())) { | ||
| 969 | // Maybe Linux early returned from read on terminated thread (!pid_alive) | ||
| 970 | // and failed to restore read position. | ||
| 971 | // See next_tid and proc_task_instantiate in Linux. | ||
| 972 | result = Incomplete; | ||
| 973 | } | ||
| 974 | } | ||
| 975 | } | ||
| 976 | |||
| 977 | bool ThreadLister::IsAlive(int tid) { | ||
| 978 | // /proc/%d/task/%d/status uses same call to detect alive threads as | ||
| 979 | // proc_task_readdir. See task_state implementation in Linux. | ||
| 980 | char path[80]; | ||
| 981 | internal_snprintf(path, sizeof(path), "/proc/%d/task/%d/status", pid_, tid); | ||
| 982 | if (!ReadFileToVector(path, &buffer_) || buffer_.empty()) | ||
| 983 | return false; | ||
| 984 | buffer_.push_back(0); | ||
| 985 | static const char kPrefix[] = "\nPPid:"; | ||
| 986 | const char *field = internal_strstr(buffer_.data(), kPrefix); | ||
| 987 | if (!field) | ||
| 988 | return false; | ||
| 989 | field += internal_strlen(kPrefix); | ||
| 990 | return (int)internal_atoll(field) != 0; | ||
| 991 | } | ||
| 992 | |||
| 993 | ThreadLister::~ThreadLister() { | ||
| 994 | if (!internal_iserror(descriptor_)) | ||
| 995 | internal_close(descriptor_); | ||
| 996 | } | ||
| 997 | #endif | ||
| 998 | |||
| 999 | #if SANITIZER_WORDSIZE == 32 | ||
| 1000 | // Take care of unusable kernel area in top gigabyte. | ||
| 1001 | static uptr GetKernelAreaSize() { | ||
| 1002 | #if SANITIZER_LINUX && !SANITIZER_X32 | ||
| 1003 | const uptr gbyte = 1UL << 30; | ||
| 1004 | |||
| 1005 | // Firstly check if there are writable segments | ||
| 1006 | // mapped to top gigabyte (e.g. stack). | ||
| 1007 | MemoryMappingLayout proc_maps(/*cache_enabled*/true); | ||
| 1008 | if (proc_maps.Error()) | ||
| 1009 | return 0; | ||
| 1010 | MemoryMappedSegment segment; | ||
| 1011 | while (proc_maps.Next(&segment)) { | ||
| 1012 | if ((segment.end >= 3 * gbyte) && segment.IsWritable()) return 0; | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | #if !SANITIZER_ANDROID | ||
| 1016 | // Even if nothing is mapped, top Gb may still be accessible | ||
| 1017 | // if we are running on 64-bit kernel. | ||
| 1018 | // Uname may report misleading results if personality type | ||
| 1019 | // is modified (e.g. under schroot) so check this as well. | ||
| 1020 | struct utsname uname_info; | ||
| 1021 | int pers = personality(0xffffffffUL); | ||
| 1022 | if (!(pers & PER_MASK) && internal_uname(&uname_info) == 0 && | ||
| 1023 | internal_strstr(uname_info.machine, "64")) | ||
| 1024 | return 0; | ||
| 1025 | #endif // SANITIZER_ANDROID | ||
| 1026 | |||
| 1027 | // Top gigabyte is reserved for kernel. | ||
| 1028 | return gbyte; | ||
| 1029 | #else | ||
| 1030 | return 0; | ||
| 1031 | #endif // SANITIZER_LINUX && !SANITIZER_X32 | ||
| 1032 | } | ||
| 1033 | #endif // SANITIZER_WORDSIZE == 32 | ||
| 1034 | |||
| 1035 | uptr GetMaxVirtualAddress() { | ||
| 1036 | #if (SANITIZER_NETBSD || SANITIZER_OPENBSD) && defined(__x86_64__) | ||
| 1037 | return 0x7f7ffffff000ULL; // (0x00007f8000000000 - PAGE_SIZE) | ||
| 1038 | #elif SANITIZER_WORDSIZE == 64 | ||
| 1039 | # if defined(__powerpc64__) || defined(__aarch64__) | ||
| 1040 | // On PowerPC64 we have two different address space layouts: 44- and 46-bit. | ||
| 1041 | // We somehow need to figure out which one we are using now and choose | ||
| 1042 | // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL. | ||
| 1043 | // Note that with 'ulimit -s unlimited' the stack is moved away from the top | ||
| 1044 | // of the address space, so simply checking the stack address is not enough. | ||
| 1045 | // This should (does) work for both PowerPC64 Endian modes. | ||
| 1046 | // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit. | ||
| 1047 | return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1; | ||
| 1048 | # elif defined(__mips64) | ||
| 1049 | return (1ULL << 40) - 1; // 0x000000ffffffffffUL; | ||
| 1050 | # elif defined(__s390x__) | ||
| 1051 | return (1ULL << 53) - 1; // 0x001fffffffffffffUL; | ||
| 1052 | #elif defined(__sparc__) | ||
| 1053 | return ~(uptr)0; | ||
| 1054 | # else | ||
| 1055 | return (1ULL << 47) - 1; // 0x00007fffffffffffUL; | ||
| 1056 | # endif | ||
| 1057 | #else // SANITIZER_WORDSIZE == 32 | ||
| 1058 | # if defined(__s390__) | ||
| 1059 | return (1ULL << 31) - 1; // 0x7fffffff; | ||
| 1060 | # else | ||
| 1061 | return (1ULL << 32) - 1; // 0xffffffff; | ||
| 1062 | # endif | ||
| 1063 | #endif // SANITIZER_WORDSIZE | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | uptr GetMaxUserVirtualAddress() { | ||
| 1067 | uptr addr = GetMaxVirtualAddress(); | ||
| 1068 | #if SANITIZER_WORDSIZE == 32 && !defined(__s390__) | ||
| 1069 | if (!common_flags()->full_address_space) | ||
| 1070 | addr -= GetKernelAreaSize(); | ||
| 1071 | CHECK_LT(reinterpret_cast<uptr>(&addr), addr); | ||
| 1072 | #endif | ||
| 1073 | return addr; | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | #if !SANITIZER_ANDROID | ||
| 1077 | uptr GetPageSize() { | ||
| 1078 | #if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) && \ | ||
| 1079 | defined(EXEC_PAGESIZE) | ||
| 1080 | return EXEC_PAGESIZE; | ||
| 1081 | #elif SANITIZER_FREEBSD || SANITIZER_NETBSD | ||
| 1082 | // Use sysctl as sysconf can trigger interceptors internally. | ||
| 1083 | int pz = 0; | ||
| 1084 | uptr pzl = sizeof(pz); | ||
| 1085 | int mib[2] = {CTL_HW, HW_PAGESIZE}; | ||
| 1086 | int rv = internal_sysctl(mib, 2, &pz, &pzl, nullptr, 0); | ||
| 1087 | CHECK_EQ(rv, 0); | ||
| 1088 | return (uptr)pz; | ||
| 1089 | #elif SANITIZER_USE_GETAUXVAL | ||
| 1090 | return getauxval(AT_PAGESZ); | ||
| 1091 | #else | ||
| 1092 | return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy. | ||
| 1093 | #endif | ||
| 1094 | } | ||
| 1095 | #endif // !SANITIZER_ANDROID | ||
| 1096 | |||
| 1097 | #if !SANITIZER_OPENBSD | ||
| 1098 | uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { | ||
| 1099 | #if SANITIZER_SOLARIS | ||
| 1100 | const char *default_module_name = getexecname(); | ||
| 1101 | CHECK_NE(default_module_name, NULL); | ||
| 1102 | return internal_snprintf(buf, buf_len, "%s", default_module_name); | ||
| 1103 | #else | ||
| 1104 | #if SANITIZER_FREEBSD || SANITIZER_NETBSD | ||
| 1105 | #if SANITIZER_FREEBSD | ||
| 1106 | const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; | ||
| 1107 | #else | ||
| 1108 | const int Mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; | ||
| 1109 | #endif | ||
| 1110 | const char *default_module_name = "kern.proc.pathname"; | ||
| 1111 | uptr Size = buf_len; | ||
| 1112 | bool IsErr = | ||
| 1113 | (internal_sysctl(Mib, ARRAY_SIZE(Mib), buf, &Size, NULL, 0) != 0); | ||
| 1114 | int readlink_error = IsErr ? errno : 0; | ||
| 1115 | uptr module_name_len = Size; | ||
| 1116 | #else | ||
| 1117 | const char *default_module_name = "/proc/self/exe"; | ||
| 1118 | uptr module_name_len = internal_readlink( | ||
| 1119 | default_module_name, buf, buf_len); | ||
| 1120 | int readlink_error; | ||
| 1121 | bool IsErr = internal_iserror(module_name_len, &readlink_error); | ||
| 1122 | #endif // SANITIZER_SOLARIS | ||
| 1123 | if (IsErr) { | ||
| 1124 | // We can't read binary name for some reason, assume it's unknown. | ||
| 1125 | Report("WARNING: reading executable name failed with errno %d, " | ||
| 1126 | "some stack frames may not be symbolized\n", readlink_error); | ||
| 1127 | module_name_len = internal_snprintf(buf, buf_len, "%s", | ||
| 1128 | default_module_name); | ||
| 1129 | CHECK_LT(module_name_len, buf_len); | ||
| 1130 | } | ||
| 1131 | return module_name_len; | ||
| 1132 | #endif | ||
| 1133 | } | ||
| 1134 | #endif // !SANITIZER_OPENBSD | ||
| 1135 | |||
| 1136 | uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { | ||
| 1137 | #if SANITIZER_LINUX | ||
| 1138 | char *tmpbuf; | ||
| 1139 | uptr tmpsize; | ||
| 1140 | uptr tmplen; | ||
| 1141 | if (ReadFileToBuffer("/proc/self/cmdline", &tmpbuf, &tmpsize, &tmplen, | ||
| 1142 | 1024 * 1024)) { | ||
| 1143 | internal_strncpy(buf, tmpbuf, buf_len); | ||
| 1144 | UnmapOrDie(tmpbuf, tmpsize); | ||
| 1145 | return internal_strlen(buf); | ||
| 1146 | } | ||
| 1147 | #endif | ||
| 1148 | return ReadBinaryName(buf, buf_len); | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | // Match full names of the form /path/to/base_name{-,.}* | ||
| 1152 | bool LibraryNameIs(const char *full_name, const char *base_name) { | ||
| 1153 | const char *name = full_name; | ||
| 1154 | // Strip path. | ||
| 1155 | while (*name != '\0') name++; | ||
| 1156 | while (name > full_name && *name != '/') name--; | ||
| 1157 | if (*name == '/') name++; | ||
| 1158 | uptr base_name_length = internal_strlen(base_name); | ||
| 1159 | if (internal_strncmp(name, base_name, base_name_length)) return false; | ||
| 1160 | return (name[base_name_length] == '-' || name[base_name_length] == '.'); | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | #if !SANITIZER_ANDROID | ||
| 1164 | // Call cb for each region mapped by map. | ||
| 1165 | void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) { | ||
| 1166 | CHECK_NE(map, nullptr); | ||
| 1167 | #if !SANITIZER_FREEBSD && !SANITIZER_OPENBSD | ||
| 1168 | typedef ElfW(Phdr) Elf_Phdr; | ||
| 1169 | typedef ElfW(Ehdr) Elf_Ehdr; | ||
| 1170 | #endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD | ||
| 1171 | char *base = (char *)map->l_addr; | ||
| 1172 | Elf_Ehdr *ehdr = (Elf_Ehdr *)base; | ||
| 1173 | char *phdrs = base + ehdr->e_phoff; | ||
| 1174 | char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize; | ||
| 1175 | |||
| 1176 | // Find the segment with the minimum base so we can "relocate" the p_vaddr | ||
| 1177 | // fields. Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC | ||
| 1178 | // objects have a non-zero base. | ||
| 1179 | uptr preferred_base = (uptr)-1; | ||
| 1180 | for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { | ||
| 1181 | Elf_Phdr *phdr = (Elf_Phdr *)iter; | ||
| 1182 | if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr) | ||
| 1183 | preferred_base = (uptr)phdr->p_vaddr; | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | // Compute the delta from the real base to get a relocation delta. | ||
| 1187 | sptr delta = (uptr)base - preferred_base; | ||
| 1188 | // Now we can figure out what the loader really mapped. | ||
| 1189 | for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { | ||
| 1190 | Elf_Phdr *phdr = (Elf_Phdr *)iter; | ||
| 1191 | if (phdr->p_type == PT_LOAD) { | ||
| 1192 | uptr seg_start = phdr->p_vaddr + delta; | ||
| 1193 | uptr seg_end = seg_start + phdr->p_memsz; | ||
| 1194 | // None of these values are aligned. We consider the ragged edges of the | ||
| 1195 | // load command as defined, since they are mapped from the file. | ||
| 1196 | seg_start = RoundDownTo(seg_start, GetPageSizeCached()); | ||
| 1197 | seg_end = RoundUpTo(seg_end, GetPageSizeCached()); | ||
| 1198 | cb((void *)seg_start, seg_end - seg_start); | ||
| 1199 | } | ||
| 1200 | } | ||
| 1201 | } | ||
| 1202 | #endif | ||
| 1203 | |||
| 1204 | #if defined(__x86_64__) && SANITIZER_LINUX | ||
| 1205 | // We cannot use glibc's clone wrapper, because it messes with the child | ||
| 1206 | // task's TLS. It writes the PID and TID of the child task to its thread | ||
| 1207 | // descriptor, but in our case the child task shares the thread descriptor with | ||
| 1208 | // the parent (because we don't know how to allocate a new thread | ||
| 1209 | // descriptor to keep glibc happy). So the stock version of clone(), when | ||
| 1210 | // used with CLONE_VM, would end up corrupting the parent's thread descriptor. | ||
| 1211 | uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, | ||
| 1212 | int *parent_tidptr, void *newtls, int *child_tidptr) { | ||
| 1213 | long long res; | ||
| 1214 | if (!fn || !child_stack) | ||
| 1215 | return -EINVAL; | ||
| 1216 | CHECK_EQ(0, (uptr)child_stack % 16); | ||
| 1217 | child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); | ||
| 1218 | ((unsigned long long *)child_stack)[0] = (uptr)fn; | ||
| 1219 | ((unsigned long long *)child_stack)[1] = (uptr)arg; | ||
| 1220 | register void *r8 __asm__("r8") = newtls; | ||
| 1221 | register int *r10 __asm__("r10") = child_tidptr; | ||
| 1222 | __asm__ __volatile__( | ||
| 1223 | /* %rax = syscall(%rax = SYSCALL(clone), | ||
| 1224 | * %rdi = flags, | ||
| 1225 | * %rsi = child_stack, | ||
| 1226 | * %rdx = parent_tidptr, | ||
| 1227 | * %r8 = new_tls, | ||
| 1228 | * %r10 = child_tidptr) | ||
| 1229 | */ | ||
| 1230 | "syscall\n" | ||
| 1231 | |||
| 1232 | /* if (%rax != 0) | ||
| 1233 | * return; | ||
| 1234 | */ | ||
| 1235 | "testq %%rax,%%rax\n" | ||
| 1236 | "jnz 1f\n" | ||
| 1237 | |||
| 1238 | /* In the child. Terminate unwind chain. */ | ||
| 1239 | // XXX: We should also terminate the CFI unwind chain | ||
| 1240 | // here. Unfortunately clang 3.2 doesn't support the | ||
| 1241 | // necessary CFI directives, so we skip that part. | ||
| 1242 | "xorq %%rbp,%%rbp\n" | ||
| 1243 | |||
| 1244 | /* Call "fn(arg)". */ | ||
| 1245 | "popq %%rax\n" | ||
| 1246 | "popq %%rdi\n" | ||
| 1247 | "call *%%rax\n" | ||
| 1248 | |||
| 1249 | /* Call _exit(%rax). */ | ||
| 1250 | "movq %%rax,%%rdi\n" | ||
| 1251 | "movq %2,%%rax\n" | ||
| 1252 | "syscall\n" | ||
| 1253 | |||
| 1254 | /* Return to parent. */ | ||
| 1255 | "1:\n" | ||
| 1256 | : "=a" (res) | ||
| 1257 | : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), | ||
| 1258 | "S"(child_stack), | ||
| 1259 | "D"(flags), | ||
| 1260 | "d"(parent_tidptr), | ||
| 1261 | "r"(r8), | ||
| 1262 | "r"(r10) | ||
| 1263 | : "memory", "r11", "rcx"); | ||
| 1264 | return res; | ||
| 1265 | } | ||
| 1266 | #elif defined(__mips__) | ||
| 1267 | uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, | ||
| 1268 | int *parent_tidptr, void *newtls, int *child_tidptr) { | ||
| 1269 | long long res; | ||
| 1270 | if (!fn || !child_stack) | ||
| 1271 | return -EINVAL; | ||
| 1272 | CHECK_EQ(0, (uptr)child_stack % 16); | ||
| 1273 | child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); | ||
| 1274 | ((unsigned long long *)child_stack)[0] = (uptr)fn; | ||
| 1275 | ((unsigned long long *)child_stack)[1] = (uptr)arg; | ||
| 1276 | register void *a3 __asm__("$7") = newtls; | ||
| 1277 | register int *a4 __asm__("$8") = child_tidptr; | ||
| 1278 | // We don't have proper CFI directives here because it requires alot of code | ||
| 1279 | // for very marginal benefits. | ||
| 1280 | __asm__ __volatile__( | ||
| 1281 | /* $v0 = syscall($v0 = __NR_clone, | ||
| 1282 | * $a0 = flags, | ||
| 1283 | * $a1 = child_stack, | ||
| 1284 | * $a2 = parent_tidptr, | ||
| 1285 | * $a3 = new_tls, | ||
| 1286 | * $a4 = child_tidptr) | ||
| 1287 | */ | ||
| 1288 | ".cprestore 16;\n" | ||
| 1289 | "move $4,%1;\n" | ||
| 1290 | "move $5,%2;\n" | ||
| 1291 | "move $6,%3;\n" | ||
| 1292 | "move $7,%4;\n" | ||
| 1293 | /* Store the fifth argument on stack | ||
| 1294 | * if we are using 32-bit abi. | ||
| 1295 | */ | ||
| 1296 | #if SANITIZER_WORDSIZE == 32 | ||
| 1297 | "lw %5,16($29);\n" | ||
| 1298 | #else | ||
| 1299 | "move $8,%5;\n" | ||
| 1300 | #endif | ||
| 1301 | "li $2,%6;\n" | ||
| 1302 | "syscall;\n" | ||
| 1303 | |||
| 1304 | /* if ($v0 != 0) | ||
| 1305 | * return; | ||
| 1306 | */ | ||
| 1307 | "bnez $2,1f;\n" | ||
| 1308 | |||
| 1309 | /* Call "fn(arg)". */ | ||
| 1310 | #if SANITIZER_WORDSIZE == 32 | ||
| 1311 | #ifdef __BIG_ENDIAN__ | ||
| 1312 | "lw $25,4($29);\n" | ||
| 1313 | "lw $4,12($29);\n" | ||
| 1314 | #else | ||
| 1315 | "lw $25,0($29);\n" | ||
| 1316 | "lw $4,8($29);\n" | ||
| 1317 | #endif | ||
| 1318 | #else | ||
| 1319 | "ld $25,0($29);\n" | ||
| 1320 | "ld $4,8($29);\n" | ||
| 1321 | #endif | ||
| 1322 | "jal $25;\n" | ||
| 1323 | |||
| 1324 | /* Call _exit($v0). */ | ||
| 1325 | "move $4,$2;\n" | ||
| 1326 | "li $2,%7;\n" | ||
| 1327 | "syscall;\n" | ||
| 1328 | |||
| 1329 | /* Return to parent. */ | ||
| 1330 | "1:\n" | ||
| 1331 | : "=r" (res) | ||
| 1332 | : "r"(flags), | ||
| 1333 | "r"(child_stack), | ||
| 1334 | "r"(parent_tidptr), | ||
| 1335 | "r"(a3), | ||
| 1336 | "r"(a4), | ||
| 1337 | "i"(__NR_clone), | ||
| 1338 | "i"(__NR_exit) | ||
| 1339 | : "memory", "$29" ); | ||
| 1340 | return res; | ||
| 1341 | } | ||
| 1342 | #elif defined(__aarch64__) | ||
| 1343 | uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, | ||
| 1344 | int *parent_tidptr, void *newtls, int *child_tidptr) { | ||
| 1345 | long long res; | ||
| 1346 | if (!fn || !child_stack) | ||
| 1347 | return -EINVAL; | ||
| 1348 | CHECK_EQ(0, (uptr)child_stack % 16); | ||
| 1349 | child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); | ||
| 1350 | ((unsigned long long *)child_stack)[0] = (uptr)fn; | ||
| 1351 | ((unsigned long long *)child_stack)[1] = (uptr)arg; | ||
| 1352 | |||
| 1353 | register int (*__fn)(void *) __asm__("x0") = fn; | ||
| 1354 | register void *__stack __asm__("x1") = child_stack; | ||
| 1355 | register int __flags __asm__("x2") = flags; | ||
| 1356 | register void *__arg __asm__("x3") = arg; | ||
| 1357 | register int *__ptid __asm__("x4") = parent_tidptr; | ||
| 1358 | register void *__tls __asm__("x5") = newtls; | ||
| 1359 | register int *__ctid __asm__("x6") = child_tidptr; | ||
| 1360 | |||
| 1361 | __asm__ __volatile__( | ||
| 1362 | "mov x0,x2\n" /* flags */ | ||
| 1363 | "mov x2,x4\n" /* ptid */ | ||
| 1364 | "mov x3,x5\n" /* tls */ | ||
| 1365 | "mov x4,x6\n" /* ctid */ | ||
| 1366 | "mov x8,%9\n" /* clone */ | ||
| 1367 | |||
| 1368 | "svc 0x0\n" | ||
| 1369 | |||
| 1370 | /* if (%r0 != 0) | ||
| 1371 | * return %r0; | ||
| 1372 | */ | ||
| 1373 | "cmp x0, #0\n" | ||
| 1374 | "bne 1f\n" | ||
| 1375 | |||
| 1376 | /* In the child, now. Call "fn(arg)". */ | ||
| 1377 | "ldp x1, x0, [sp], #16\n" | ||
| 1378 | "blr x1\n" | ||
| 1379 | |||
| 1380 | /* Call _exit(%r0). */ | ||
| 1381 | "mov x8, %10\n" | ||
| 1382 | "svc 0x0\n" | ||
| 1383 | "1:\n" | ||
| 1384 | |||
| 1385 | : "=r" (res) | ||
| 1386 | : "i"(-EINVAL), | ||
| 1387 | "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg), | ||
| 1388 | "r"(__ptid), "r"(__tls), "r"(__ctid), | ||
| 1389 | "i"(__NR_clone), "i"(__NR_exit) | ||
| 1390 | : "x30", "memory"); | ||
| 1391 | return res; | ||
| 1392 | } | ||
| 1393 | #elif defined(__powerpc64__) | ||
| 1394 | uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, | ||
| 1395 | int *parent_tidptr, void *newtls, int *child_tidptr) { | ||
| 1396 | long long res; | ||
| 1397 | // Stack frame structure. | ||
| 1398 | #if SANITIZER_PPC64V1 | ||
| 1399 | // Back chain == 0 (SP + 112) | ||
| 1400 | // Frame (112 bytes): | ||
| 1401 | // Parameter save area (SP + 48), 8 doublewords | ||
| 1402 | // TOC save area (SP + 40) | ||
| 1403 | // Link editor doubleword (SP + 32) | ||
| 1404 | // Compiler doubleword (SP + 24) | ||
| 1405 | // LR save area (SP + 16) | ||
| 1406 | // CR save area (SP + 8) | ||
| 1407 | // Back chain (SP + 0) | ||
| 1408 | # define FRAME_SIZE 112 | ||
| 1409 | # define FRAME_TOC_SAVE_OFFSET 40 | ||
| 1410 | #elif SANITIZER_PPC64V2 | ||
| 1411 | // Back chain == 0 (SP + 32) | ||
| 1412 | // Frame (32 bytes): | ||
| 1413 | // TOC save area (SP + 24) | ||
| 1414 | // LR save area (SP + 16) | ||
| 1415 | // CR save area (SP + 8) | ||
| 1416 | // Back chain (SP + 0) | ||
| 1417 | # define FRAME_SIZE 32 | ||
| 1418 | # define FRAME_TOC_SAVE_OFFSET 24 | ||
| 1419 | #else | ||
| 1420 | # error "Unsupported PPC64 ABI" | ||
| 1421 | #endif | ||
| 1422 | if (!fn || !child_stack) | ||
| 1423 | return -EINVAL; | ||
| 1424 | CHECK_EQ(0, (uptr)child_stack % 16); | ||
| 1425 | |||
| 1426 | register int (*__fn)(void *) __asm__("r3") = fn; | ||
| 1427 | register void *__cstack __asm__("r4") = child_stack; | ||
| 1428 | register int __flags __asm__("r5") = flags; | ||
| 1429 | register void *__arg __asm__("r6") = arg; | ||
| 1430 | register int *__ptidptr __asm__("r7") = parent_tidptr; | ||
| 1431 | register void *__newtls __asm__("r8") = newtls; | ||
| 1432 | register int *__ctidptr __asm__("r9") = child_tidptr; | ||
| 1433 | |||
| 1434 | __asm__ __volatile__( | ||
| 1435 | /* fn and arg are saved across the syscall */ | ||
| 1436 | "mr 28, %5\n\t" | ||
| 1437 | "mr 27, %8\n\t" | ||
| 1438 | |||
| 1439 | /* syscall | ||
| 1440 | r0 == __NR_clone | ||
| 1441 | r3 == flags | ||
| 1442 | r4 == child_stack | ||
| 1443 | r5 == parent_tidptr | ||
| 1444 | r6 == newtls | ||
| 1445 | r7 == child_tidptr */ | ||
| 1446 | "mr 3, %7\n\t" | ||
| 1447 | "mr 5, %9\n\t" | ||
| 1448 | "mr 6, %10\n\t" | ||
| 1449 | "mr 7, %11\n\t" | ||
| 1450 | "li 0, %3\n\t" | ||
| 1451 | "sc\n\t" | ||
| 1452 | |||
| 1453 | /* Test if syscall was successful */ | ||
| 1454 | "cmpdi cr1, 3, 0\n\t" | ||
| 1455 | "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t" | ||
| 1456 | "bne- cr1, 1f\n\t" | ||
| 1457 | |||
| 1458 | /* Set up stack frame */ | ||
| 1459 | "li 29, 0\n\t" | ||
| 1460 | "stdu 29, -8(1)\n\t" | ||
| 1461 | "stdu 1, -%12(1)\n\t" | ||
| 1462 | /* Do the function call */ | ||
| 1463 | "std 2, %13(1)\n\t" | ||
| 1464 | #if SANITIZER_PPC64V1 | ||
| 1465 | "ld 0, 0(28)\n\t" | ||
| 1466 | "ld 2, 8(28)\n\t" | ||
| 1467 | "mtctr 0\n\t" | ||
| 1468 | #elif SANITIZER_PPC64V2 | ||
| 1469 | "mr 12, 28\n\t" | ||
| 1470 | "mtctr 12\n\t" | ||
| 1471 | #else | ||
| 1472 | # error "Unsupported PPC64 ABI" | ||
| 1473 | #endif | ||
| 1474 | "mr 3, 27\n\t" | ||
| 1475 | "bctrl\n\t" | ||
| 1476 | "ld 2, %13(1)\n\t" | ||
| 1477 | |||
| 1478 | /* Call _exit(r3) */ | ||
| 1479 | "li 0, %4\n\t" | ||
| 1480 | "sc\n\t" | ||
| 1481 | |||
| 1482 | /* Return to parent */ | ||
| 1483 | "1:\n\t" | ||
| 1484 | "mr %0, 3\n\t" | ||
| 1485 | : "=r" (res) | ||
| 1486 | : "0" (-1), | ||
| 1487 | "i" (EINVAL), | ||
| 1488 | "i" (__NR_clone), | ||
| 1489 | "i" (__NR_exit), | ||
| 1490 | "r" (__fn), | ||
| 1491 | "r" (__cstack), | ||
| 1492 | "r" (__flags), | ||
| 1493 | "r" (__arg), | ||
| 1494 | "r" (__ptidptr), | ||
| 1495 | "r" (__newtls), | ||
| 1496 | "r" (__ctidptr), | ||
| 1497 | "i" (FRAME_SIZE), | ||
| 1498 | "i" (FRAME_TOC_SAVE_OFFSET) | ||
| 1499 | : "cr0", "cr1", "memory", "ctr", "r0", "r27", "r28", "r29"); | ||
| 1500 | return res; | ||
| 1501 | } | ||
| 1502 | #elif defined(__i386__) && SANITIZER_LINUX | ||
| 1503 | uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, | ||
| 1504 | int *parent_tidptr, void *newtls, int *child_tidptr) { | ||
| 1505 | int res; | ||
| 1506 | if (!fn || !child_stack) | ||
| 1507 | return -EINVAL; | ||
| 1508 | CHECK_EQ(0, (uptr)child_stack % 16); | ||
| 1509 | child_stack = (char *)child_stack - 7 * sizeof(unsigned int); | ||
| 1510 | ((unsigned int *)child_stack)[0] = (uptr)flags; | ||
| 1511 | ((unsigned int *)child_stack)[1] = (uptr)0; | ||
| 1512 | ((unsigned int *)child_stack)[2] = (uptr)fn; | ||
| 1513 | ((unsigned int *)child_stack)[3] = (uptr)arg; | ||
| 1514 | __asm__ __volatile__( | ||
| 1515 | /* %eax = syscall(%eax = SYSCALL(clone), | ||
| 1516 | * %ebx = flags, | ||
| 1517 | * %ecx = child_stack, | ||
| 1518 | * %edx = parent_tidptr, | ||
| 1519 | * %esi = new_tls, | ||
| 1520 | * %edi = child_tidptr) | ||
| 1521 | */ | ||
| 1522 | |||
| 1523 | /* Obtain flags */ | ||
| 1524 | "movl (%%ecx), %%ebx\n" | ||
| 1525 | /* Do the system call */ | ||
| 1526 | "pushl %%ebx\n" | ||
| 1527 | "pushl %%esi\n" | ||
| 1528 | "pushl %%edi\n" | ||
| 1529 | /* Remember the flag value. */ | ||
| 1530 | "movl %%ebx, (%%ecx)\n" | ||
| 1531 | "int $0x80\n" | ||
| 1532 | "popl %%edi\n" | ||
| 1533 | "popl %%esi\n" | ||
| 1534 | "popl %%ebx\n" | ||
| 1535 | |||
| 1536 | /* if (%eax != 0) | ||
| 1537 | * return; | ||
| 1538 | */ | ||
| 1539 | |||
| 1540 | "test %%eax,%%eax\n" | ||
| 1541 | "jnz 1f\n" | ||
| 1542 | |||
| 1543 | /* terminate the stack frame */ | ||
| 1544 | "xorl %%ebp,%%ebp\n" | ||
| 1545 | /* Call FN. */ | ||
| 1546 | "call *%%ebx\n" | ||
| 1547 | #ifdef PIC | ||
| 1548 | "call here\n" | ||
| 1549 | "here:\n" | ||
| 1550 | "popl %%ebx\n" | ||
| 1551 | "addl $_GLOBAL_OFFSET_TABLE_+[.-here], %%ebx\n" | ||
| 1552 | #endif | ||
| 1553 | /* Call exit */ | ||
| 1554 | "movl %%eax, %%ebx\n" | ||
| 1555 | "movl %2, %%eax\n" | ||
| 1556 | "int $0x80\n" | ||
| 1557 | "1:\n" | ||
| 1558 | : "=a" (res) | ||
| 1559 | : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), | ||
| 1560 | "c"(child_stack), | ||
| 1561 | "d"(parent_tidptr), | ||
| 1562 | "S"(newtls), | ||
| 1563 | "D"(child_tidptr) | ||
| 1564 | : "memory"); | ||
| 1565 | return res; | ||
| 1566 | } | ||
| 1567 | #elif defined(__arm__) && SANITIZER_LINUX | ||
| 1568 | uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, | ||
| 1569 | int *parent_tidptr, void *newtls, int *child_tidptr) { | ||
| 1570 | unsigned int res; | ||
| 1571 | if (!fn || !child_stack) | ||
| 1572 | return -EINVAL; | ||
| 1573 | child_stack = (char *)child_stack - 2 * sizeof(unsigned int); | ||
| 1574 | ((unsigned int *)child_stack)[0] = (uptr)fn; | ||
| 1575 | ((unsigned int *)child_stack)[1] = (uptr)arg; | ||
| 1576 | register int r0 __asm__("r0") = flags; | ||
| 1577 | register void *r1 __asm__("r1") = child_stack; | ||
| 1578 | register int *r2 __asm__("r2") = parent_tidptr; | ||
| 1579 | register void *r3 __asm__("r3") = newtls; | ||
| 1580 | register int *r4 __asm__("r4") = child_tidptr; | ||
| 1581 | register int r7 __asm__("r7") = __NR_clone; | ||
| 1582 | |||
| 1583 | #if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__) | ||
| 1584 | # define ARCH_HAS_BX | ||
| 1585 | #endif | ||
| 1586 | #if __ARM_ARCH > 4 | ||
| 1587 | # define ARCH_HAS_BLX | ||
| 1588 | #endif | ||
| 1589 | |||
| 1590 | #ifdef ARCH_HAS_BX | ||
| 1591 | # ifdef ARCH_HAS_BLX | ||
| 1592 | # define BLX(R) "blx " #R "\n" | ||
| 1593 | # else | ||
| 1594 | # define BLX(R) "mov lr, pc; bx " #R "\n" | ||
| 1595 | # endif | ||
| 1596 | #else | ||
| 1597 | # define BLX(R) "mov lr, pc; mov pc," #R "\n" | ||
| 1598 | #endif | ||
| 1599 | |||
| 1600 | __asm__ __volatile__( | ||
| 1601 | /* %r0 = syscall(%r7 = SYSCALL(clone), | ||
| 1602 | * %r0 = flags, | ||
| 1603 | * %r1 = child_stack, | ||
| 1604 | * %r2 = parent_tidptr, | ||
| 1605 | * %r3 = new_tls, | ||
| 1606 | * %r4 = child_tidptr) | ||
| 1607 | */ | ||
| 1608 | |||
| 1609 | /* Do the system call */ | ||
| 1610 | "swi 0x0\n" | ||
| 1611 | |||
| 1612 | /* if (%r0 != 0) | ||
| 1613 | * return %r0; | ||
| 1614 | */ | ||
| 1615 | "cmp r0, #0\n" | ||
| 1616 | "bne 1f\n" | ||
| 1617 | |||
| 1618 | /* In the child, now. Call "fn(arg)". */ | ||
| 1619 | "ldr r0, [sp, #4]\n" | ||
| 1620 | "ldr ip, [sp], #8\n" | ||
| 1621 | BLX(ip) | ||
| 1622 | /* Call _exit(%r0). */ | ||
| 1623 | "mov r7, %7\n" | ||
| 1624 | "swi 0x0\n" | ||
| 1625 | "1:\n" | ||
| 1626 | "mov %0, r0\n" | ||
| 1627 | : "=r"(res) | ||
| 1628 | : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7), | ||
| 1629 | "i"(__NR_exit) | ||
| 1630 | : "memory"); | ||
| 1631 | return res; | ||
| 1632 | } | ||
| 1633 | #endif // defined(__x86_64__) && SANITIZER_LINUX | ||
| 1634 | |||
| 1635 | #if SANITIZER_LINUX | ||
| 1636 | int internal_uname(struct utsname *buf) { | ||
| 1637 | return internal_syscall(SYSCALL(uname), buf); | ||
| 1638 | } | ||
| 1639 | #endif | ||
| 1640 | |||
| 1641 | #if SANITIZER_ANDROID | ||
| 1642 | #if __ANDROID_API__ < 21 | ||
| 1643 | extern "C" __attribute__((weak)) int dl_iterate_phdr( | ||
| 1644 | int (*)(struct dl_phdr_info *, size_t, void *), void *); | ||
| 1645 | #endif | ||
| 1646 | |||
| 1647 | static int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size, | ||
| 1648 | void *data) { | ||
| 1649 | // Any name starting with "lib" indicates a bug in L where library base names | ||
| 1650 | // are returned instead of paths. | ||
| 1651 | if (info->dlpi_name && info->dlpi_name[0] == 'l' && | ||
| 1652 | info->dlpi_name[1] == 'i' && info->dlpi_name[2] == 'b') { | ||
| 1653 | *(bool *)data = true; | ||
| 1654 | return 1; | ||
| 1655 | } | ||
| 1656 | return 0; | ||
| 1657 | } | ||
| 1658 | |||
| 1659 | static atomic_uint32_t android_api_level; | ||
| 1660 | |||
| 1661 | static AndroidApiLevel AndroidDetectApiLevelStatic() { | ||
| 1662 | #if __ANDROID_API__ <= 19 | ||
| 1663 | return ANDROID_KITKAT; | ||
| 1664 | #elif __ANDROID_API__ <= 22 | ||
| 1665 | return ANDROID_LOLLIPOP_MR1; | ||
| 1666 | #else | ||
| 1667 | return ANDROID_POST_LOLLIPOP; | ||
| 1668 | #endif | ||
| 1669 | } | ||
| 1670 | |||
| 1671 | static AndroidApiLevel AndroidDetectApiLevel() { | ||
| 1672 | if (!&dl_iterate_phdr) | ||
| 1673 | return ANDROID_KITKAT; // K or lower | ||
| 1674 | bool base_name_seen = false; | ||
| 1675 | dl_iterate_phdr(dl_iterate_phdr_test_cb, &base_name_seen); | ||
| 1676 | if (base_name_seen) | ||
| 1677 | return ANDROID_LOLLIPOP_MR1; // L MR1 | ||
| 1678 | return ANDROID_POST_LOLLIPOP; // post-L | ||
| 1679 | // Plain L (API level 21) is completely broken wrt ASan and not very | ||
| 1680 | // interesting to detect. | ||
| 1681 | } | ||
| 1682 | |||
| 1683 | extern "C" __attribute__((weak)) void* _DYNAMIC; | ||
| 1684 | |||
| 1685 | AndroidApiLevel AndroidGetApiLevel() { | ||
| 1686 | AndroidApiLevel level = | ||
| 1687 | (AndroidApiLevel)atomic_load(&android_api_level, memory_order_relaxed); | ||
| 1688 | if (level) return level; | ||
| 1689 | level = &_DYNAMIC == nullptr ? AndroidDetectApiLevelStatic() | ||
| 1690 | : AndroidDetectApiLevel(); | ||
| 1691 | atomic_store(&android_api_level, level, memory_order_relaxed); | ||
| 1692 | return level; | ||
| 1693 | } | ||
| 1694 | |||
| 1695 | #endif | ||
| 1696 | |||
| 1697 | static HandleSignalMode GetHandleSignalModeImpl(int signum) { | ||
| 1698 | switch (signum) { | ||
| 1699 | case SIGABRT: | ||
| 1700 | return common_flags()->handle_abort; | ||
| 1701 | case SIGILL: | ||
| 1702 | return common_flags()->handle_sigill; | ||
| 1703 | case SIGTRAP: | ||
| 1704 | return common_flags()->handle_sigtrap; | ||
| 1705 | case SIGFPE: | ||
| 1706 | return common_flags()->handle_sigfpe; | ||
| 1707 | case SIGSEGV: | ||
| 1708 | return common_flags()->handle_segv; | ||
| 1709 | case SIGBUS: | ||
| 1710 | return common_flags()->handle_sigbus; | ||
| 1711 | } | ||
| 1712 | return kHandleSignalNo; | ||
| 1713 | } | ||
| 1714 | |||
| 1715 | HandleSignalMode GetHandleSignalMode(int signum) { | ||
| 1716 | HandleSignalMode result = GetHandleSignalModeImpl(signum); | ||
| 1717 | if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler) | ||
| 1718 | return kHandleSignalExclusive; | ||
| 1719 | return result; | ||
| 1720 | } | ||
| 1721 | |||
| 1722 | #if !SANITIZER_GO | ||
| 1723 | void *internal_start_thread(void *(*func)(void *arg), void *arg) { | ||
| 1724 | // Start the thread with signals blocked, otherwise it can steal user signals. | ||
| 1725 | __sanitizer_sigset_t set, old; | ||
| 1726 | internal_sigfillset(&set); | ||
| 1727 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 1728 | // Glibc uses SIGSETXID signal during setuid call. If this signal is blocked | ||
| 1729 | // on any thread, setuid call hangs (see test/tsan/setuid.c). | ||
| 1730 | internal_sigdelset(&set, 33); | ||
| 1731 | #endif | ||
| 1732 | internal_sigprocmask(SIG_SETMASK, &set, &old); | ||
| 1733 | void *th; | ||
| 1734 | real_pthread_create(&th, nullptr, func, arg); | ||
| 1735 | internal_sigprocmask(SIG_SETMASK, &old, nullptr); | ||
| 1736 | return th; | ||
| 1737 | } | ||
| 1738 | |||
| 1739 | void internal_join_thread(void *th) { | ||
| 1740 | real_pthread_join(th, nullptr); | ||
| 1741 | } | ||
| 1742 | #else | ||
| 1743 | void *internal_start_thread(void *(*func)(void *), void *arg) { return 0; } | ||
| 1744 | |||
| 1745 | void internal_join_thread(void *th) {} | ||
| 1746 | #endif | ||
| 1747 | |||
| 1748 | #if defined(__aarch64__) | ||
| 1749 | // Android headers in the older NDK releases miss this definition. | ||
| 1750 | struct __sanitizer_esr_context { | ||
| 1751 | struct _aarch64_ctx head; | ||
| 1752 | uint64_t esr; | ||
| 1753 | }; | ||
| 1754 | |||
| 1755 | static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) { | ||
| 1756 | static const u32 kEsrMagic = 0x45535201; | ||
| 1757 | u8 *aux = ucontext->uc_mcontext.__reserved; | ||
| 1758 | while (true) { | ||
| 1759 | _aarch64_ctx *ctx = (_aarch64_ctx *)aux; | ||
| 1760 | if (ctx->size == 0) break; | ||
| 1761 | if (ctx->magic == kEsrMagic) { | ||
| 1762 | *esr = ((__sanitizer_esr_context *)ctx)->esr; | ||
| 1763 | return true; | ||
| 1764 | } | ||
| 1765 | aux += ctx->size; | ||
| 1766 | } | ||
| 1767 | return false; | ||
| 1768 | } | ||
| 1769 | #endif | ||
| 1770 | |||
| 1771 | #if SANITIZER_OPENBSD | ||
| 1772 | using Context = sigcontext; | ||
| 1773 | #else | ||
| 1774 | using Context = ucontext_t; | ||
| 1775 | #endif | ||
| 1776 | |||
| 1777 | SignalContext::WriteFlag SignalContext::GetWriteFlag() const { | ||
| 1778 | Context *ucontext = (Context *)context; | ||
| 1779 | #if defined(__x86_64__) || defined(__i386__) | ||
| 1780 | static const uptr PF_WRITE = 1U << 1; | ||
| 1781 | #if SANITIZER_FREEBSD | ||
| 1782 | uptr err = ucontext->uc_mcontext.mc_err; | ||
| 1783 | #elif SANITIZER_NETBSD | ||
| 1784 | uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR]; | ||
| 1785 | #elif SANITIZER_OPENBSD | ||
| 1786 | uptr err = ucontext->sc_err; | ||
| 1787 | #elif SANITIZER_SOLARIS && defined(__i386__) | ||
| 1788 | const int Err = 13; | ||
| 1789 | uptr err = ucontext->uc_mcontext.gregs[Err]; | ||
| 1790 | #else | ||
| 1791 | uptr err = ucontext->uc_mcontext.gregs[REG_ERR]; | ||
| 1792 | #endif // SANITIZER_FREEBSD | ||
| 1793 | return err & PF_WRITE ? WRITE : READ; | ||
| 1794 | #elif defined(__mips__) | ||
| 1795 | uint32_t *exception_source; | ||
| 1796 | uint32_t faulty_instruction; | ||
| 1797 | uint32_t op_code; | ||
| 1798 | |||
| 1799 | exception_source = (uint32_t *)ucontext->uc_mcontext.pc; | ||
| 1800 | faulty_instruction = (uint32_t)(*exception_source); | ||
| 1801 | |||
| 1802 | op_code = (faulty_instruction >> 26) & 0x3f; | ||
| 1803 | |||
| 1804 | // FIXME: Add support for FPU, microMIPS, DSP, MSA memory instructions. | ||
| 1805 | switch (op_code) { | ||
| 1806 | case 0x28: // sb | ||
| 1807 | case 0x29: // sh | ||
| 1808 | case 0x2b: // sw | ||
| 1809 | case 0x3f: // sd | ||
| 1810 | #if __mips_isa_rev < 6 | ||
| 1811 | case 0x2c: // sdl | ||
| 1812 | case 0x2d: // sdr | ||
| 1813 | case 0x2a: // swl | ||
| 1814 | case 0x2e: // swr | ||
| 1815 | #endif | ||
| 1816 | return SignalContext::WRITE; | ||
| 1817 | |||
| 1818 | case 0x20: // lb | ||
| 1819 | case 0x24: // lbu | ||
| 1820 | case 0x21: // lh | ||
| 1821 | case 0x25: // lhu | ||
| 1822 | case 0x23: // lw | ||
| 1823 | case 0x27: // lwu | ||
| 1824 | case 0x37: // ld | ||
| 1825 | #if __mips_isa_rev < 6 | ||
| 1826 | case 0x1a: // ldl | ||
| 1827 | case 0x1b: // ldr | ||
| 1828 | case 0x22: // lwl | ||
| 1829 | case 0x26: // lwr | ||
| 1830 | #endif | ||
| 1831 | return SignalContext::READ; | ||
| 1832 | #if __mips_isa_rev == 6 | ||
| 1833 | case 0x3b: // pcrel | ||
| 1834 | op_code = (faulty_instruction >> 19) & 0x3; | ||
| 1835 | switch (op_code) { | ||
| 1836 | case 0x1: // lwpc | ||
| 1837 | case 0x2: // lwupc | ||
| 1838 | return SignalContext::READ; | ||
| 1839 | } | ||
| 1840 | #endif | ||
| 1841 | } | ||
| 1842 | return SignalContext::UNKNOWN; | ||
| 1843 | #elif defined(__arm__) | ||
| 1844 | static const uptr FSR_WRITE = 1U << 11; | ||
| 1845 | uptr fsr = ucontext->uc_mcontext.error_code; | ||
| 1846 | return fsr & FSR_WRITE ? WRITE : READ; | ||
| 1847 | #elif defined(__aarch64__) | ||
| 1848 | static const u64 ESR_ELx_WNR = 1U << 6; | ||
| 1849 | u64 esr; | ||
| 1850 | if (!Aarch64GetESR(ucontext, &esr)) return UNKNOWN; | ||
| 1851 | return esr & ESR_ELx_WNR ? WRITE : READ; | ||
| 1852 | #elif defined(__sparc__) | ||
| 1853 | // Decode the instruction to determine the access type. | ||
| 1854 | // From OpenSolaris $SRC/uts/sun4/os/trap.c (get_accesstype). | ||
| 1855 | #if SANITIZER_SOLARIS | ||
| 1856 | uptr pc = ucontext->uc_mcontext.gregs[REG_PC]; | ||
| 1857 | #else | ||
| 1858 | // Historical BSDism here. | ||
| 1859 | struct sigcontext *scontext = (struct sigcontext *)context; | ||
| 1860 | #if defined(__arch64__) | ||
| 1861 | uptr pc = scontext->sigc_regs.tpc; | ||
| 1862 | #else | ||
| 1863 | uptr pc = scontext->si_regs.pc; | ||
| 1864 | #endif | ||
| 1865 | #endif | ||
| 1866 | u32 instr = *(u32 *)pc; | ||
| 1867 | return (instr >> 21) & 1 ? WRITE: READ; | ||
| 1868 | #elif defined(__riscv) | ||
| 1869 | unsigned long pc = ucontext->uc_mcontext.__gregs[REG_PC]; | ||
| 1870 | unsigned faulty_instruction = *(uint16_t *)pc; | ||
| 1871 | |||
| 1872 | #if defined(__riscv_compressed) | ||
| 1873 | if ((faulty_instruction & 0x3) != 0x3) { // it's a compressed instruction | ||
| 1874 | // set op_bits to the instruction bits [1, 0, 15, 14, 13] | ||
| 1875 | unsigned op_bits = | ||
| 1876 | ((faulty_instruction & 0x3) << 3) | (faulty_instruction >> 13); | ||
| 1877 | unsigned rd = faulty_instruction & 0xF80; // bits 7-11, inclusive | ||
| 1878 | switch (op_bits) { | ||
| 1879 | case 0b10'010: // c.lwsp (rd != x0) | ||
| 1880 | #if __riscv_xlen == 64 | ||
| 1881 | case 0b10'011: // c.ldsp (rd != x0) | ||
| 1882 | #endif | ||
| 1883 | return rd ? SignalContext::READ : SignalContext::UNKNOWN; | ||
| 1884 | case 0b00'010: // c.lw | ||
| 1885 | #if __riscv_flen >= 32 && __riscv_xlen == 32 | ||
| 1886 | case 0b10'011: // c.flwsp | ||
| 1887 | #endif | ||
| 1888 | #if __riscv_flen >= 32 || __riscv_xlen == 64 | ||
| 1889 | case 0b00'011: // c.flw / c.ld | ||
| 1890 | #endif | ||
| 1891 | #if __riscv_flen == 64 | ||
| 1892 | case 0b00'001: // c.fld | ||
| 1893 | case 0b10'001: // c.fldsp | ||
| 1894 | #endif | ||
| 1895 | return SignalContext::READ; | ||
| 1896 | case 0b00'110: // c.sw | ||
| 1897 | case 0b10'110: // c.swsp | ||
| 1898 | #if __riscv_flen >= 32 || __riscv_xlen == 64 | ||
| 1899 | case 0b00'111: // c.fsw / c.sd | ||
| 1900 | case 0b10'111: // c.fswsp / c.sdsp | ||
| 1901 | #endif | ||
| 1902 | #if __riscv_flen == 64 | ||
| 1903 | case 0b00'101: // c.fsd | ||
| 1904 | case 0b10'101: // c.fsdsp | ||
| 1905 | #endif | ||
| 1906 | return SignalContext::WRITE; | ||
| 1907 | default: | ||
| 1908 | return SignalContext::UNKNOWN; | ||
| 1909 | } | ||
| 1910 | } | ||
| 1911 | #endif | ||
| 1912 | |||
| 1913 | unsigned opcode = faulty_instruction & 0x7f; // lower 7 bits | ||
| 1914 | unsigned funct3 = (faulty_instruction >> 12) & 0x7; // bits 12-14, inclusive | ||
| 1915 | switch (opcode) { | ||
| 1916 | case 0b0000011: // loads | ||
| 1917 | switch (funct3) { | ||
| 1918 | case 0b000: // lb | ||
| 1919 | case 0b001: // lh | ||
| 1920 | case 0b010: // lw | ||
| 1921 | #if __riscv_xlen == 64 | ||
| 1922 | case 0b011: // ld | ||
| 1923 | #endif | ||
| 1924 | case 0b100: // lbu | ||
| 1925 | case 0b101: // lhu | ||
| 1926 | return SignalContext::READ; | ||
| 1927 | default: | ||
| 1928 | return SignalContext::UNKNOWN; | ||
| 1929 | } | ||
| 1930 | case 0b0100011: // stores | ||
| 1931 | switch (funct3) { | ||
| 1932 | case 0b000: // sb | ||
| 1933 | case 0b001: // sh | ||
| 1934 | case 0b010: // sw | ||
| 1935 | #if __riscv_xlen == 64 | ||
| 1936 | case 0b011: // sd | ||
| 1937 | #endif | ||
| 1938 | return SignalContext::WRITE; | ||
| 1939 | default: | ||
| 1940 | return SignalContext::UNKNOWN; | ||
| 1941 | } | ||
| 1942 | #if __riscv_flen >= 32 | ||
| 1943 | case 0b0000111: // floating-point loads | ||
| 1944 | switch (funct3) { | ||
| 1945 | case 0b010: // flw | ||
| 1946 | #if __riscv_flen == 64 | ||
| 1947 | case 0b011: // fld | ||
| 1948 | #endif | ||
| 1949 | return SignalContext::READ; | ||
| 1950 | default: | ||
| 1951 | return SignalContext::UNKNOWN; | ||
| 1952 | } | ||
| 1953 | case 0b0100111: // floating-point stores | ||
| 1954 | switch (funct3) { | ||
| 1955 | case 0b010: // fsw | ||
| 1956 | #if __riscv_flen == 64 | ||
| 1957 | case 0b011: // fsd | ||
| 1958 | #endif | ||
| 1959 | return SignalContext::WRITE; | ||
| 1960 | default: | ||
| 1961 | return SignalContext::UNKNOWN; | ||
| 1962 | } | ||
| 1963 | #endif | ||
| 1964 | default: | ||
| 1965 | return SignalContext::UNKNOWN; | ||
| 1966 | } | ||
| 1967 | #else | ||
| 1968 | (void)ucontext; | ||
| 1969 | return UNKNOWN; // FIXME: Implement. | ||
| 1970 | #endif | ||
| 1971 | } | ||
| 1972 | |||
| 1973 | bool SignalContext::IsTrueFaultingAddress() const { | ||
| 1974 | auto si = static_cast<const siginfo_t *>(siginfo); | ||
| 1975 | // SIGSEGV signals without a true fault address have si_code set to 128. | ||
| 1976 | return si->si_signo == SIGSEGV && si->si_code != 128; | ||
| 1977 | } | ||
| 1978 | |||
| 1979 | void SignalContext::DumpAllRegisters(void *context) { | ||
| 1980 | // FIXME: Implement this. | ||
| 1981 | } | ||
| 1982 | |||
| 1983 | static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { | ||
| 1984 | #if SANITIZER_NETBSD | ||
| 1985 | // This covers all NetBSD architectures | ||
| 1986 | ucontext_t *ucontext = (ucontext_t *)context; | ||
| 1987 | *pc = _UC_MACHINE_PC(ucontext); | ||
| 1988 | *bp = _UC_MACHINE_FP(ucontext); | ||
| 1989 | *sp = _UC_MACHINE_SP(ucontext); | ||
| 1990 | #elif defined(__arm__) | ||
| 1991 | ucontext_t *ucontext = (ucontext_t*)context; | ||
| 1992 | *pc = ucontext->uc_mcontext.arm_pc; | ||
| 1993 | *bp = ucontext->uc_mcontext.arm_fp; | ||
| 1994 | *sp = ucontext->uc_mcontext.arm_sp; | ||
| 1995 | #elif defined(__aarch64__) | ||
| 1996 | ucontext_t *ucontext = (ucontext_t*)context; | ||
| 1997 | *pc = ucontext->uc_mcontext.pc; | ||
| 1998 | *bp = ucontext->uc_mcontext.regs[29]; | ||
| 1999 | *sp = ucontext->uc_mcontext.sp; | ||
| 2000 | #elif defined(__hppa__) | ||
| 2001 | ucontext_t *ucontext = (ucontext_t*)context; | ||
| 2002 | *pc = ucontext->uc_mcontext.sc_iaoq[0]; | ||
| 2003 | /* GCC uses %r3 whenever a frame pointer is needed. */ | ||
| 2004 | *bp = ucontext->uc_mcontext.sc_gr[3]; | ||
| 2005 | *sp = ucontext->uc_mcontext.sc_gr[30]; | ||
| 2006 | #elif defined(__x86_64__) | ||
| 2007 | # if SANITIZER_FREEBSD | ||
| 2008 | ucontext_t *ucontext = (ucontext_t*)context; | ||
| 2009 | *pc = ucontext->uc_mcontext.mc_rip; | ||
| 2010 | *bp = ucontext->uc_mcontext.mc_rbp; | ||
| 2011 | *sp = ucontext->uc_mcontext.mc_rsp; | ||
| 2012 | #elif SANITIZER_OPENBSD | ||
| 2013 | sigcontext *ucontext = (sigcontext *)context; | ||
| 2014 | *pc = ucontext->sc_rip; | ||
| 2015 | *bp = ucontext->sc_rbp; | ||
| 2016 | *sp = ucontext->sc_rsp; | ||
| 2017 | # else | ||
| 2018 | ucontext_t *ucontext = (ucontext_t*)context; | ||
| 2019 | *pc = ucontext->uc_mcontext.gregs[REG_RIP]; | ||
| 2020 | *bp = ucontext->uc_mcontext.gregs[REG_RBP]; | ||
| 2021 | *sp = ucontext->uc_mcontext.gregs[REG_RSP]; | ||
| 2022 | # endif | ||
| 2023 | #elif defined(__i386__) | ||
| 2024 | # if SANITIZER_FREEBSD | ||
| 2025 | ucontext_t *ucontext = (ucontext_t*)context; | ||
| 2026 | *pc = ucontext->uc_mcontext.mc_eip; | ||
| 2027 | *bp = ucontext->uc_mcontext.mc_ebp; | ||
| 2028 | *sp = ucontext->uc_mcontext.mc_esp; | ||
| 2029 | #elif SANITIZER_OPENBSD | ||
| 2030 | sigcontext *ucontext = (sigcontext *)context; | ||
| 2031 | *pc = ucontext->sc_eip; | ||
| 2032 | *bp = ucontext->sc_ebp; | ||
| 2033 | *sp = ucontext->sc_esp; | ||
| 2034 | # else | ||
| 2035 | ucontext_t *ucontext = (ucontext_t*)context; | ||
| 2036 | # if SANITIZER_SOLARIS | ||
| 2037 | /* Use the numeric values: the symbolic ones are undefined by llvm | ||
| 2038 | include/llvm/Support/Solaris.h. */ | ||
| 2039 | # ifndef REG_EIP | ||
| 2040 | # define REG_EIP 14 // REG_PC | ||
| 2041 | # endif | ||
| 2042 | # ifndef REG_EBP | ||
| 2043 | # define REG_EBP 6 // REG_FP | ||
| 2044 | # endif | ||
| 2045 | # ifndef REG_UESP | ||
| 2046 | # define REG_UESP 17 // REG_SP | ||
| 2047 | # endif | ||
| 2048 | # endif | ||
| 2049 | *pc = ucontext->uc_mcontext.gregs[REG_EIP]; | ||
| 2050 | *bp = ucontext->uc_mcontext.gregs[REG_EBP]; | ||
| 2051 | *sp = ucontext->uc_mcontext.gregs[REG_UESP]; | ||
| 2052 | # endif | ||
| 2053 | #elif defined(__powerpc__) || defined(__powerpc64__) | ||
| 2054 | ucontext_t *ucontext = (ucontext_t*)context; | ||
| 2055 | *pc = ucontext->uc_mcontext.regs->nip; | ||
| 2056 | *sp = ucontext->uc_mcontext.regs->gpr[PT_R1]; | ||
| 2057 | // The powerpc{,64}-linux ABIs do not specify r31 as the frame | ||
| 2058 | // pointer, but GCC always uses r31 when we need a frame pointer. | ||
| 2059 | *bp = ucontext->uc_mcontext.regs->gpr[PT_R31]; | ||
| 2060 | #elif defined(__sparc__) | ||
| 2061 | #if defined(__arch64__) || defined(__sparcv9) | ||
| 2062 | #define STACK_BIAS 2047 | ||
| 2063 | #else | ||
| 2064 | #define STACK_BIAS 0 | ||
| 2065 | # endif | ||
| 2066 | # if SANITIZER_SOLARIS | ||
| 2067 | ucontext_t *ucontext = (ucontext_t *)context; | ||
| 2068 | *pc = ucontext->uc_mcontext.gregs[REG_PC]; | ||
| 2069 | *sp = ucontext->uc_mcontext.gregs[REG_O6] + STACK_BIAS; | ||
| 2070 | #else | ||
| 2071 | // Historical BSDism here. | ||
| 2072 | struct sigcontext *scontext = (struct sigcontext *)context; | ||
| 2073 | #if defined(__arch64__) | ||
| 2074 | *pc = scontext->sigc_regs.tpc; | ||
| 2075 | *sp = scontext->sigc_regs.u_regs[14] + STACK_BIAS; | ||
| 2076 | #else | ||
| 2077 | *pc = scontext->si_regs.pc; | ||
| 2078 | *sp = scontext->si_regs.u_regs[14]; | ||
| 2079 | #endif | ||
| 2080 | # endif | ||
| 2081 | *bp = (uptr)((uhwptr *)*sp)[14] + STACK_BIAS; | ||
| 2082 | #elif defined(__mips__) | ||
| 2083 | ucontext_t *ucontext = (ucontext_t*)context; | ||
| 2084 | *pc = ucontext->uc_mcontext.pc; | ||
| 2085 | *bp = ucontext->uc_mcontext.gregs[30]; | ||
| 2086 | *sp = ucontext->uc_mcontext.gregs[29]; | ||
| 2087 | #elif defined(__s390__) | ||
| 2088 | ucontext_t *ucontext = (ucontext_t*)context; | ||
| 2089 | # if defined(__s390x__) | ||
| 2090 | *pc = ucontext->uc_mcontext.psw.addr; | ||
| 2091 | # else | ||
| 2092 | *pc = ucontext->uc_mcontext.psw.addr & 0x7fffffff; | ||
| 2093 | # endif | ||
| 2094 | *bp = ucontext->uc_mcontext.gregs[11]; | ||
| 2095 | *sp = ucontext->uc_mcontext.gregs[15]; | ||
| 2096 | #elif defined(__riscv) | ||
| 2097 | ucontext_t *ucontext = (ucontext_t*)context; | ||
| 2098 | *pc = ucontext->uc_mcontext.__gregs[REG_PC]; | ||
| 2099 | *bp = ucontext->uc_mcontext.__gregs[REG_S0]; | ||
| 2100 | *sp = ucontext->uc_mcontext.__gregs[REG_SP]; | ||
| 2101 | #else | ||
| 2102 | # error "Unsupported arch" | ||
| 2103 | #endif | ||
| 2104 | } | ||
| 2105 | |||
| 2106 | void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } | ||
| 2107 | |||
| 2108 | void InitializePlatformEarly() { | ||
| 2109 | // Do nothing. | ||
| 2110 | } | ||
| 2111 | |||
| 2112 | void MaybeReexec() { | ||
| 2113 | // No need to re-exec on Linux. | ||
| 2114 | } | ||
| 2115 | |||
| 2116 | void CheckASLR() { | ||
| 2117 | #if SANITIZER_NETBSD | ||
| 2118 | int mib[3]; | ||
| 2119 | int paxflags; | ||
| 2120 | uptr len = sizeof(paxflags); | ||
| 2121 | |||
| 2122 | mib[0] = CTL_PROC; | ||
| 2123 | mib[1] = internal_getpid(); | ||
| 2124 | mib[2] = PROC_PID_PAXFLAGS; | ||
| 2125 | |||
| 2126 | if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) { | ||
| 2127 | Printf("sysctl failed\n"); | ||
| 2128 | Die(); | ||
| 2129 | } | ||
| 2130 | |||
| 2131 | if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) { | ||
| 2132 | Printf("This sanitizer is not compatible with enabled ASLR.\n" | ||
| 2133 | "To disable ASLR, please run \"paxctl +a %s\" and try again.\n", | ||
| 2134 | GetArgv()[0]); | ||
| 2135 | Die(); | ||
| 2136 | } | ||
| 2137 | #elif SANITIZER_PPC64V2 | ||
| 2138 | // Disable ASLR for Linux PPC64LE. | ||
| 2139 | int old_personality = personality(0xffffffff); | ||
| 2140 | if (old_personality != -1 && (old_personality & ADDR_NO_RANDOMIZE) == 0) { | ||
| 2141 | VReport(1, "WARNING: Program is being run with address space layout " | ||
| 2142 | "randomization (ASLR) enabled which prevents the thread and " | ||
| 2143 | "memory sanitizers from working on powerpc64le.\n" | ||
| 2144 | "ASLR will be disabled and the program re-executed.\n"); | ||
| 2145 | CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1); | ||
| 2146 | ReExec(); | ||
| 2147 | } | ||
| 2148 | #elif SANITIZER_FREEBSD | ||
| 2149 | int aslr_pie; | ||
| 2150 | uptr len = sizeof(aslr_pie); | ||
| 2151 | #if SANITIZER_WORDSIZE == 64 | ||
| 2152 | if (UNLIKELY(internal_sysctlbyname("kern.elf64.aslr.pie_enable", | ||
| 2153 | &aslr_pie, &len, NULL, 0) == -1)) { | ||
| 2154 | // We're making things less 'dramatic' here since | ||
| 2155 | // the OID is not necessarily guaranteed to be here | ||
| 2156 | // just yet regarding FreeBSD release | ||
| 2157 | return; | ||
| 2158 | } | ||
| 2159 | |||
| 2160 | if (aslr_pie > 0) { | ||
| 2161 | Printf("This sanitizer is not compatible with enabled ASLR " | ||
| 2162 | "and binaries compiled with PIE\n"); | ||
| 2163 | Die(); | ||
| 2164 | } | ||
| 2165 | #endif | ||
| 2166 | // there might be 32 bits compat for 64 bits | ||
| 2167 | if (UNLIKELY(internal_sysctlbyname("kern.elf32.aslr.pie_enable", | ||
| 2168 | &aslr_pie, &len, NULL, 0) == -1)) { | ||
| 2169 | return; | ||
| 2170 | } | ||
| 2171 | |||
| 2172 | if (aslr_pie > 0) { | ||
| 2173 | Printf("This sanitizer is not compatible with enabled ASLR " | ||
| 2174 | "and binaries compiled with PIE\n"); | ||
| 2175 | Die(); | ||
| 2176 | } | ||
| 2177 | #else | ||
| 2178 | // Do nothing | ||
| 2179 | #endif | ||
| 2180 | } | ||
| 2181 | |||
| 2182 | void CheckMPROTECT() { | ||
| 2183 | #if SANITIZER_NETBSD | ||
| 2184 | int mib[3]; | ||
| 2185 | int paxflags; | ||
| 2186 | uptr len = sizeof(paxflags); | ||
| 2187 | |||
| 2188 | mib[0] = CTL_PROC; | ||
| 2189 | mib[1] = internal_getpid(); | ||
| 2190 | mib[2] = PROC_PID_PAXFLAGS; | ||
| 2191 | |||
| 2192 | if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) { | ||
| 2193 | Printf("sysctl failed\n"); | ||
| 2194 | Die(); | ||
| 2195 | } | ||
| 2196 | |||
| 2197 | if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_MPROTECT)) { | ||
| 2198 | Printf("This sanitizer is not compatible with enabled MPROTECT\n"); | ||
| 2199 | Die(); | ||
| 2200 | } | ||
| 2201 | #else | ||
| 2202 | // Do nothing | ||
| 2203 | #endif | ||
| 2204 | } | ||
| 2205 | |||
| 2206 | void PrintModuleMap() { } | ||
| 2207 | |||
| 2208 | void CheckNoDeepBind(const char *filename, int flag) { | ||
| 2209 | #ifdef RTLD_DEEPBIND | ||
| 2210 | if (flag & RTLD_DEEPBIND) { | ||
| 2211 | Report( | ||
| 2212 | "You are trying to dlopen a %s shared library with RTLD_DEEPBIND flag" | ||
| 2213 | " which is incompatible with sanitizer runtime " | ||
| 2214 | "(see https://github.com/google/sanitizers/issues/611 for details" | ||
| 2215 | "). If you want to run %s library under sanitizers please remove " | ||
| 2216 | "RTLD_DEEPBIND from dlopen flags.\n", | ||
| 2217 | filename, filename); | ||
| 2218 | Die(); | ||
| 2219 | } | ||
| 2220 | #endif | ||
| 2221 | } | ||
| 2222 | |||
| 2223 | uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, | ||
| 2224 | uptr *largest_gap_found, | ||
| 2225 | uptr *max_occupied_addr) { | ||
| 2226 | UNREACHABLE("FindAvailableMemoryRange is not available"); | ||
| 2227 | return 0; | ||
| 2228 | } | ||
| 2229 | |||
| 2230 | bool GetRandom(void *buffer, uptr length, bool blocking) { | ||
| 2231 | if (!buffer || !length || length > 256) | ||
| 2232 | return false; | ||
| 2233 | #if SANITIZER_USE_GETENTROPY | ||
| 2234 | uptr rnd = getentropy(buffer, length); | ||
| 2235 | int rverrno = 0; | ||
| 2236 | if (internal_iserror(rnd, &rverrno) && rverrno == EFAULT) | ||
| 2237 | return false; | ||
| 2238 | else if (rnd == 0) | ||
| 2239 | return true; | ||
| 2240 | #endif // SANITIZER_USE_GETENTROPY | ||
| 2241 | |||
| 2242 | #if SANITIZER_USE_GETRANDOM | ||
| 2243 | static atomic_uint8_t skip_getrandom_syscall; | ||
| 2244 | if (!atomic_load_relaxed(&skip_getrandom_syscall)) { | ||
| 2245 | // Up to 256 bytes, getrandom will not be interrupted. | ||
| 2246 | uptr res = internal_syscall(SYSCALL(getrandom), buffer, length, | ||
| 2247 | blocking ? 0 : GRND_NONBLOCK); | ||
| 2248 | int rverrno = 0; | ||
| 2249 | if (internal_iserror(res, &rverrno) && rverrno == ENOSYS) | ||
| 2250 | atomic_store_relaxed(&skip_getrandom_syscall, 1); | ||
| 2251 | else if (res == length) | ||
| 2252 | return true; | ||
| 2253 | } | ||
| 2254 | #endif // SANITIZER_USE_GETRANDOM | ||
| 2255 | // Up to 256 bytes, a read off /dev/urandom will not be interrupted. | ||
| 2256 | // blocking is moot here, O_NONBLOCK has no effect when opening /dev/urandom. | ||
| 2257 | uptr fd = internal_open("/dev/urandom", O_RDONLY); | ||
| 2258 | if (internal_iserror(fd)) | ||
| 2259 | return false; | ||
| 2260 | uptr res = internal_read(fd, buffer, length); | ||
| 2261 | if (internal_iserror(res)) | ||
| 2262 | return false; | ||
| 2263 | internal_close(fd); | ||
| 2264 | return true; | ||
| 2265 | } | ||
| 2266 | |||
| 2267 | } // namespace __sanitizer | ||
| 2268 | |||
| 2269 | #endif | ||
lib/tsan/sanitizer_common/sanitizer_linux.h created+162| ... | @@ -0,0 +1,162 @@ | ||
| 1 | //===-- sanitizer_linux.h ---------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Linux-specific syscall wrappers and classes. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_LINUX_H | ||
| 13 | #define SANITIZER_LINUX_H | ||
| 14 | |||
| 15 | #include "sanitizer_platform.h" | ||
| 16 | #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ | ||
| 17 | SANITIZER_OPENBSD || SANITIZER_SOLARIS | ||
| 18 | #include "sanitizer_common.h" | ||
| 19 | #include "sanitizer_internal_defs.h" | ||
| 20 | #include "sanitizer_platform_limits_freebsd.h" | ||
| 21 | #include "sanitizer_platform_limits_netbsd.h" | ||
| 22 | #include "sanitizer_platform_limits_openbsd.h" | ||
| 23 | #include "sanitizer_platform_limits_posix.h" | ||
| 24 | #include "sanitizer_platform_limits_solaris.h" | ||
| 25 | #include "sanitizer_posix.h" | ||
| 26 | |||
| 27 | struct link_map; // Opaque type returned by dlopen(). | ||
| 28 | struct utsname; | ||
| 29 | |||
| 30 | namespace __sanitizer { | ||
| 31 | // Dirent structure for getdents(). Note that this structure is different from | ||
| 32 | // the one in <dirent.h>, which is used by readdir(). | ||
| 33 | struct linux_dirent; | ||
| 34 | |||
| 35 | struct ProcSelfMapsBuff { | ||
| 36 | char *data; | ||
| 37 | uptr mmaped_size; | ||
| 38 | uptr len; | ||
| 39 | }; | ||
| 40 | |||
| 41 | struct MemoryMappingLayoutData { | ||
| 42 | ProcSelfMapsBuff proc_self_maps; | ||
| 43 | const char *current; | ||
| 44 | }; | ||
| 45 | |||
| 46 | void ReadProcMaps(ProcSelfMapsBuff *proc_maps); | ||
| 47 | |||
| 48 | // Syscall wrappers. | ||
| 49 | uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count); | ||
| 50 | uptr internal_sigaltstack(const void* ss, void* oss); | ||
| 51 | uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, | ||
| 52 | __sanitizer_sigset_t *oldset); | ||
| 53 | uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp); | ||
| 54 | |||
| 55 | // Linux-only syscalls. | ||
| 56 | #if SANITIZER_LINUX | ||
| 57 | uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5); | ||
| 58 | // Used only by sanitizer_stoptheworld. Signal handlers that are actually used | ||
| 59 | // (like the process-wide error reporting SEGV handler) must use | ||
| 60 | // internal_sigaction instead. | ||
| 61 | int internal_sigaction_norestorer(int signum, const void *act, void *oldact); | ||
| 62 | void internal_sigdelset(__sanitizer_sigset_t *set, int signum); | ||
| 63 | #if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \ | ||
| 64 | || defined(__powerpc64__) || defined(__s390__) || defined(__i386__) \ | ||
| 65 | || defined(__arm__) | ||
| 66 | uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, | ||
| 67 | int *parent_tidptr, void *newtls, int *child_tidptr); | ||
| 68 | #endif | ||
| 69 | int internal_uname(struct utsname *buf); | ||
| 70 | #elif SANITIZER_FREEBSD | ||
| 71 | void internal_sigdelset(__sanitizer_sigset_t *set, int signum); | ||
| 72 | #elif SANITIZER_NETBSD | ||
| 73 | void internal_sigdelset(__sanitizer_sigset_t *set, int signum); | ||
| 74 | uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg); | ||
| 75 | #endif // SANITIZER_LINUX | ||
| 76 | |||
| 77 | // This class reads thread IDs from /proc/<pid>/task using only syscalls. | ||
| 78 | class ThreadLister { | ||
| 79 | public: | ||
| 80 | explicit ThreadLister(pid_t pid); | ||
| 81 | ~ThreadLister(); | ||
| 82 | enum Result { | ||
| 83 | Error, | ||
| 84 | Incomplete, | ||
| 85 | Ok, | ||
| 86 | }; | ||
| 87 | Result ListThreads(InternalMmapVector<tid_t> *threads); | ||
| 88 | |||
| 89 | private: | ||
| 90 | bool IsAlive(int tid); | ||
| 91 | |||
| 92 | pid_t pid_; | ||
| 93 | int descriptor_ = -1; | ||
| 94 | InternalMmapVector<char> buffer_; | ||
| 95 | }; | ||
| 96 | |||
| 97 | // Exposed for testing. | ||
| 98 | uptr ThreadDescriptorSize(); | ||
| 99 | uptr ThreadSelf(); | ||
| 100 | uptr ThreadSelfOffset(); | ||
| 101 | |||
| 102 | // Matches a library's file name against a base name (stripping path and version | ||
| 103 | // information). | ||
| 104 | bool LibraryNameIs(const char *full_name, const char *base_name); | ||
| 105 | |||
| 106 | // Call cb for each region mapped by map. | ||
| 107 | void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)); | ||
| 108 | |||
| 109 | // Releases memory pages entirely within the [beg, end] address range. | ||
| 110 | // The pages no longer count toward RSS; reads are guaranteed to return 0. | ||
| 111 | // Requires (but does not verify!) that pages are MAP_PRIVATE. | ||
| 112 | INLINE void ReleaseMemoryPagesToOSAndZeroFill(uptr beg, uptr end) { | ||
| 113 | // man madvise on Linux promises zero-fill for anonymous private pages. | ||
| 114 | // Testing shows the same behaviour for private (but not anonymous) mappings | ||
| 115 | // of shm_open() files, as long as the underlying file is untouched. | ||
| 116 | CHECK(SANITIZER_LINUX); | ||
| 117 | ReleaseMemoryPagesToOS(beg, end); | ||
| 118 | } | ||
| 119 | |||
| 120 | #if SANITIZER_ANDROID | ||
| 121 | |||
| 122 | #if defined(__aarch64__) | ||
| 123 | # define __get_tls() \ | ||
| 124 | ({ void** __v; __asm__("mrs %0, tpidr_el0" : "=r"(__v)); __v; }) | ||
| 125 | #elif defined(__arm__) | ||
| 126 | # define __get_tls() \ | ||
| 127 | ({ void** __v; __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__v)); __v; }) | ||
| 128 | #elif defined(__mips__) | ||
| 129 | // On mips32r1, this goes via a kernel illegal instruction trap that's | ||
| 130 | // optimized for v1. | ||
| 131 | # define __get_tls() \ | ||
| 132 | ({ register void** __v asm("v1"); \ | ||
| 133 | __asm__(".set push\n" \ | ||
| 134 | ".set mips32r2\n" \ | ||
| 135 | "rdhwr %0,$29\n" \ | ||
| 136 | ".set pop\n" : "=r"(__v)); \ | ||
| 137 | __v; }) | ||
| 138 | #elif defined(__i386__) | ||
| 139 | # define __get_tls() \ | ||
| 140 | ({ void** __v; __asm__("movl %%gs:0, %0" : "=r"(__v)); __v; }) | ||
| 141 | #elif defined(__x86_64__) | ||
| 142 | # define __get_tls() \ | ||
| 143 | ({ void** __v; __asm__("mov %%fs:0, %0" : "=r"(__v)); __v; }) | ||
| 144 | #else | ||
| 145 | #error "Unsupported architecture." | ||
| 146 | #endif | ||
| 147 | |||
| 148 | // The Android Bionic team has allocated a TLS slot for sanitizers starting | ||
| 149 | // with Q, given that Android currently doesn't support ELF TLS. It is used to | ||
| 150 | // store sanitizer thread specific data. | ||
| 151 | static const int TLS_SLOT_SANITIZER = 6; | ||
| 152 | |||
| 153 | ALWAYS_INLINE uptr *get_android_tls_ptr() { | ||
| 154 | return reinterpret_cast<uptr *>(&__get_tls()[TLS_SLOT_SANITIZER]); | ||
| 155 | } | ||
| 156 | |||
| 157 | #endif // SANITIZER_ANDROID | ||
| 158 | |||
| 159 | } // namespace __sanitizer | ||
| 160 | |||
| 161 | #endif | ||
| 162 | #endif // SANITIZER_LINUX_H | ||
lib/tsan/sanitizer_common/sanitizer_linux_s390.cpp created+222| ... | @@ -0,0 +1,222 @@ | ||
| 1 | //===-- sanitizer_linux_s390.cpp ------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer | ||
| 10 | // run-time libraries and implements s390-linux-specific functions from | ||
| 11 | // sanitizer_libc.h. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_platform.h" | ||
| 15 | |||
| 16 | #if SANITIZER_LINUX && SANITIZER_S390 | ||
| 17 | |||
| 18 | #include <dlfcn.h> | ||
| 19 | #include <errno.h> | ||
| 20 | #include <sys/syscall.h> | ||
| 21 | #include <sys/utsname.h> | ||
| 22 | #include <unistd.h> | ||
| 23 | |||
| 24 | #include "sanitizer_libc.h" | ||
| 25 | #include "sanitizer_linux.h" | ||
| 26 | |||
| 27 | namespace __sanitizer { | ||
| 28 | |||
| 29 | // --------------- sanitizer_libc.h | ||
| 30 | uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, | ||
| 31 | u64 offset) { | ||
| 32 | struct s390_mmap_params { | ||
| 33 | unsigned long addr; | ||
| 34 | unsigned long length; | ||
| 35 | unsigned long prot; | ||
| 36 | unsigned long flags; | ||
| 37 | unsigned long fd; | ||
| 38 | unsigned long offset; | ||
| 39 | } params = { | ||
| 40 | (unsigned long)addr, | ||
| 41 | (unsigned long)length, | ||
| 42 | (unsigned long)prot, | ||
| 43 | (unsigned long)flags, | ||
| 44 | (unsigned long)fd, | ||
| 45 | # ifdef __s390x__ | ||
| 46 | (unsigned long)offset, | ||
| 47 | # else | ||
| 48 | (unsigned long)(offset / 4096), | ||
| 49 | # endif | ||
| 50 | }; | ||
| 51 | # ifdef __s390x__ | ||
| 52 | return syscall(__NR_mmap, &params); | ||
| 53 | # else | ||
| 54 | return syscall(__NR_mmap2, &params); | ||
| 55 | # endif | ||
| 56 | } | ||
| 57 | |||
| 58 | uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, | ||
| 59 | int *parent_tidptr, void *newtls, int *child_tidptr) { | ||
| 60 | if (!fn || !child_stack) | ||
| 61 | return -EINVAL; | ||
| 62 | CHECK_EQ(0, (uptr)child_stack % 16); | ||
| 63 | // Minimum frame size. | ||
| 64 | #ifdef __s390x__ | ||
| 65 | child_stack = (char *)child_stack - 160; | ||
| 66 | #else | ||
| 67 | child_stack = (char *)child_stack - 96; | ||
| 68 | #endif | ||
| 69 | // Terminate unwind chain. | ||
| 70 | ((unsigned long *)child_stack)[0] = 0; | ||
| 71 | // And pass parameters. | ||
| 72 | ((unsigned long *)child_stack)[1] = (uptr)fn; | ||
| 73 | ((unsigned long *)child_stack)[2] = (uptr)arg; | ||
| 74 | register long res __asm__("r2"); | ||
| 75 | register void *__cstack __asm__("r2") = child_stack; | ||
| 76 | register int __flags __asm__("r3") = flags; | ||
| 77 | register int * __ptidptr __asm__("r4") = parent_tidptr; | ||
| 78 | register int * __ctidptr __asm__("r5") = child_tidptr; | ||
| 79 | register void * __newtls __asm__("r6") = newtls; | ||
| 80 | |||
| 81 | __asm__ __volatile__( | ||
| 82 | /* Clone. */ | ||
| 83 | "svc %1\n" | ||
| 84 | |||
| 85 | /* if (%r2 != 0) | ||
| 86 | * return; | ||
| 87 | */ | ||
| 88 | #ifdef __s390x__ | ||
| 89 | "cghi %%r2, 0\n" | ||
| 90 | #else | ||
| 91 | "chi %%r2, 0\n" | ||
| 92 | #endif | ||
| 93 | "jne 1f\n" | ||
| 94 | |||
| 95 | /* Call "fn(arg)". */ | ||
| 96 | #ifdef __s390x__ | ||
| 97 | "lmg %%r1, %%r2, 8(%%r15)\n" | ||
| 98 | #else | ||
| 99 | "lm %%r1, %%r2, 4(%%r15)\n" | ||
| 100 | #endif | ||
| 101 | "basr %%r14, %%r1\n" | ||
| 102 | |||
| 103 | /* Call _exit(%r2). */ | ||
| 104 | "svc %2\n" | ||
| 105 | |||
| 106 | /* Return to parent. */ | ||
| 107 | "1:\n" | ||
| 108 | : "=r" (res) | ||
| 109 | : "i"(__NR_clone), "i"(__NR_exit), | ||
| 110 | "r"(__cstack), | ||
| 111 | "r"(__flags), | ||
| 112 | "r"(__ptidptr), | ||
| 113 | "r"(__ctidptr), | ||
| 114 | "r"(__newtls) | ||
| 115 | : "memory", "cc"); | ||
| 116 | return res; | ||
| 117 | } | ||
| 118 | |||
| 119 | #if SANITIZER_S390_64 | ||
| 120 | static bool FixedCVE_2016_2143() { | ||
| 121 | // Try to determine if the running kernel has a fix for CVE-2016-2143, | ||
| 122 | // return false if in doubt (better safe than sorry). Distros may want to | ||
| 123 | // adjust this for their own kernels. | ||
| 124 | struct utsname buf; | ||
| 125 | unsigned int major, minor, patch = 0; | ||
| 126 | // This should never fail, but just in case... | ||
| 127 | if (internal_uname(&buf)) | ||
| 128 | return false; | ||
| 129 | const char *ptr = buf.release; | ||
| 130 | major = internal_simple_strtoll(ptr, &ptr, 10); | ||
| 131 | // At least first 2 should be matched. | ||
| 132 | if (ptr[0] != '.') | ||
| 133 | return false; | ||
| 134 | minor = internal_simple_strtoll(ptr+1, &ptr, 10); | ||
| 135 | // Third is optional. | ||
| 136 | if (ptr[0] == '.') | ||
| 137 | patch = internal_simple_strtoll(ptr+1, &ptr, 10); | ||
| 138 | if (major < 3) { | ||
| 139 | if (major == 2 && minor == 6 && patch == 32 && ptr[0] == '-' && | ||
| 140 | internal_strstr(ptr, ".el6")) { | ||
| 141 | // Check RHEL6 | ||
| 142 | int r1 = internal_simple_strtoll(ptr+1, &ptr, 10); | ||
| 143 | if (r1 >= 657) // 2.6.32-657.el6 or later | ||
| 144 | return true; | ||
| 145 | if (r1 == 642 && ptr[0] == '.') { | ||
| 146 | int r2 = internal_simple_strtoll(ptr+1, &ptr, 10); | ||
| 147 | if (r2 >= 9) // 2.6.32-642.9.1.el6 or later | ||
| 148 | return true; | ||
| 149 | } | ||
| 150 | } | ||
| 151 | // <3.0 is bad. | ||
| 152 | return false; | ||
| 153 | } else if (major == 3) { | ||
| 154 | // 3.2.79+ is OK. | ||
| 155 | if (minor == 2 && patch >= 79) | ||
| 156 | return true; | ||
| 157 | // 3.12.58+ is OK. | ||
| 158 | if (minor == 12 && patch >= 58) | ||
| 159 | return true; | ||
| 160 | if (minor == 10 && patch == 0 && ptr[0] == '-' && | ||
| 161 | internal_strstr(ptr, ".el7")) { | ||
| 162 | // Check RHEL7 | ||
| 163 | int r1 = internal_simple_strtoll(ptr+1, &ptr, 10); | ||
| 164 | if (r1 >= 426) // 3.10.0-426.el7 or later | ||
| 165 | return true; | ||
| 166 | if (r1 == 327 && ptr[0] == '.') { | ||
| 167 | int r2 = internal_simple_strtoll(ptr+1, &ptr, 10); | ||
| 168 | if (r2 >= 27) // 3.10.0-327.27.1.el7 or later | ||
| 169 | return true; | ||
| 170 | } | ||
| 171 | } | ||
| 172 | // Otherwise, bad. | ||
| 173 | return false; | ||
| 174 | } else if (major == 4) { | ||
| 175 | // 4.1.21+ is OK. | ||
| 176 | if (minor == 1 && patch >= 21) | ||
| 177 | return true; | ||
| 178 | // 4.4.6+ is OK. | ||
| 179 | if (minor == 4 && patch >= 6) | ||
| 180 | return true; | ||
| 181 | if (minor == 4 && patch == 0 && ptr[0] == '-' && | ||
| 182 | internal_strstr(buf.version, "Ubuntu")) { | ||
| 183 | // Check Ubuntu 16.04 | ||
| 184 | int r1 = internal_simple_strtoll(ptr+1, &ptr, 10); | ||
| 185 | if (r1 >= 13) // 4.4.0-13 or later | ||
| 186 | return true; | ||
| 187 | } | ||
| 188 | // Otherwise, OK if 4.5+. | ||
| 189 | return minor >= 5; | ||
| 190 | } else { | ||
| 191 | // Linux 5 and up are fine. | ||
| 192 | return true; | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | void AvoidCVE_2016_2143() { | ||
| 197 | // Older kernels are affected by CVE-2016-2143 - they will crash hard | ||
| 198 | // if someone uses 4-level page tables (ie. virtual addresses >= 4TB) | ||
| 199 | // and fork() in the same process. Unfortunately, sanitizers tend to | ||
| 200 | // require such addresses. Since this is very likely to crash the whole | ||
| 201 | // machine (sanitizers themselves use fork() for llvm-symbolizer, for one), | ||
| 202 | // abort the process at initialization instead. | ||
| 203 | if (FixedCVE_2016_2143()) | ||
| 204 | return; | ||
| 205 | if (GetEnv("SANITIZER_IGNORE_CVE_2016_2143")) | ||
| 206 | return; | ||
| 207 | Report( | ||
| 208 | "ERROR: Your kernel seems to be vulnerable to CVE-2016-2143. Using ASan,\n" | ||
| 209 | "MSan, TSan, DFSan or LSan with such kernel can and will crash your\n" | ||
| 210 | "machine, or worse.\n" | ||
| 211 | "\n" | ||
| 212 | "If you are certain your kernel is not vulnerable (you have compiled it\n" | ||
| 213 | "yourself, or are using an unrecognized distribution kernel), you can\n" | ||
| 214 | "override this safety check by exporting SANITIZER_IGNORE_CVE_2016_2143\n" | ||
| 215 | "with any value.\n"); | ||
| 216 | Die(); | ||
| 217 | } | ||
| 218 | #endif | ||
| 219 | |||
| 220 | } // namespace __sanitizer | ||
| 221 | |||
| 222 | #endif // SANITIZER_LINUX && SANITIZER_S390 | ||
lib/tsan/sanitizer_common/sanitizer_list.h created+166| ... | @@ -0,0 +1,166 @@ | ||
| 1 | //===-- sanitizer_list.h ----------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file contains implementation of a list class to be used by | ||
| 10 | // ThreadSanitizer, etc run-times. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_LIST_H | ||
| 15 | #define SANITIZER_LIST_H | ||
| 16 | |||
| 17 | #include "sanitizer_internal_defs.h" | ||
| 18 | |||
| 19 | namespace __sanitizer { | ||
| 20 | |||
| 21 | // Intrusive singly-linked list with size(), push_back(), push_front() | ||
| 22 | // pop_front(), append_front() and append_back(). | ||
| 23 | // This class should be a POD (so that it can be put into TLS) | ||
| 24 | // and an object with all zero fields should represent a valid empty list. | ||
| 25 | // This class does not have a CTOR, so clear() should be called on all | ||
| 26 | // non-zero-initialized objects before using. | ||
| 27 | template<class Item> | ||
| 28 | struct IntrusiveList { | ||
| 29 | friend class Iterator; | ||
| 30 | |||
| 31 | void clear() { | ||
| 32 | first_ = last_ = nullptr; | ||
| 33 | size_ = 0; | ||
| 34 | } | ||
| 35 | |||
| 36 | bool empty() const { return size_ == 0; } | ||
| 37 | uptr size() const { return size_; } | ||
| 38 | |||
| 39 | void push_back(Item *x) { | ||
| 40 | if (empty()) { | ||
| 41 | x->next = nullptr; | ||
| 42 | first_ = last_ = x; | ||
| 43 | size_ = 1; | ||
| 44 | } else { | ||
| 45 | x->next = nullptr; | ||
| 46 | last_->next = x; | ||
| 47 | last_ = x; | ||
| 48 | size_++; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | void push_front(Item *x) { | ||
| 53 | if (empty()) { | ||
| 54 | x->next = nullptr; | ||
| 55 | first_ = last_ = x; | ||
| 56 | size_ = 1; | ||
| 57 | } else { | ||
| 58 | x->next = first_; | ||
| 59 | first_ = x; | ||
| 60 | size_++; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | void pop_front() { | ||
| 65 | CHECK(!empty()); | ||
| 66 | first_ = first_->next; | ||
| 67 | if (!first_) | ||
| 68 | last_ = nullptr; | ||
| 69 | size_--; | ||
| 70 | } | ||
| 71 | |||
| 72 | void extract(Item *prev, Item *x) { | ||
| 73 | CHECK(!empty()); | ||
| 74 | CHECK_NE(prev, nullptr); | ||
| 75 | CHECK_NE(x, nullptr); | ||
| 76 | CHECK_EQ(prev->next, x); | ||
| 77 | prev->next = x->next; | ||
| 78 | if (last_ == x) | ||
| 79 | last_ = prev; | ||
| 80 | size_--; | ||
| 81 | } | ||
| 82 | |||
| 83 | Item *front() { return first_; } | ||
| 84 | const Item *front() const { return first_; } | ||
| 85 | Item *back() { return last_; } | ||
| 86 | const Item *back() const { return last_; } | ||
| 87 | |||
| 88 | void append_front(IntrusiveList<Item> *l) { | ||
| 89 | CHECK_NE(this, l); | ||
| 90 | if (l->empty()) | ||
| 91 | return; | ||
| 92 | if (empty()) { | ||
| 93 | *this = *l; | ||
| 94 | } else if (!l->empty()) { | ||
| 95 | l->last_->next = first_; | ||
| 96 | first_ = l->first_; | ||
| 97 | size_ += l->size(); | ||
| 98 | } | ||
| 99 | l->clear(); | ||
| 100 | } | ||
| 101 | |||
| 102 | void append_back(IntrusiveList<Item> *l) { | ||
| 103 | CHECK_NE(this, l); | ||
| 104 | if (l->empty()) | ||
| 105 | return; | ||
| 106 | if (empty()) { | ||
| 107 | *this = *l; | ||
| 108 | } else { | ||
| 109 | last_->next = l->first_; | ||
| 110 | last_ = l->last_; | ||
| 111 | size_ += l->size(); | ||
| 112 | } | ||
| 113 | l->clear(); | ||
| 114 | } | ||
| 115 | |||
| 116 | void CheckConsistency() { | ||
| 117 | if (size_ == 0) { | ||
| 118 | CHECK_EQ(first_, 0); | ||
| 119 | CHECK_EQ(last_, 0); | ||
| 120 | } else { | ||
| 121 | uptr count = 0; | ||
| 122 | for (Item *i = first_; ; i = i->next) { | ||
| 123 | count++; | ||
| 124 | if (i == last_) break; | ||
| 125 | } | ||
| 126 | CHECK_EQ(size(), count); | ||
| 127 | CHECK_EQ(last_->next, 0); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | template<class ItemTy> | ||
| 132 | class IteratorBase { | ||
| 133 | public: | ||
| 134 | explicit IteratorBase(ItemTy *current) : current_(current) {} | ||
| 135 | IteratorBase &operator++() { | ||
| 136 | current_ = current_->next; | ||
| 137 | return *this; | ||
| 138 | } | ||
| 139 | bool operator!=(IteratorBase other) const { | ||
| 140 | return current_ != other.current_; | ||
| 141 | } | ||
| 142 | ItemTy &operator*() { | ||
| 143 | return *current_; | ||
| 144 | } | ||
| 145 | private: | ||
| 146 | ItemTy *current_; | ||
| 147 | }; | ||
| 148 | |||
| 149 | typedef IteratorBase<Item> Iterator; | ||
| 150 | typedef IteratorBase<const Item> ConstIterator; | ||
| 151 | |||
| 152 | Iterator begin() { return Iterator(first_); } | ||
| 153 | Iterator end() { return Iterator(0); } | ||
| 154 | |||
| 155 | ConstIterator begin() const { return ConstIterator(first_); } | ||
| 156 | ConstIterator end() const { return ConstIterator(0); } | ||
| 157 | |||
| 158 | // private, don't use directly. | ||
| 159 | uptr size_; | ||
| 160 | Item *first_; | ||
| 161 | Item *last_; | ||
| 162 | }; | ||
| 163 | |||
| 164 | } // namespace __sanitizer | ||
| 165 | |||
| 166 | #endif // SANITIZER_LIST_H | ||
lib/tsan/sanitizer_common/sanitizer_local_address_space_view.h created+76| ... | @@ -0,0 +1,76 @@ | ||
| 1 | //===-- sanitizer_local_address_space_view.h --------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // `LocalAddressSpaceView` provides the local (i.e. target and current address | ||
| 10 | // space are the same) implementation of the `AddressSpaveView` interface which | ||
| 11 | // provides a simple interface to load memory from another process (i.e. | ||
| 12 | // out-of-process) | ||
| 13 | // | ||
| 14 | // The `AddressSpaceView` interface requires that the type can be used as a | ||
| 15 | // template parameter to objects that wish to be able to operate in an | ||
| 16 | // out-of-process manner. In normal usage, objects are in-process and are thus | ||
| 17 | // instantiated with the `LocalAddressSpaceView` type. This type is used to | ||
| 18 | // load any pointers in instance methods. This implementation is effectively | ||
| 19 | // a no-op. When an object is to be used in an out-of-process manner it is | ||
| 20 | // instansiated with the `RemoteAddressSpaceView` type. | ||
| 21 | // | ||
| 22 | // By making `AddressSpaceView` a template parameter of an object, it can | ||
| 23 | // change its implementation at compile time which has no run time overhead. | ||
| 24 | // This also allows unifying in-process and out-of-process code which avoids | ||
| 25 | // code duplication. | ||
| 26 | // | ||
| 27 | //===----------------------------------------------------------------------===// | ||
| 28 | #ifndef SANITIZER_LOCAL_ADDRES_SPACE_VIEW_H | ||
| 29 | #define SANITIZER_LOCAL_ADDRES_SPACE_VIEW_H | ||
| 30 | |||
| 31 | namespace __sanitizer { | ||
| 32 | struct LocalAddressSpaceView { | ||
| 33 | // Load memory `sizeof(T) * num_elements` bytes of memory from the target | ||
| 34 | // process (always local for this implementation) starting at address | ||
| 35 | // `target_address`. The local copy of this memory is returned as a pointer. | ||
| 36 | // The caller should not write to this memory. The behaviour when doing so is | ||
| 37 | // undefined. Callers should use `LoadWritable()` to get access to memory | ||
| 38 | // that is writable. | ||
| 39 | // | ||
| 40 | // The lifetime of loaded memory is implementation defined. | ||
| 41 | template <typename T> | ||
| 42 | static const T *Load(const T *target_address, uptr num_elements = 1) { | ||
| 43 | // The target address space is the local address space so | ||
| 44 | // nothing needs to be copied. Just return the pointer. | ||
| 45 | return target_address; | ||
| 46 | } | ||
| 47 | |||
| 48 | // Load memory `sizeof(T) * num_elements` bytes of memory from the target | ||
| 49 | // process (always local for this implementation) starting at address | ||
| 50 | // `target_address`. The local copy of this memory is returned as a pointer. | ||
| 51 | // The memory returned may be written to. | ||
| 52 | // | ||
| 53 | // Writes made to the returned memory will be visible in the memory returned | ||
| 54 | // by subsequent `Load()` or `LoadWritable()` calls provided the | ||
| 55 | // `target_address` parameter is the same. It is not guaranteed that the | ||
| 56 | // memory returned by previous calls to `Load()` will contain any performed | ||
| 57 | // writes. If two or more overlapping regions of memory are loaded via | ||
| 58 | // separate calls to `LoadWritable()`, it is implementation defined whether | ||
| 59 | // writes made to the region returned by one call are visible in the regions | ||
| 60 | // returned by other calls. | ||
| 61 | // | ||
| 62 | // Given the above it is recommended to load the largest possible object | ||
| 63 | // that requires modification (e.g. a class) rather than individual fields | ||
| 64 | // from a class to avoid issues with overlapping writable regions. | ||
| 65 | // | ||
| 66 | // The lifetime of loaded memory is implementation defined. | ||
| 67 | template <typename T> | ||
| 68 | static T *LoadWritable(T *target_address, uptr num_elements = 1) { | ||
| 69 | // The target address space is the local address space so | ||
| 70 | // nothing needs to be copied. Just return the pointer. | ||
| 71 | return target_address; | ||
| 72 | } | ||
| 73 | }; | ||
| 74 | } // namespace __sanitizer | ||
| 75 | |||
| 76 | #endif | ||
lib/tsan/sanitizer_common/sanitizer_mac.cpp created+1228| ... | @@ -0,0 +1,1228 @@ | ||
| 1 | //===-- sanitizer_mac.cpp -------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between various sanitizers' runtime libraries and | ||
| 10 | // implements OSX-specific functions. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_platform.h" | ||
| 14 | #if SANITIZER_MAC | ||
| 15 | #include "sanitizer_mac.h" | ||
| 16 | #include "interception/interception.h" | ||
| 17 | |||
| 18 | // Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so | ||
| 19 | // the clients will most certainly use 64-bit ones as well. | ||
| 20 | #ifndef _DARWIN_USE_64_BIT_INODE | ||
| 21 | #define _DARWIN_USE_64_BIT_INODE 1 | ||
| 22 | #endif | ||
| 23 | #include <stdio.h> | ||
| 24 | |||
| 25 | #include "sanitizer_common.h" | ||
| 26 | #include "sanitizer_file.h" | ||
| 27 | #include "sanitizer_flags.h" | ||
| 28 | #include "sanitizer_internal_defs.h" | ||
| 29 | #include "sanitizer_libc.h" | ||
| 30 | #include "sanitizer_platform_limits_posix.h" | ||
| 31 | #include "sanitizer_procmaps.h" | ||
| 32 | #include "sanitizer_ptrauth.h" | ||
| 33 | |||
| 34 | #if !SANITIZER_IOS | ||
| 35 | #include <crt_externs.h> // for _NSGetEnviron | ||
| 36 | #else | ||
| 37 | extern char **environ; | ||
| 38 | #endif | ||
| 39 | |||
| 40 | #if defined(__has_include) && __has_include(<os/trace.h>) | ||
| 41 | #define SANITIZER_OS_TRACE 1 | ||
| 42 | #include <os/trace.h> | ||
| 43 | #else | ||
| 44 | #define SANITIZER_OS_TRACE 0 | ||
| 45 | #endif | ||
| 46 | |||
| 47 | #if !SANITIZER_IOS | ||
| 48 | #include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron | ||
| 49 | #else | ||
| 50 | extern "C" { | ||
| 51 | extern char ***_NSGetArgv(void); | ||
| 52 | } | ||
| 53 | #endif | ||
| 54 | |||
| 55 | #include <asl.h> | ||
| 56 | #include <dlfcn.h> // for dladdr() | ||
| 57 | #include <errno.h> | ||
| 58 | #include <fcntl.h> | ||
| 59 | #include <libkern/OSAtomic.h> | ||
| 60 | #include <mach-o/dyld.h> | ||
| 61 | #include <mach/mach.h> | ||
| 62 | #include <mach/mach_time.h> | ||
| 63 | #include <mach/vm_statistics.h> | ||
| 64 | #include <malloc/malloc.h> | ||
| 65 | #include <pthread.h> | ||
| 66 | #include <sched.h> | ||
| 67 | #include <signal.h> | ||
| 68 | #include <spawn.h> | ||
| 69 | #include <stdlib.h> | ||
| 70 | #include <sys/ioctl.h> | ||
| 71 | #include <sys/mman.h> | ||
| 72 | #include <sys/resource.h> | ||
| 73 | #include <sys/stat.h> | ||
| 74 | #include <sys/sysctl.h> | ||
| 75 | #include <sys/types.h> | ||
| 76 | #include <sys/wait.h> | ||
| 77 | #include <unistd.h> | ||
| 78 | #include <util.h> | ||
| 79 | |||
| 80 | // From <crt_externs.h>, but we don't have that file on iOS. | ||
| 81 | extern "C" { | ||
| 82 | extern char ***_NSGetArgv(void); | ||
| 83 | extern char ***_NSGetEnviron(void); | ||
| 84 | } | ||
| 85 | |||
| 86 | // From <mach/mach_vm.h>, but we don't have that file on iOS. | ||
| 87 | extern "C" { | ||
| 88 | extern kern_return_t mach_vm_region_recurse( | ||
| 89 | vm_map_t target_task, | ||
| 90 | mach_vm_address_t *address, | ||
| 91 | mach_vm_size_t *size, | ||
| 92 | natural_t *nesting_depth, | ||
| 93 | vm_region_recurse_info_t info, | ||
| 94 | mach_msg_type_number_t *infoCnt); | ||
| 95 | } | ||
| 96 | |||
| 97 | namespace __sanitizer { | ||
| 98 | |||
| 99 | #include "sanitizer_syscall_generic.inc" | ||
| 100 | |||
| 101 | // Direct syscalls, don't call libmalloc hooks (but not available on 10.6). | ||
| 102 | extern "C" void *__mmap(void *addr, size_t len, int prot, int flags, int fildes, | ||
| 103 | off_t off) SANITIZER_WEAK_ATTRIBUTE; | ||
| 104 | extern "C" int __munmap(void *, size_t) SANITIZER_WEAK_ATTRIBUTE; | ||
| 105 | |||
| 106 | // ---------------------- sanitizer_libc.h | ||
| 107 | |||
| 108 | // From <mach/vm_statistics.h>, but not on older OSs. | ||
| 109 | #ifndef VM_MEMORY_SANITIZER | ||
| 110 | #define VM_MEMORY_SANITIZER 99 | ||
| 111 | #endif | ||
| 112 | |||
| 113 | // XNU on Darwin provides a mmap flag that optimizes allocation/deallocation of | ||
| 114 | // giant memory regions (i.e. shadow memory regions). | ||
| 115 | #define kXnuFastMmapFd 0x4 | ||
| 116 | static size_t kXnuFastMmapThreshold = 2 << 30; // 2 GB | ||
| 117 | static bool use_xnu_fast_mmap = false; | ||
| 118 | |||
| 119 | uptr internal_mmap(void *addr, size_t length, int prot, int flags, | ||
| 120 | int fd, u64 offset) { | ||
| 121 | if (fd == -1) { | ||
| 122 | fd = VM_MAKE_TAG(VM_MEMORY_SANITIZER); | ||
| 123 | if (length >= kXnuFastMmapThreshold) { | ||
| 124 | if (use_xnu_fast_mmap) fd |= kXnuFastMmapFd; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | if (&__mmap) return (uptr)__mmap(addr, length, prot, flags, fd, offset); | ||
| 128 | return (uptr)mmap(addr, length, prot, flags, fd, offset); | ||
| 129 | } | ||
| 130 | |||
| 131 | uptr internal_munmap(void *addr, uptr length) { | ||
| 132 | if (&__munmap) return __munmap(addr, length); | ||
| 133 | return munmap(addr, length); | ||
| 134 | } | ||
| 135 | |||
| 136 | int internal_mprotect(void *addr, uptr length, int prot) { | ||
| 137 | return mprotect(addr, length, prot); | ||
| 138 | } | ||
| 139 | |||
| 140 | uptr internal_close(fd_t fd) { | ||
| 141 | return close(fd); | ||
| 142 | } | ||
| 143 | |||
| 144 | uptr internal_open(const char *filename, int flags) { | ||
| 145 | return open(filename, flags); | ||
| 146 | } | ||
| 147 | |||
| 148 | uptr internal_open(const char *filename, int flags, u32 mode) { | ||
| 149 | return open(filename, flags, mode); | ||
| 150 | } | ||
| 151 | |||
| 152 | uptr internal_read(fd_t fd, void *buf, uptr count) { | ||
| 153 | return read(fd, buf, count); | ||
| 154 | } | ||
| 155 | |||
| 156 | uptr internal_write(fd_t fd, const void *buf, uptr count) { | ||
| 157 | return write(fd, buf, count); | ||
| 158 | } | ||
| 159 | |||
| 160 | uptr internal_stat(const char *path, void *buf) { | ||
| 161 | return stat(path, (struct stat *)buf); | ||
| 162 | } | ||
| 163 | |||
| 164 | uptr internal_lstat(const char *path, void *buf) { | ||
| 165 | return lstat(path, (struct stat *)buf); | ||
| 166 | } | ||
| 167 | |||
| 168 | uptr internal_fstat(fd_t fd, void *buf) { | ||
| 169 | return fstat(fd, (struct stat *)buf); | ||
| 170 | } | ||
| 171 | |||
| 172 | uptr internal_filesize(fd_t fd) { | ||
| 173 | struct stat st; | ||
| 174 | if (internal_fstat(fd, &st)) | ||
| 175 | return -1; | ||
| 176 | return (uptr)st.st_size; | ||
| 177 | } | ||
| 178 | |||
| 179 | uptr internal_dup(int oldfd) { | ||
| 180 | return dup(oldfd); | ||
| 181 | } | ||
| 182 | |||
| 183 | uptr internal_dup2(int oldfd, int newfd) { | ||
| 184 | return dup2(oldfd, newfd); | ||
| 185 | } | ||
| 186 | |||
| 187 | uptr internal_readlink(const char *path, char *buf, uptr bufsize) { | ||
| 188 | return readlink(path, buf, bufsize); | ||
| 189 | } | ||
| 190 | |||
| 191 | uptr internal_unlink(const char *path) { | ||
| 192 | return unlink(path); | ||
| 193 | } | ||
| 194 | |||
| 195 | uptr internal_sched_yield() { | ||
| 196 | return sched_yield(); | ||
| 197 | } | ||
| 198 | |||
| 199 | void internal__exit(int exitcode) { | ||
| 200 | _exit(exitcode); | ||
| 201 | } | ||
| 202 | |||
| 203 | unsigned int internal_sleep(unsigned int seconds) { | ||
| 204 | return sleep(seconds); | ||
| 205 | } | ||
| 206 | |||
| 207 | uptr internal_getpid() { | ||
| 208 | return getpid(); | ||
| 209 | } | ||
| 210 | |||
| 211 | int internal_dlinfo(void *handle, int request, void *p) { | ||
| 212 | UNIMPLEMENTED(); | ||
| 213 | } | ||
| 214 | |||
| 215 | int internal_sigaction(int signum, const void *act, void *oldact) { | ||
| 216 | return sigaction(signum, | ||
| 217 | (const struct sigaction *)act, (struct sigaction *)oldact); | ||
| 218 | } | ||
| 219 | |||
| 220 | void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); } | ||
| 221 | |||
| 222 | uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, | ||
| 223 | __sanitizer_sigset_t *oldset) { | ||
| 224 | // Don't use sigprocmask here, because it affects all threads. | ||
| 225 | return pthread_sigmask(how, set, oldset); | ||
| 226 | } | ||
| 227 | |||
| 228 | // Doesn't call pthread_atfork() handlers (but not available on 10.6). | ||
| 229 | extern "C" pid_t __fork(void) SANITIZER_WEAK_ATTRIBUTE; | ||
| 230 | |||
| 231 | int internal_fork() { | ||
| 232 | if (&__fork) | ||
| 233 | return __fork(); | ||
| 234 | return fork(); | ||
| 235 | } | ||
| 236 | |||
| 237 | int internal_sysctl(const int *name, unsigned int namelen, void *oldp, | ||
| 238 | uptr *oldlenp, const void *newp, uptr newlen) { | ||
| 239 | return sysctl(const_cast<int *>(name), namelen, oldp, (size_t *)oldlenp, | ||
| 240 | const_cast<void *>(newp), (size_t)newlen); | ||
| 241 | } | ||
| 242 | |||
| 243 | int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, | ||
| 244 | const void *newp, uptr newlen) { | ||
| 245 | return sysctlbyname(sname, oldp, (size_t *)oldlenp, const_cast<void *>(newp), | ||
| 246 | (size_t)newlen); | ||
| 247 | } | ||
| 248 | |||
| 249 | static fd_t internal_spawn_impl(const char *argv[], const char *envp[], | ||
| 250 | pid_t *pid) { | ||
| 251 | fd_t master_fd = kInvalidFd; | ||
| 252 | fd_t slave_fd = kInvalidFd; | ||
| 253 | |||
| 254 | auto fd_closer = at_scope_exit([&] { | ||
| 255 | internal_close(master_fd); | ||
| 256 | internal_close(slave_fd); | ||
| 257 | }); | ||
| 258 | |||
| 259 | // We need a new pseudoterminal to avoid buffering problems. The 'atos' tool | ||
| 260 | // in particular detects when it's talking to a pipe and forgets to flush the | ||
| 261 | // output stream after sending a response. | ||
| 262 | master_fd = posix_openpt(O_RDWR); | ||
| 263 | if (master_fd == kInvalidFd) return kInvalidFd; | ||
| 264 | |||
| 265 | int res = grantpt(master_fd) || unlockpt(master_fd); | ||
| 266 | if (res != 0) return kInvalidFd; | ||
| 267 | |||
| 268 | // Use TIOCPTYGNAME instead of ptsname() to avoid threading problems. | ||
| 269 | char slave_pty_name[128]; | ||
| 270 | res = ioctl(master_fd, TIOCPTYGNAME, slave_pty_name); | ||
| 271 | if (res == -1) return kInvalidFd; | ||
| 272 | |||
| 273 | slave_fd = internal_open(slave_pty_name, O_RDWR); | ||
| 274 | if (slave_fd == kInvalidFd) return kInvalidFd; | ||
| 275 | |||
| 276 | // File descriptor actions | ||
| 277 | posix_spawn_file_actions_t acts; | ||
| 278 | res = posix_spawn_file_actions_init(&acts); | ||
| 279 | if (res != 0) return kInvalidFd; | ||
| 280 | |||
| 281 | auto acts_cleanup = at_scope_exit([&] { | ||
| 282 | posix_spawn_file_actions_destroy(&acts); | ||
| 283 | }); | ||
| 284 | |||
| 285 | res = posix_spawn_file_actions_adddup2(&acts, slave_fd, STDIN_FILENO) || | ||
| 286 | posix_spawn_file_actions_adddup2(&acts, slave_fd, STDOUT_FILENO) || | ||
| 287 | posix_spawn_file_actions_addclose(&acts, slave_fd); | ||
| 288 | if (res != 0) return kInvalidFd; | ||
| 289 | |||
| 290 | // Spawn attributes | ||
| 291 | posix_spawnattr_t attrs; | ||
| 292 | res = posix_spawnattr_init(&attrs); | ||
| 293 | if (res != 0) return kInvalidFd; | ||
| 294 | |||
| 295 | auto attrs_cleanup = at_scope_exit([&] { | ||
| 296 | posix_spawnattr_destroy(&attrs); | ||
| 297 | }); | ||
| 298 | |||
| 299 | // In the spawned process, close all file descriptors that are not explicitly | ||
| 300 | // described by the file actions object. This is Darwin-specific extension. | ||
| 301 | res = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_CLOEXEC_DEFAULT); | ||
| 302 | if (res != 0) return kInvalidFd; | ||
| 303 | |||
| 304 | // posix_spawn | ||
| 305 | char **argv_casted = const_cast<char **>(argv); | ||
| 306 | char **envp_casted = const_cast<char **>(envp); | ||
| 307 | res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted); | ||
| 308 | if (res != 0) return kInvalidFd; | ||
| 309 | |||
| 310 | // Disable echo in the new terminal, disable CR. | ||
| 311 | struct termios termflags; | ||
| 312 | tcgetattr(master_fd, &termflags); | ||
| 313 | termflags.c_oflag &= ~ONLCR; | ||
| 314 | termflags.c_lflag &= ~ECHO; | ||
| 315 | tcsetattr(master_fd, TCSANOW, &termflags); | ||
| 316 | |||
| 317 | // On success, do not close master_fd on scope exit. | ||
| 318 | fd_t fd = master_fd; | ||
| 319 | master_fd = kInvalidFd; | ||
| 320 | |||
| 321 | return fd; | ||
| 322 | } | ||
| 323 | |||
| 324 | fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid) { | ||
| 325 | // The client program may close its stdin and/or stdout and/or stderr thus | ||
| 326 | // allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this | ||
| 327 | // case the communication is broken if either the parent or the child tries to | ||
| 328 | // close or duplicate these descriptors. We temporarily reserve these | ||
| 329 | // descriptors here to prevent this. | ||
| 330 | fd_t low_fds[3]; | ||
| 331 | size_t count = 0; | ||
| 332 | |||
| 333 | for (; count < 3; count++) { | ||
| 334 | low_fds[count] = posix_openpt(O_RDWR); | ||
| 335 | if (low_fds[count] >= STDERR_FILENO) | ||
| 336 | break; | ||
| 337 | } | ||
| 338 | |||
| 339 | fd_t fd = internal_spawn_impl(argv, envp, pid); | ||
| 340 | |||
| 341 | for (; count > 0; count--) { | ||
| 342 | internal_close(low_fds[count]); | ||
| 343 | } | ||
| 344 | |||
| 345 | return fd; | ||
| 346 | } | ||
| 347 | |||
| 348 | uptr internal_rename(const char *oldpath, const char *newpath) { | ||
| 349 | return rename(oldpath, newpath); | ||
| 350 | } | ||
| 351 | |||
| 352 | uptr internal_ftruncate(fd_t fd, uptr size) { | ||
| 353 | return ftruncate(fd, size); | ||
| 354 | } | ||
| 355 | |||
| 356 | uptr internal_execve(const char *filename, char *const argv[], | ||
| 357 | char *const envp[]) { | ||
| 358 | return execve(filename, argv, envp); | ||
| 359 | } | ||
| 360 | |||
| 361 | uptr internal_waitpid(int pid, int *status, int options) { | ||
| 362 | return waitpid(pid, status, options); | ||
| 363 | } | ||
| 364 | |||
| 365 | // ----------------- sanitizer_common.h | ||
| 366 | bool FileExists(const char *filename) { | ||
| 367 | if (ShouldMockFailureToOpen(filename)) | ||
| 368 | return false; | ||
| 369 | struct stat st; | ||
| 370 | if (stat(filename, &st)) | ||
| 371 | return false; | ||
| 372 | // Sanity check: filename is a regular file. | ||
| 373 | return S_ISREG(st.st_mode); | ||
| 374 | } | ||
| 375 | |||
| 376 | tid_t GetTid() { | ||
| 377 | tid_t tid; | ||
| 378 | pthread_threadid_np(nullptr, &tid); | ||
| 379 | return tid; | ||
| 380 | } | ||
| 381 | |||
| 382 | void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, | ||
| 383 | uptr *stack_bottom) { | ||
| 384 | CHECK(stack_top); | ||
| 385 | CHECK(stack_bottom); | ||
| 386 | uptr stacksize = pthread_get_stacksize_np(pthread_self()); | ||
| 387 | // pthread_get_stacksize_np() returns an incorrect stack size for the main | ||
| 388 | // thread on Mavericks. See | ||
| 389 | // https://github.com/google/sanitizers/issues/261 | ||
| 390 | if ((GetMacosAlignedVersion() >= MacosVersion(10, 9)) && at_initialization && | ||
| 391 | stacksize == (1 << 19)) { | ||
| 392 | struct rlimit rl; | ||
| 393 | CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0); | ||
| 394 | // Most often rl.rlim_cur will be the desired 8M. | ||
| 395 | if (rl.rlim_cur < kMaxThreadStackSize) { | ||
| 396 | stacksize = rl.rlim_cur; | ||
| 397 | } else { | ||
| 398 | stacksize = kMaxThreadStackSize; | ||
| 399 | } | ||
| 400 | } | ||
| 401 | void *stackaddr = pthread_get_stackaddr_np(pthread_self()); | ||
| 402 | *stack_top = (uptr)stackaddr; | ||
| 403 | *stack_bottom = *stack_top - stacksize; | ||
| 404 | } | ||
| 405 | |||
| 406 | char **GetEnviron() { | ||
| 407 | #if !SANITIZER_IOS | ||
| 408 | char ***env_ptr = _NSGetEnviron(); | ||
| 409 | if (!env_ptr) { | ||
| 410 | Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is " | ||
| 411 | "called after libSystem_initializer().\n"); | ||
| 412 | CHECK(env_ptr); | ||
| 413 | } | ||
| 414 | char **environ = *env_ptr; | ||
| 415 | #endif | ||
| 416 | CHECK(environ); | ||
| 417 | return environ; | ||
| 418 | } | ||
| 419 | |||
| 420 | const char *GetEnv(const char *name) { | ||
| 421 | char **env = GetEnviron(); | ||
| 422 | uptr name_len = internal_strlen(name); | ||
| 423 | while (*env != 0) { | ||
| 424 | uptr len = internal_strlen(*env); | ||
| 425 | if (len > name_len) { | ||
| 426 | const char *p = *env; | ||
| 427 | if (!internal_memcmp(p, name, name_len) && | ||
| 428 | p[name_len] == '=') { // Match. | ||
| 429 | return *env + name_len + 1; // String starting after =. | ||
| 430 | } | ||
| 431 | } | ||
| 432 | env++; | ||
| 433 | } | ||
| 434 | return 0; | ||
| 435 | } | ||
| 436 | |||
| 437 | uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { | ||
| 438 | CHECK_LE(kMaxPathLength, buf_len); | ||
| 439 | |||
| 440 | // On OS X the executable path is saved to the stack by dyld. Reading it | ||
| 441 | // from there is much faster than calling dladdr, especially for large | ||
| 442 | // binaries with symbols. | ||
| 443 | InternalScopedString exe_path(kMaxPathLength); | ||
| 444 | uint32_t size = exe_path.size(); | ||
| 445 | if (_NSGetExecutablePath(exe_path.data(), &size) == 0 && | ||
| 446 | realpath(exe_path.data(), buf) != 0) { | ||
| 447 | return internal_strlen(buf); | ||
| 448 | } | ||
| 449 | return 0; | ||
| 450 | } | ||
| 451 | |||
| 452 | uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { | ||
| 453 | return ReadBinaryName(buf, buf_len); | ||
| 454 | } | ||
| 455 | |||
| 456 | void ReExec() { | ||
| 457 | UNIMPLEMENTED(); | ||
| 458 | } | ||
| 459 | |||
| 460 | void CheckASLR() { | ||
| 461 | // Do nothing | ||
| 462 | } | ||
| 463 | |||
| 464 | void CheckMPROTECT() { | ||
| 465 | // Do nothing | ||
| 466 | } | ||
| 467 | |||
| 468 | uptr GetPageSize() { | ||
| 469 | return sysconf(_SC_PAGESIZE); | ||
| 470 | } | ||
| 471 | |||
| 472 | extern "C" unsigned malloc_num_zones; | ||
| 473 | extern "C" malloc_zone_t **malloc_zones; | ||
| 474 | malloc_zone_t sanitizer_zone; | ||
| 475 | |||
| 476 | // We need to make sure that sanitizer_zone is registered as malloc_zones[0]. If | ||
| 477 | // libmalloc tries to set up a different zone as malloc_zones[0], it will call | ||
| 478 | // mprotect(malloc_zones, ..., PROT_READ). This interceptor will catch that and | ||
| 479 | // make sure we are still the first (default) zone. | ||
| 480 | void MprotectMallocZones(void *addr, int prot) { | ||
| 481 | if (addr == malloc_zones && prot == PROT_READ) { | ||
| 482 | if (malloc_num_zones > 1 && malloc_zones[0] != &sanitizer_zone) { | ||
| 483 | for (unsigned i = 1; i < malloc_num_zones; i++) { | ||
| 484 | if (malloc_zones[i] == &sanitizer_zone) { | ||
| 485 | // Swap malloc_zones[0] and malloc_zones[i]. | ||
| 486 | malloc_zones[i] = malloc_zones[0]; | ||
| 487 | malloc_zones[0] = &sanitizer_zone; | ||
| 488 | break; | ||
| 489 | } | ||
| 490 | } | ||
| 491 | } | ||
| 492 | } | ||
| 493 | } | ||
| 494 | |||
| 495 | BlockingMutex::BlockingMutex() { | ||
| 496 | internal_memset(this, 0, sizeof(*this)); | ||
| 497 | } | ||
| 498 | |||
| 499 | void BlockingMutex::Lock() { | ||
| 500 | CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_)); | ||
| 501 | CHECK_EQ(OS_SPINLOCK_INIT, 0); | ||
| 502 | CHECK_EQ(owner_, 0); | ||
| 503 | OSSpinLockLock((OSSpinLock*)&opaque_storage_); | ||
| 504 | } | ||
| 505 | |||
| 506 | void BlockingMutex::Unlock() { | ||
| 507 | OSSpinLockUnlock((OSSpinLock*)&opaque_storage_); | ||
| 508 | } | ||
| 509 | |||
| 510 | void BlockingMutex::CheckLocked() { | ||
| 511 | CHECK_NE(*(OSSpinLock*)&opaque_storage_, 0); | ||
| 512 | } | ||
| 513 | |||
| 514 | u64 NanoTime() { | ||
| 515 | timeval tv; | ||
| 516 | internal_memset(&tv, 0, sizeof(tv)); | ||
| 517 | gettimeofday(&tv, 0); | ||
| 518 | return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000; | ||
| 519 | } | ||
| 520 | |||
| 521 | // This needs to be called during initialization to avoid being racy. | ||
| 522 | u64 MonotonicNanoTime() { | ||
| 523 | static mach_timebase_info_data_t timebase_info; | ||
| 524 | if (timebase_info.denom == 0) mach_timebase_info(&timebase_info); | ||
| 525 | return (mach_absolute_time() * timebase_info.numer) / timebase_info.denom; | ||
| 526 | } | ||
| 527 | |||
| 528 | uptr GetTlsSize() { | ||
| 529 | return 0; | ||
| 530 | } | ||
| 531 | |||
| 532 | void InitTlsSize() { | ||
| 533 | } | ||
| 534 | |||
| 535 | uptr TlsBaseAddr() { | ||
| 536 | uptr segbase = 0; | ||
| 537 | #if defined(__x86_64__) | ||
| 538 | asm("movq %%gs:0,%0" : "=r"(segbase)); | ||
| 539 | #elif defined(__i386__) | ||
| 540 | asm("movl %%gs:0,%0" : "=r"(segbase)); | ||
| 541 | #endif | ||
| 542 | return segbase; | ||
| 543 | } | ||
| 544 | |||
| 545 | // The size of the tls on darwin does not appear to be well documented, | ||
| 546 | // however the vm memory map suggests that it is 1024 uptrs in size, | ||
| 547 | // with a size of 0x2000 bytes on x86_64 and 0x1000 bytes on i386. | ||
| 548 | uptr TlsSize() { | ||
| 549 | #if defined(__x86_64__) || defined(__i386__) | ||
| 550 | return 1024 * sizeof(uptr); | ||
| 551 | #else | ||
| 552 | return 0; | ||
| 553 | #endif | ||
| 554 | } | ||
| 555 | |||
| 556 | void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, | ||
| 557 | uptr *tls_addr, uptr *tls_size) { | ||
| 558 | #if !SANITIZER_GO | ||
| 559 | uptr stack_top, stack_bottom; | ||
| 560 | GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); | ||
| 561 | *stk_addr = stack_bottom; | ||
| 562 | *stk_size = stack_top - stack_bottom; | ||
| 563 | *tls_addr = TlsBaseAddr(); | ||
| 564 | *tls_size = TlsSize(); | ||
| 565 | #else | ||
| 566 | *stk_addr = 0; | ||
| 567 | *stk_size = 0; | ||
| 568 | *tls_addr = 0; | ||
| 569 | *tls_size = 0; | ||
| 570 | #endif | ||
| 571 | } | ||
| 572 | |||
| 573 | void ListOfModules::init() { | ||
| 574 | clearOrInit(); | ||
| 575 | MemoryMappingLayout memory_mapping(false); | ||
| 576 | memory_mapping.DumpListOfModules(&modules_); | ||
| 577 | } | ||
| 578 | |||
| 579 | void ListOfModules::fallbackInit() { clear(); } | ||
| 580 | |||
| 581 | static HandleSignalMode GetHandleSignalModeImpl(int signum) { | ||
| 582 | switch (signum) { | ||
| 583 | case SIGABRT: | ||
| 584 | return common_flags()->handle_abort; | ||
| 585 | case SIGILL: | ||
| 586 | return common_flags()->handle_sigill; | ||
| 587 | case SIGTRAP: | ||
| 588 | return common_flags()->handle_sigtrap; | ||
| 589 | case SIGFPE: | ||
| 590 | return common_flags()->handle_sigfpe; | ||
| 591 | case SIGSEGV: | ||
| 592 | return common_flags()->handle_segv; | ||
| 593 | case SIGBUS: | ||
| 594 | return common_flags()->handle_sigbus; | ||
| 595 | } | ||
| 596 | return kHandleSignalNo; | ||
| 597 | } | ||
| 598 | |||
| 599 | HandleSignalMode GetHandleSignalMode(int signum) { | ||
| 600 | // Handling fatal signals on watchOS and tvOS devices is disallowed. | ||
| 601 | if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM)) | ||
| 602 | return kHandleSignalNo; | ||
| 603 | HandleSignalMode result = GetHandleSignalModeImpl(signum); | ||
| 604 | if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler) | ||
| 605 | return kHandleSignalExclusive; | ||
| 606 | return result; | ||
| 607 | } | ||
| 608 | |||
| 609 | // This corresponds to Triple::getMacOSXVersion() in the Clang driver. | ||
| 610 | static MacosVersion GetMacosAlignedVersionInternal() { | ||
| 611 | u16 kernel_major = GetDarwinKernelVersion().major; | ||
| 612 | // Darwin 0-3 -> unsupported | ||
| 613 | // Darwin 4-19 -> macOS 10.x | ||
| 614 | // Darwin 20+ -> macOS 11+ | ||
| 615 | CHECK_GE(kernel_major, 4); | ||
| 616 | u16 major, minor; | ||
| 617 | if (kernel_major < 20) { | ||
| 618 | major = 10; | ||
| 619 | minor = kernel_major - 4; | ||
| 620 | } else { | ||
| 621 | major = 11 + kernel_major - 20; | ||
| 622 | minor = 0; | ||
| 623 | } | ||
| 624 | return MacosVersion(major, minor); | ||
| 625 | } | ||
| 626 | |||
| 627 | static_assert(sizeof(MacosVersion) == sizeof(atomic_uint32_t::Type), | ||
| 628 | "MacosVersion cache size"); | ||
| 629 | static atomic_uint32_t cached_macos_version; | ||
| 630 | |||
| 631 | MacosVersion GetMacosAlignedVersion() { | ||
| 632 | atomic_uint32_t::Type result = | ||
| 633 | atomic_load(&cached_macos_version, memory_order_acquire); | ||
| 634 | if (!result) { | ||
| 635 | MacosVersion version = GetMacosAlignedVersionInternal(); | ||
| 636 | result = *reinterpret_cast<atomic_uint32_t::Type *>(&version); | ||
| 637 | atomic_store(&cached_macos_version, result, memory_order_release); | ||
| 638 | } | ||
| 639 | return *reinterpret_cast<MacosVersion *>(&result); | ||
| 640 | } | ||
| 641 | |||
| 642 | void ParseVersion(const char *vers, u16 *major, u16 *minor) { | ||
| 643 | // Format: <major>.<minor>.<patch>\0 | ||
| 644 | CHECK_GE(internal_strlen(vers), 5); | ||
| 645 | const char *p = vers; | ||
| 646 | *major = internal_simple_strtoll(p, &p, /*base=*/10); | ||
| 647 | CHECK_EQ(*p, '.'); | ||
| 648 | p += 1; | ||
| 649 | *minor = internal_simple_strtoll(p, &p, /*base=*/10); | ||
| 650 | } | ||
| 651 | |||
| 652 | DarwinKernelVersion GetDarwinKernelVersion() { | ||
| 653 | char buf[100]; | ||
| 654 | size_t len = sizeof(buf); | ||
| 655 | int res = internal_sysctlbyname("kern.osrelease", buf, &len, nullptr, 0); | ||
| 656 | CHECK_EQ(res, 0); | ||
| 657 | |||
| 658 | u16 major, minor; | ||
| 659 | ParseVersion(buf, &major, &minor); | ||
| 660 | |||
| 661 | return DarwinKernelVersion(major, minor); | ||
| 662 | } | ||
| 663 | |||
| 664 | uptr GetRSS() { | ||
| 665 | struct task_basic_info info; | ||
| 666 | unsigned count = TASK_BASIC_INFO_COUNT; | ||
| 667 | kern_return_t result = | ||
| 668 | task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count); | ||
| 669 | if (UNLIKELY(result != KERN_SUCCESS)) { | ||
| 670 | Report("Cannot get task info. Error: %d\n", result); | ||
| 671 | Die(); | ||
| 672 | } | ||
| 673 | return info.resident_size; | ||
| 674 | } | ||
| 675 | |||
| 676 | void *internal_start_thread(void *(*func)(void *arg), void *arg) { | ||
| 677 | // Start the thread with signals blocked, otherwise it can steal user signals. | ||
| 678 | __sanitizer_sigset_t set, old; | ||
| 679 | internal_sigfillset(&set); | ||
| 680 | internal_sigprocmask(SIG_SETMASK, &set, &old); | ||
| 681 | pthread_t th; | ||
| 682 | pthread_create(&th, 0, func, arg); | ||
| 683 | internal_sigprocmask(SIG_SETMASK, &old, 0); | ||
| 684 | return th; | ||
| 685 | } | ||
| 686 | |||
| 687 | void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); } | ||
| 688 | |||
| 689 | #if !SANITIZER_GO | ||
| 690 | static BlockingMutex syslog_lock(LINKER_INITIALIZED); | ||
| 691 | #endif | ||
| 692 | |||
| 693 | void WriteOneLineToSyslog(const char *s) { | ||
| 694 | #if !SANITIZER_GO | ||
| 695 | syslog_lock.CheckLocked(); | ||
| 696 | asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s); | ||
| 697 | #endif | ||
| 698 | } | ||
| 699 | |||
| 700 | void LogMessageOnPrintf(const char *str) { | ||
| 701 | // Log all printf output to CrashLog. | ||
| 702 | if (common_flags()->abort_on_error) | ||
| 703 | CRAppendCrashLogMessage(str); | ||
| 704 | } | ||
| 705 | |||
| 706 | void LogFullErrorReport(const char *buffer) { | ||
| 707 | #if !SANITIZER_GO | ||
| 708 | // Log with os_trace. This will make it into the crash log. | ||
| 709 | #if SANITIZER_OS_TRACE | ||
| 710 | if (GetMacosAlignedVersion() >= MacosVersion(10, 10)) { | ||
| 711 | // os_trace requires the message (format parameter) to be a string literal. | ||
| 712 | if (internal_strncmp(SanitizerToolName, "AddressSanitizer", | ||
| 713 | sizeof("AddressSanitizer") - 1) == 0) | ||
| 714 | os_trace("Address Sanitizer reported a failure."); | ||
| 715 | else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer", | ||
| 716 | sizeof("UndefinedBehaviorSanitizer") - 1) == 0) | ||
| 717 | os_trace("Undefined Behavior Sanitizer reported a failure."); | ||
| 718 | else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer", | ||
| 719 | sizeof("ThreadSanitizer") - 1) == 0) | ||
| 720 | os_trace("Thread Sanitizer reported a failure."); | ||
| 721 | else | ||
| 722 | os_trace("Sanitizer tool reported a failure."); | ||
| 723 | |||
| 724 | if (common_flags()->log_to_syslog) | ||
| 725 | os_trace("Consult syslog for more information."); | ||
| 726 | } | ||
| 727 | #endif | ||
| 728 | |||
| 729 | // Log to syslog. | ||
| 730 | // The logging on OS X may call pthread_create so we need the threading | ||
| 731 | // environment to be fully initialized. Also, this should never be called when | ||
| 732 | // holding the thread registry lock since that may result in a deadlock. If | ||
| 733 | // the reporting thread holds the thread registry mutex, and asl_log waits | ||
| 734 | // for GCD to dispatch a new thread, the process will deadlock, because the | ||
| 735 | // pthread_create wrapper needs to acquire the lock as well. | ||
| 736 | BlockingMutexLock l(&syslog_lock); | ||
| 737 | if (common_flags()->log_to_syslog) | ||
| 738 | WriteToSyslog(buffer); | ||
| 739 | |||
| 740 | // The report is added to CrashLog as part of logging all of Printf output. | ||
| 741 | #endif | ||
| 742 | } | ||
| 743 | |||
| 744 | SignalContext::WriteFlag SignalContext::GetWriteFlag() const { | ||
| 745 | #if defined(__x86_64__) || defined(__i386__) | ||
| 746 | ucontext_t *ucontext = static_cast<ucontext_t*>(context); | ||
| 747 | return ucontext->uc_mcontext->__es.__err & 2 /*T_PF_WRITE*/ ? WRITE : READ; | ||
| 748 | #else | ||
| 749 | return UNKNOWN; | ||
| 750 | #endif | ||
| 751 | } | ||
| 752 | |||
| 753 | bool SignalContext::IsTrueFaultingAddress() const { | ||
| 754 | auto si = static_cast<const siginfo_t *>(siginfo); | ||
| 755 | // "Real" SIGSEGV codes (e.g., SEGV_MAPERR, SEGV_MAPERR) are non-zero. | ||
| 756 | return si->si_signo == SIGSEGV && si->si_code != 0; | ||
| 757 | } | ||
| 758 | |||
| 759 | #if defined(__aarch64__) && defined(arm_thread_state64_get_sp) | ||
| 760 | #define AARCH64_GET_REG(r) \ | ||
| 761 | (uptr)ptrauth_strip( \ | ||
| 762 | (void *)arm_thread_state64_get_##r(ucontext->uc_mcontext->__ss), 0) | ||
| 763 | #else | ||
| 764 | #define AARCH64_GET_REG(r) ucontext->uc_mcontext->__ss.__##r | ||
| 765 | #endif | ||
| 766 | |||
| 767 | static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { | ||
| 768 | ucontext_t *ucontext = (ucontext_t*)context; | ||
| 769 | # if defined(__aarch64__) | ||
| 770 | *pc = AARCH64_GET_REG(pc); | ||
| 771 | # if defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0 | ||
| 772 | *bp = AARCH64_GET_REG(fp); | ||
| 773 | # else | ||
| 774 | *bp = AARCH64_GET_REG(lr); | ||
| 775 | # endif | ||
| 776 | *sp = AARCH64_GET_REG(sp); | ||
| 777 | # elif defined(__x86_64__) | ||
| 778 | *pc = ucontext->uc_mcontext->__ss.__rip; | ||
| 779 | *bp = ucontext->uc_mcontext->__ss.__rbp; | ||
| 780 | *sp = ucontext->uc_mcontext->__ss.__rsp; | ||
| 781 | # elif defined(__arm__) | ||
| 782 | *pc = ucontext->uc_mcontext->__ss.__pc; | ||
| 783 | *bp = ucontext->uc_mcontext->__ss.__r[7]; | ||
| 784 | *sp = ucontext->uc_mcontext->__ss.__sp; | ||
| 785 | # elif defined(__i386__) | ||
| 786 | *pc = ucontext->uc_mcontext->__ss.__eip; | ||
| 787 | *bp = ucontext->uc_mcontext->__ss.__ebp; | ||
| 788 | *sp = ucontext->uc_mcontext->__ss.__esp; | ||
| 789 | # else | ||
| 790 | # error "Unknown architecture" | ||
| 791 | # endif | ||
| 792 | } | ||
| 793 | |||
| 794 | void SignalContext::InitPcSpBp() { | ||
| 795 | addr = (uptr)ptrauth_strip((void *)addr, 0); | ||
| 796 | GetPcSpBp(context, &pc, &sp, &bp); | ||
| 797 | } | ||
| 798 | |||
| 799 | void InitializePlatformEarly() { | ||
| 800 | // Only use xnu_fast_mmap when on x86_64 and the kernel supports it. | ||
| 801 | use_xnu_fast_mmap = | ||
| 802 | #if defined(__x86_64__) | ||
| 803 | GetDarwinKernelVersion() >= DarwinKernelVersion(17, 5); | ||
| 804 | #else | ||
| 805 | false; | ||
| 806 | #endif | ||
| 807 | } | ||
| 808 | |||
| 809 | #if !SANITIZER_GO | ||
| 810 | static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES"; | ||
| 811 | LowLevelAllocator allocator_for_env; | ||
| 812 | |||
| 813 | // Change the value of the env var |name|, leaking the original value. | ||
| 814 | // If |name_value| is NULL, the variable is deleted from the environment, | ||
| 815 | // otherwise the corresponding "NAME=value" string is replaced with | ||
| 816 | // |name_value|. | ||
| 817 | void LeakyResetEnv(const char *name, const char *name_value) { | ||
| 818 | char **env = GetEnviron(); | ||
| 819 | uptr name_len = internal_strlen(name); | ||
| 820 | while (*env != 0) { | ||
| 821 | uptr len = internal_strlen(*env); | ||
| 822 | if (len > name_len) { | ||
| 823 | const char *p = *env; | ||
| 824 | if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') { | ||
| 825 | // Match. | ||
| 826 | if (name_value) { | ||
| 827 | // Replace the old value with the new one. | ||
| 828 | *env = const_cast<char*>(name_value); | ||
| 829 | } else { | ||
| 830 | // Shift the subsequent pointers back. | ||
| 831 | char **del = env; | ||
| 832 | do { | ||
| 833 | del[0] = del[1]; | ||
| 834 | } while (*del++); | ||
| 835 | } | ||
| 836 | } | ||
| 837 | } | ||
| 838 | env++; | ||
| 839 | } | ||
| 840 | } | ||
| 841 | |||
| 842 | SANITIZER_WEAK_CXX_DEFAULT_IMPL | ||
| 843 | bool ReexecDisabled() { | ||
| 844 | return false; | ||
| 845 | } | ||
| 846 | |||
| 847 | extern "C" SANITIZER_WEAK_ATTRIBUTE double dyldVersionNumber; | ||
| 848 | static const double kMinDyldVersionWithAutoInterposition = 360.0; | ||
| 849 | |||
| 850 | bool DyldNeedsEnvVariable() { | ||
| 851 | // Although sanitizer support was added to LLVM on OS X 10.7+, GCC users | ||
| 852 | // still may want use them on older systems. On older Darwin platforms, dyld | ||
| 853 | // doesn't export dyldVersionNumber symbol and we simply return true. | ||
| 854 | if (!&dyldVersionNumber) return true; | ||
| 855 | // If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if | ||
| 856 | // DYLD_INSERT_LIBRARIES is not set. However, checking OS version via | ||
| 857 | // GetMacosAlignedVersion() doesn't work for the simulator. Let's instead | ||
| 858 | // check `dyldVersionNumber`, which is exported by dyld, against a known | ||
| 859 | // version number from the first OS release where this appeared. | ||
| 860 | return dyldVersionNumber < kMinDyldVersionWithAutoInterposition; | ||
| 861 | } | ||
| 862 | |||
| 863 | void MaybeReexec() { | ||
| 864 | // FIXME: This should really live in some "InitializePlatform" method. | ||
| 865 | MonotonicNanoTime(); | ||
| 866 | |||
| 867 | if (ReexecDisabled()) return; | ||
| 868 | |||
| 869 | // Make sure the dynamic runtime library is preloaded so that the | ||
| 870 | // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec | ||
| 871 | // ourselves. | ||
| 872 | Dl_info info; | ||
| 873 | RAW_CHECK(dladdr((void*)((uptr)&__sanitizer_report_error_summary), &info)); | ||
| 874 | char *dyld_insert_libraries = | ||
| 875 | const_cast<char*>(GetEnv(kDyldInsertLibraries)); | ||
| 876 | uptr old_env_len = dyld_insert_libraries ? | ||
| 877 | internal_strlen(dyld_insert_libraries) : 0; | ||
| 878 | uptr fname_len = internal_strlen(info.dli_fname); | ||
| 879 | const char *dylib_name = StripModuleName(info.dli_fname); | ||
| 880 | uptr dylib_name_len = internal_strlen(dylib_name); | ||
| 881 | |||
| 882 | bool lib_is_in_env = dyld_insert_libraries && | ||
| 883 | internal_strstr(dyld_insert_libraries, dylib_name); | ||
| 884 | if (DyldNeedsEnvVariable() && !lib_is_in_env) { | ||
| 885 | // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime | ||
| 886 | // library. | ||
| 887 | InternalScopedString program_name(1024); | ||
| 888 | uint32_t buf_size = program_name.size(); | ||
| 889 | _NSGetExecutablePath(program_name.data(), &buf_size); | ||
| 890 | char *new_env = const_cast<char*>(info.dli_fname); | ||
| 891 | if (dyld_insert_libraries) { | ||
| 892 | // Append the runtime dylib name to the existing value of | ||
| 893 | // DYLD_INSERT_LIBRARIES. | ||
| 894 | new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2); | ||
| 895 | internal_strncpy(new_env, dyld_insert_libraries, old_env_len); | ||
| 896 | new_env[old_env_len] = ':'; | ||
| 897 | // Copy fname_len and add a trailing zero. | ||
| 898 | internal_strncpy(new_env + old_env_len + 1, info.dli_fname, | ||
| 899 | fname_len + 1); | ||
| 900 | // Ok to use setenv() since the wrappers don't depend on the value of | ||
| 901 | // asan_inited. | ||
| 902 | setenv(kDyldInsertLibraries, new_env, /*overwrite*/1); | ||
| 903 | } else { | ||
| 904 | // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name. | ||
| 905 | setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0); | ||
| 906 | } | ||
| 907 | VReport(1, "exec()-ing the program with\n"); | ||
| 908 | VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env); | ||
| 909 | VReport(1, "to enable wrappers.\n"); | ||
| 910 | execv(program_name.data(), *_NSGetArgv()); | ||
| 911 | |||
| 912 | // We get here only if execv() failed. | ||
| 913 | Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, " | ||
| 914 | "which is required for the sanitizer to work. We tried to set the " | ||
| 915 | "environment variable and re-execute itself, but execv() failed, " | ||
| 916 | "possibly because of sandbox restrictions. Make sure to launch the " | ||
| 917 | "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env); | ||
| 918 | RAW_CHECK("execv failed" && 0); | ||
| 919 | } | ||
| 920 | |||
| 921 | // Verify that interceptors really work. We'll use dlsym to locate | ||
| 922 | // "pthread_create", if interceptors are working, it should really point to | ||
| 923 | // "wrap_pthread_create" within our own dylib. | ||
| 924 | Dl_info info_pthread_create; | ||
| 925 | void *dlopen_addr = dlsym(RTLD_DEFAULT, "pthread_create"); | ||
| 926 | RAW_CHECK(dladdr(dlopen_addr, &info_pthread_create)); | ||
| 927 | if (internal_strcmp(info.dli_fname, info_pthread_create.dli_fname) != 0) { | ||
| 928 | Report( | ||
| 929 | "ERROR: Interceptors are not working. This may be because %s is " | ||
| 930 | "loaded too late (e.g. via dlopen). Please launch the executable " | ||
| 931 | "with:\n%s=%s\n", | ||
| 932 | SanitizerToolName, kDyldInsertLibraries, info.dli_fname); | ||
| 933 | RAW_CHECK("interceptors not installed" && 0); | ||
| 934 | } | ||
| 935 | |||
| 936 | if (!lib_is_in_env) | ||
| 937 | return; | ||
| 938 | |||
| 939 | if (!common_flags()->strip_env) | ||
| 940 | return; | ||
| 941 | |||
| 942 | // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove | ||
| 943 | // the dylib from the environment variable, because interceptors are installed | ||
| 944 | // and we don't want our children to inherit the variable. | ||
| 945 | |||
| 946 | uptr env_name_len = internal_strlen(kDyldInsertLibraries); | ||
| 947 | // Allocate memory to hold the previous env var name, its value, the '=' | ||
| 948 | // sign and the '\0' char. | ||
| 949 | char *new_env = (char*)allocator_for_env.Allocate( | ||
| 950 | old_env_len + 2 + env_name_len); | ||
| 951 | RAW_CHECK(new_env); | ||
| 952 | internal_memset(new_env, '\0', old_env_len + 2 + env_name_len); | ||
| 953 | internal_strncpy(new_env, kDyldInsertLibraries, env_name_len); | ||
| 954 | new_env[env_name_len] = '='; | ||
| 955 | char *new_env_pos = new_env + env_name_len + 1; | ||
| 956 | |||
| 957 | // Iterate over colon-separated pieces of |dyld_insert_libraries|. | ||
| 958 | char *piece_start = dyld_insert_libraries; | ||
| 959 | char *piece_end = NULL; | ||
| 960 | char *old_env_end = dyld_insert_libraries + old_env_len; | ||
| 961 | do { | ||
| 962 | if (piece_start[0] == ':') piece_start++; | ||
| 963 | piece_end = internal_strchr(piece_start, ':'); | ||
| 964 | if (!piece_end) piece_end = dyld_insert_libraries + old_env_len; | ||
| 965 | if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break; | ||
| 966 | uptr piece_len = piece_end - piece_start; | ||
| 967 | |||
| 968 | char *filename_start = | ||
| 969 | (char *)internal_memrchr(piece_start, '/', piece_len); | ||
| 970 | uptr filename_len = piece_len; | ||
| 971 | if (filename_start) { | ||
| 972 | filename_start += 1; | ||
| 973 | filename_len = piece_len - (filename_start - piece_start); | ||
| 974 | } else { | ||
| 975 | filename_start = piece_start; | ||
| 976 | } | ||
| 977 | |||
| 978 | // If the current piece isn't the runtime library name, | ||
| 979 | // append it to new_env. | ||
| 980 | if ((dylib_name_len != filename_len) || | ||
| 981 | (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) { | ||
| 982 | if (new_env_pos != new_env + env_name_len + 1) { | ||
| 983 | new_env_pos[0] = ':'; | ||
| 984 | new_env_pos++; | ||
| 985 | } | ||
| 986 | internal_strncpy(new_env_pos, piece_start, piece_len); | ||
| 987 | new_env_pos += piece_len; | ||
| 988 | } | ||
| 989 | // Move on to the next piece. | ||
| 990 | piece_start = piece_end; | ||
| 991 | } while (piece_start < old_env_end); | ||
| 992 | |||
| 993 | // Can't use setenv() here, because it requires the allocator to be | ||
| 994 | // initialized. | ||
| 995 | // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in | ||
| 996 | // a separate function called after InitializeAllocator(). | ||
| 997 | if (new_env_pos == new_env + env_name_len + 1) new_env = NULL; | ||
| 998 | LeakyResetEnv(kDyldInsertLibraries, new_env); | ||
| 999 | } | ||
| 1000 | #endif // SANITIZER_GO | ||
| 1001 | |||
| 1002 | char **GetArgv() { | ||
| 1003 | return *_NSGetArgv(); | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | #if SANITIZER_IOS | ||
| 1007 | // The task_vm_info struct is normally provided by the macOS SDK, but we need | ||
| 1008 | // fields only available in 10.12+. Declare the struct manually to be able to | ||
| 1009 | // build against older SDKs. | ||
| 1010 | struct __sanitizer_task_vm_info { | ||
| 1011 | mach_vm_size_t virtual_size; | ||
| 1012 | integer_t region_count; | ||
| 1013 | integer_t page_size; | ||
| 1014 | mach_vm_size_t resident_size; | ||
| 1015 | mach_vm_size_t resident_size_peak; | ||
| 1016 | mach_vm_size_t device; | ||
| 1017 | mach_vm_size_t device_peak; | ||
| 1018 | mach_vm_size_t internal; | ||
| 1019 | mach_vm_size_t internal_peak; | ||
| 1020 | mach_vm_size_t external; | ||
| 1021 | mach_vm_size_t external_peak; | ||
| 1022 | mach_vm_size_t reusable; | ||
| 1023 | mach_vm_size_t reusable_peak; | ||
| 1024 | mach_vm_size_t purgeable_volatile_pmap; | ||
| 1025 | mach_vm_size_t purgeable_volatile_resident; | ||
| 1026 | mach_vm_size_t purgeable_volatile_virtual; | ||
| 1027 | mach_vm_size_t compressed; | ||
| 1028 | mach_vm_size_t compressed_peak; | ||
| 1029 | mach_vm_size_t compressed_lifetime; | ||
| 1030 | mach_vm_size_t phys_footprint; | ||
| 1031 | mach_vm_address_t min_address; | ||
| 1032 | mach_vm_address_t max_address; | ||
| 1033 | }; | ||
| 1034 | #define __SANITIZER_TASK_VM_INFO_COUNT ((mach_msg_type_number_t) \ | ||
| 1035 | (sizeof(__sanitizer_task_vm_info) / sizeof(natural_t))) | ||
| 1036 | |||
| 1037 | static uptr GetTaskInfoMaxAddress() { | ||
| 1038 | __sanitizer_task_vm_info vm_info = {} /* zero initialize */; | ||
| 1039 | mach_msg_type_number_t count = __SANITIZER_TASK_VM_INFO_COUNT; | ||
| 1040 | int err = task_info(mach_task_self(), TASK_VM_INFO, (int *)&vm_info, &count); | ||
| 1041 | return err ? 0 : vm_info.max_address; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | uptr GetMaxUserVirtualAddress() { | ||
| 1045 | static uptr max_vm = GetTaskInfoMaxAddress(); | ||
| 1046 | if (max_vm != 0) | ||
| 1047 | return max_vm - 1; | ||
| 1048 | |||
| 1049 | // xnu cannot provide vm address limit | ||
| 1050 | # if SANITIZER_WORDSIZE == 32 | ||
| 1051 | return 0xffe00000 - 1; | ||
| 1052 | # else | ||
| 1053 | return 0x200000000 - 1; | ||
| 1054 | # endif | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | #else // !SANITIZER_IOS | ||
| 1058 | |||
| 1059 | uptr GetMaxUserVirtualAddress() { | ||
| 1060 | # if SANITIZER_WORDSIZE == 64 | ||
| 1061 | return (1ULL << 47) - 1; // 0x00007fffffffffffUL; | ||
| 1062 | # else // SANITIZER_WORDSIZE == 32 | ||
| 1063 | static_assert(SANITIZER_WORDSIZE == 32, "Wrong wordsize"); | ||
| 1064 | return (1ULL << 32) - 1; // 0xffffffff; | ||
| 1065 | # endif | ||
| 1066 | } | ||
| 1067 | #endif | ||
| 1068 | |||
| 1069 | uptr GetMaxVirtualAddress() { | ||
| 1070 | return GetMaxUserVirtualAddress(); | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, | ||
| 1074 | uptr *largest_gap_found, | ||
| 1075 | uptr *max_occupied_addr) { | ||
| 1076 | typedef vm_region_submap_short_info_data_64_t RegionInfo; | ||
| 1077 | enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 }; | ||
| 1078 | // Start searching for available memory region past PAGEZERO, which is | ||
| 1079 | // 4KB on 32-bit and 4GB on 64-bit. | ||
| 1080 | mach_vm_address_t start_address = | ||
| 1081 | (SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000; | ||
| 1082 | |||
| 1083 | mach_vm_address_t address = start_address; | ||
| 1084 | mach_vm_address_t free_begin = start_address; | ||
| 1085 | kern_return_t kr = KERN_SUCCESS; | ||
| 1086 | if (largest_gap_found) *largest_gap_found = 0; | ||
| 1087 | if (max_occupied_addr) *max_occupied_addr = 0; | ||
| 1088 | while (kr == KERN_SUCCESS) { | ||
| 1089 | mach_vm_size_t vmsize = 0; | ||
| 1090 | natural_t depth = 0; | ||
| 1091 | RegionInfo vminfo; | ||
| 1092 | mach_msg_type_number_t count = kRegionInfoSize; | ||
| 1093 | kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth, | ||
| 1094 | (vm_region_info_t)&vminfo, &count); | ||
| 1095 | if (kr == KERN_INVALID_ADDRESS) { | ||
| 1096 | // No more regions beyond "address", consider the gap at the end of VM. | ||
| 1097 | address = GetMaxVirtualAddress() + 1; | ||
| 1098 | vmsize = 0; | ||
| 1099 | } else { | ||
| 1100 | if (max_occupied_addr) *max_occupied_addr = address + vmsize; | ||
| 1101 | } | ||
| 1102 | if (free_begin != address) { | ||
| 1103 | // We found a free region [free_begin..address-1]. | ||
| 1104 | uptr gap_start = RoundUpTo((uptr)free_begin + left_padding, alignment); | ||
| 1105 | uptr gap_end = RoundDownTo((uptr)address, alignment); | ||
| 1106 | uptr gap_size = gap_end > gap_start ? gap_end - gap_start : 0; | ||
| 1107 | if (size < gap_size) { | ||
| 1108 | return gap_start; | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | if (largest_gap_found && *largest_gap_found < gap_size) { | ||
| 1112 | *largest_gap_found = gap_size; | ||
| 1113 | } | ||
| 1114 | } | ||
| 1115 | // Move to the next region. | ||
| 1116 | address += vmsize; | ||
| 1117 | free_begin = address; | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | // We looked at all free regions and could not find one large enough. | ||
| 1121 | return 0; | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | // FIXME implement on this platform. | ||
| 1125 | void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { } | ||
| 1126 | |||
| 1127 | void SignalContext::DumpAllRegisters(void *context) { | ||
| 1128 | Report("Register values:\n"); | ||
| 1129 | |||
| 1130 | ucontext_t *ucontext = (ucontext_t*)context; | ||
| 1131 | # define DUMPREG64(r) \ | ||
| 1132 | Printf("%s = 0x%016llx ", #r, ucontext->uc_mcontext->__ss.__ ## r); | ||
| 1133 | # define DUMPREGA64(r) \ | ||
| 1134 | Printf(" %s = 0x%016llx ", #r, AARCH64_GET_REG(r)); | ||
| 1135 | # define DUMPREG32(r) \ | ||
| 1136 | Printf("%s = 0x%08x ", #r, ucontext->uc_mcontext->__ss.__ ## r); | ||
| 1137 | # define DUMPREG_(r) Printf(" "); DUMPREG(r); | ||
| 1138 | # define DUMPREG__(r) Printf(" "); DUMPREG(r); | ||
| 1139 | # define DUMPREG___(r) Printf(" "); DUMPREG(r); | ||
| 1140 | |||
| 1141 | # if defined(__x86_64__) | ||
| 1142 | # define DUMPREG(r) DUMPREG64(r) | ||
| 1143 | DUMPREG(rax); DUMPREG(rbx); DUMPREG(rcx); DUMPREG(rdx); Printf("\n"); | ||
| 1144 | DUMPREG(rdi); DUMPREG(rsi); DUMPREG(rbp); DUMPREG(rsp); Printf("\n"); | ||
| 1145 | DUMPREG_(r8); DUMPREG_(r9); DUMPREG(r10); DUMPREG(r11); Printf("\n"); | ||
| 1146 | DUMPREG(r12); DUMPREG(r13); DUMPREG(r14); DUMPREG(r15); Printf("\n"); | ||
| 1147 | # elif defined(__i386__) | ||
| 1148 | # define DUMPREG(r) DUMPREG32(r) | ||
| 1149 | DUMPREG(eax); DUMPREG(ebx); DUMPREG(ecx); DUMPREG(edx); Printf("\n"); | ||
| 1150 | DUMPREG(edi); DUMPREG(esi); DUMPREG(ebp); DUMPREG(esp); Printf("\n"); | ||
| 1151 | # elif defined(__aarch64__) | ||
| 1152 | # define DUMPREG(r) DUMPREG64(r) | ||
| 1153 | DUMPREG_(x[0]); DUMPREG_(x[1]); DUMPREG_(x[2]); DUMPREG_(x[3]); Printf("\n"); | ||
| 1154 | DUMPREG_(x[4]); DUMPREG_(x[5]); DUMPREG_(x[6]); DUMPREG_(x[7]); Printf("\n"); | ||
| 1155 | DUMPREG_(x[8]); DUMPREG_(x[9]); DUMPREG(x[10]); DUMPREG(x[11]); Printf("\n"); | ||
| 1156 | DUMPREG(x[12]); DUMPREG(x[13]); DUMPREG(x[14]); DUMPREG(x[15]); Printf("\n"); | ||
| 1157 | DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]); Printf("\n"); | ||
| 1158 | DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]); Printf("\n"); | ||
| 1159 | DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]); Printf("\n"); | ||
| 1160 | DUMPREG(x[28]); DUMPREGA64(fp); DUMPREGA64(lr); DUMPREGA64(sp); Printf("\n"); | ||
| 1161 | # elif defined(__arm__) | ||
| 1162 | # define DUMPREG(r) DUMPREG32(r) | ||
| 1163 | DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]); Printf("\n"); | ||
| 1164 | DUMPREG_(r[4]); DUMPREG_(r[5]); DUMPREG_(r[6]); DUMPREG_(r[7]); Printf("\n"); | ||
| 1165 | DUMPREG_(r[8]); DUMPREG_(r[9]); DUMPREG(r[10]); DUMPREG(r[11]); Printf("\n"); | ||
| 1166 | DUMPREG(r[12]); DUMPREG___(sp); DUMPREG___(lr); DUMPREG___(pc); Printf("\n"); | ||
| 1167 | # else | ||
| 1168 | # error "Unknown architecture" | ||
| 1169 | # endif | ||
| 1170 | |||
| 1171 | # undef DUMPREG64 | ||
| 1172 | # undef DUMPREG32 | ||
| 1173 | # undef DUMPREG_ | ||
| 1174 | # undef DUMPREG__ | ||
| 1175 | # undef DUMPREG___ | ||
| 1176 | # undef DUMPREG | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | static inline bool CompareBaseAddress(const LoadedModule &a, | ||
| 1180 | const LoadedModule &b) { | ||
| 1181 | return a.base_address() < b.base_address(); | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | void FormatUUID(char *out, uptr size, const u8 *uuid) { | ||
| 1185 | internal_snprintf(out, size, | ||
| 1186 | "<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-" | ||
| 1187 | "%02X%02X%02X%02X%02X%02X>", | ||
| 1188 | uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], | ||
| 1189 | uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], | ||
| 1190 | uuid[12], uuid[13], uuid[14], uuid[15]); | ||
| 1191 | } | ||
| 1192 | |||
| 1193 | void PrintModuleMap() { | ||
| 1194 | Printf("Process module map:\n"); | ||
| 1195 | MemoryMappingLayout memory_mapping(false); | ||
| 1196 | InternalMmapVector<LoadedModule> modules; | ||
| 1197 | modules.reserve(128); | ||
| 1198 | memory_mapping.DumpListOfModules(&modules); | ||
| 1199 | Sort(modules.data(), modules.size(), CompareBaseAddress); | ||
| 1200 | for (uptr i = 0; i < modules.size(); ++i) { | ||
| 1201 | char uuid_str[128]; | ||
| 1202 | FormatUUID(uuid_str, sizeof(uuid_str), modules[i].uuid()); | ||
| 1203 | Printf("0x%zx-0x%zx %s (%s) %s\n", modules[i].base_address(), | ||
| 1204 | modules[i].max_executable_address(), modules[i].full_name(), | ||
| 1205 | ModuleArchToString(modules[i].arch()), uuid_str); | ||
| 1206 | } | ||
| 1207 | Printf("End of module map.\n"); | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | void CheckNoDeepBind(const char *filename, int flag) { | ||
| 1211 | // Do nothing. | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | bool GetRandom(void *buffer, uptr length, bool blocking) { | ||
| 1215 | if (!buffer || !length || length > 256) | ||
| 1216 | return false; | ||
| 1217 | // arc4random never fails. | ||
| 1218 | REAL(arc4random_buf)(buffer, length); | ||
| 1219 | return true; | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | u32 GetNumberOfCPUs() { | ||
| 1223 | return (u32)sysconf(_SC_NPROCESSORS_ONLN); | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | } // namespace __sanitizer | ||
| 1227 | |||
| 1228 | #endif // SANITIZER_MAC | ||
lib/tsan/sanitizer_common/sanitizer_mac.h created+84| ... | @@ -0,0 +1,84 @@ | ||
| 1 | //===-- sanitizer_mac.h -----------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between various sanitizers' runtime libraries and | ||
| 10 | // provides definitions for OSX-specific functions. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_MAC_H | ||
| 13 | #define SANITIZER_MAC_H | ||
| 14 | |||
| 15 | #include "sanitizer_common.h" | ||
| 16 | #include "sanitizer_platform.h" | ||
| 17 | #if SANITIZER_MAC | ||
| 18 | #include "sanitizer_posix.h" | ||
| 19 | |||
| 20 | namespace __sanitizer { | ||
| 21 | |||
| 22 | struct MemoryMappingLayoutData { | ||
| 23 | int current_image; | ||
| 24 | u32 current_magic; | ||
| 25 | u32 current_filetype; | ||
| 26 | ModuleArch current_arch; | ||
| 27 | u8 current_uuid[kModuleUUIDSize]; | ||
| 28 | int current_load_cmd_count; | ||
| 29 | const char *current_load_cmd_addr; | ||
| 30 | bool current_instrumented; | ||
| 31 | }; | ||
| 32 | |||
| 33 | template <typename VersionType> | ||
| 34 | struct VersionBase { | ||
| 35 | u16 major; | ||
| 36 | u16 minor; | ||
| 37 | |||
| 38 | VersionBase(u16 major, u16 minor) : major(major), minor(minor) {} | ||
| 39 | |||
| 40 | bool operator==(const VersionType &other) const { | ||
| 41 | return major == other.major && minor == other.minor; | ||
| 42 | } | ||
| 43 | bool operator>=(const VersionType &other) const { | ||
| 44 | return major > other.major || | ||
| 45 | (major == other.major && minor >= other.minor); | ||
| 46 | } | ||
| 47 | }; | ||
| 48 | |||
| 49 | struct MacosVersion : VersionBase<MacosVersion> { | ||
| 50 | MacosVersion(u16 major, u16 minor) : VersionBase(major, minor) {} | ||
| 51 | }; | ||
| 52 | |||
| 53 | struct DarwinKernelVersion : VersionBase<DarwinKernelVersion> { | ||
| 54 | DarwinKernelVersion(u16 major, u16 minor) : VersionBase(major, minor) {} | ||
| 55 | }; | ||
| 56 | |||
| 57 | MacosVersion GetMacosAlignedVersion(); | ||
| 58 | DarwinKernelVersion GetDarwinKernelVersion(); | ||
| 59 | |||
| 60 | char **GetEnviron(); | ||
| 61 | |||
| 62 | void RestrictMemoryToMaxAddress(uptr max_address); | ||
| 63 | |||
| 64 | } // namespace __sanitizer | ||
| 65 | |||
| 66 | extern "C" { | ||
| 67 | static char __crashreporter_info_buff__[__sanitizer::kErrorMessageBufferSize] = | ||
| 68 | {}; | ||
| 69 | static const char *__crashreporter_info__ __attribute__((__used__)) = | ||
| 70 | &__crashreporter_info_buff__[0]; | ||
| 71 | asm(".desc ___crashreporter_info__, 0x10"); | ||
| 72 | } // extern "C" | ||
| 73 | |||
| 74 | namespace __sanitizer { | ||
| 75 | static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED); | ||
| 76 | |||
| 77 | INLINE void CRAppendCrashLogMessage(const char *msg) { | ||
| 78 | BlockingMutexLock l(&crashreporter_info_mutex); | ||
| 79 | internal_strlcat(__crashreporter_info_buff__, msg, | ||
| 80 | sizeof(__crashreporter_info_buff__)); } | ||
| 81 | } // namespace __sanitizer | ||
| 82 | |||
| 83 | #endif // SANITIZER_MAC | ||
| 84 | #endif // SANITIZER_MAC_H | ||
lib/tsan/sanitizer_common/sanitizer_malloc_mac.inc created+420| ... | @@ -0,0 +1,420 @@ | ||
| 1 | //===-- sanitizer_malloc_mac.inc --------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file contains Mac-specific malloc interceptors and a custom zone | ||
| 10 | // implementation, which together replace the system allocator. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_common/sanitizer_platform.h" | ||
| 15 | #if !SANITIZER_MAC | ||
| 16 | #error "This file should only be compiled on Darwin." | ||
| 17 | #endif | ||
| 18 | |||
| 19 | #include <AvailabilityMacros.h> | ||
| 20 | #include <CoreFoundation/CFBase.h> | ||
| 21 | #include <dlfcn.h> | ||
| 22 | #include <malloc/malloc.h> | ||
| 23 | #include <sys/mman.h> | ||
| 24 | |||
| 25 | #include "interception/interception.h" | ||
| 26 | #include "sanitizer_common/sanitizer_mac.h" | ||
| 27 | |||
| 28 | // Similar code is used in Google Perftools, | ||
| 29 | // https://github.com/gperftools/gperftools. | ||
| 30 | |||
| 31 | namespace __sanitizer { | ||
| 32 | |||
| 33 | extern malloc_zone_t sanitizer_zone; | ||
| 34 | |||
| 35 | struct sanitizer_malloc_introspection_t : public malloc_introspection_t { | ||
| 36 | // IMPORTANT: Do not change the order, alignment, or types of these fields to | ||
| 37 | // maintain binary compatibility. You should only add fields to this struct. | ||
| 38 | |||
| 39 | // Used to track changes to the allocator that will affect | ||
| 40 | // zone enumeration. | ||
| 41 | u64 allocator_enumeration_version; | ||
| 42 | uptr allocator_ptr; | ||
| 43 | uptr allocator_size; | ||
| 44 | }; | ||
| 45 | |||
| 46 | u64 GetMallocZoneAllocatorEnumerationVersion() { | ||
| 47 | // This represents the current allocator ABI version. | ||
| 48 | // This field should be incremented every time the Allocator | ||
| 49 | // ABI changes in a way that breaks allocator enumeration. | ||
| 50 | return 0; | ||
| 51 | } | ||
| 52 | |||
| 53 | } // namespace __sanitizer | ||
| 54 | |||
| 55 | INTERCEPTOR(malloc_zone_t *, malloc_create_zone, | ||
| 56 | vm_size_t start_size, unsigned zone_flags) { | ||
| 57 | COMMON_MALLOC_ENTER(); | ||
| 58 | uptr page_size = GetPageSizeCached(); | ||
| 59 | uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size); | ||
| 60 | COMMON_MALLOC_MEMALIGN(page_size, allocated_size); | ||
| 61 | malloc_zone_t *new_zone = (malloc_zone_t *)p; | ||
| 62 | internal_memcpy(new_zone, &sanitizer_zone, sizeof(sanitizer_zone)); | ||
| 63 | new_zone->zone_name = NULL; // The name will be changed anyway. | ||
| 64 | // Prevent the client app from overwriting the zone contents. | ||
| 65 | // Library functions that need to modify the zone will set PROT_WRITE on it. | ||
| 66 | // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher. | ||
| 67 | mprotect(new_zone, allocated_size, PROT_READ); | ||
| 68 | // We're explicitly *NOT* registering the zone. | ||
| 69 | return new_zone; | ||
| 70 | } | ||
| 71 | |||
| 72 | INTERCEPTOR(void, malloc_destroy_zone, malloc_zone_t *zone) { | ||
| 73 | COMMON_MALLOC_ENTER(); | ||
| 74 | // We don't need to do anything here. We're not registering new zones, so we | ||
| 75 | // don't to unregister. Just un-mprotect and free() the zone. | ||
| 76 | uptr page_size = GetPageSizeCached(); | ||
| 77 | uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size); | ||
| 78 | mprotect(zone, allocated_size, PROT_READ | PROT_WRITE); | ||
| 79 | if (zone->zone_name) { | ||
| 80 | COMMON_MALLOC_FREE((void *)zone->zone_name); | ||
| 81 | } | ||
| 82 | COMMON_MALLOC_FREE(zone); | ||
| 83 | } | ||
| 84 | |||
| 85 | INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) { | ||
| 86 | COMMON_MALLOC_ENTER(); | ||
| 87 | return &sanitizer_zone; | ||
| 88 | } | ||
| 89 | |||
| 90 | INTERCEPTOR(malloc_zone_t *, malloc_zone_from_ptr, const void *ptr) { | ||
| 91 | COMMON_MALLOC_ENTER(); | ||
| 92 | size_t size = sanitizer_zone.size(&sanitizer_zone, ptr); | ||
| 93 | if (size) { // Claimed by sanitizer zone? | ||
| 94 | return &sanitizer_zone; | ||
| 95 | } | ||
| 96 | return REAL(malloc_zone_from_ptr)(ptr); | ||
| 97 | } | ||
| 98 | |||
| 99 | INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) { | ||
| 100 | // FIXME: ASan should support purgeable allocations. | ||
| 101 | // https://github.com/google/sanitizers/issues/139 | ||
| 102 | COMMON_MALLOC_ENTER(); | ||
| 103 | return &sanitizer_zone; | ||
| 104 | } | ||
| 105 | |||
| 106 | INTERCEPTOR(void, malloc_make_purgeable, void *ptr) { | ||
| 107 | // FIXME: ASan should support purgeable allocations. Ignoring them is fine | ||
| 108 | // for now. | ||
| 109 | COMMON_MALLOC_ENTER(); | ||
| 110 | } | ||
| 111 | |||
| 112 | INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) { | ||
| 113 | // FIXME: ASan should support purgeable allocations. Ignoring them is fine | ||
| 114 | // for now. | ||
| 115 | COMMON_MALLOC_ENTER(); | ||
| 116 | // Must return 0 if the contents were not purged since the last call to | ||
| 117 | // malloc_make_purgeable(). | ||
| 118 | return 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) { | ||
| 122 | COMMON_MALLOC_ENTER(); | ||
| 123 | // Allocate |sizeof(COMMON_MALLOC_ZONE_NAME "-") + internal_strlen(name)| | ||
| 124 | // bytes. | ||
| 125 | size_t buflen = | ||
| 126 | sizeof(COMMON_MALLOC_ZONE_NAME "-") + (name ? internal_strlen(name) : 0); | ||
| 127 | InternalScopedString new_name(buflen); | ||
| 128 | if (name && zone->introspect == sanitizer_zone.introspect) { | ||
| 129 | new_name.append(COMMON_MALLOC_ZONE_NAME "-%s", name); | ||
| 130 | name = new_name.data(); | ||
| 131 | } | ||
| 132 | |||
| 133 | // Call the system malloc's implementation for both external and our zones, | ||
| 134 | // since that appropriately changes VM region protections on the zone. | ||
| 135 | REAL(malloc_set_zone_name)(zone, name); | ||
| 136 | } | ||
| 137 | |||
| 138 | INTERCEPTOR(void *, malloc, size_t size) { | ||
| 139 | COMMON_MALLOC_ENTER(); | ||
| 140 | COMMON_MALLOC_MALLOC(size); | ||
| 141 | return p; | ||
| 142 | } | ||
| 143 | |||
| 144 | INTERCEPTOR(void, free, void *ptr) { | ||
| 145 | COMMON_MALLOC_ENTER(); | ||
| 146 | if (!ptr) return; | ||
| 147 | COMMON_MALLOC_FREE(ptr); | ||
| 148 | } | ||
| 149 | |||
| 150 | INTERCEPTOR(void *, realloc, void *ptr, size_t size) { | ||
| 151 | COMMON_MALLOC_ENTER(); | ||
| 152 | COMMON_MALLOC_REALLOC(ptr, size); | ||
| 153 | return p; | ||
| 154 | } | ||
| 155 | |||
| 156 | INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) { | ||
| 157 | COMMON_MALLOC_ENTER(); | ||
| 158 | COMMON_MALLOC_CALLOC(nmemb, size); | ||
| 159 | return p; | ||
| 160 | } | ||
| 161 | |||
| 162 | INTERCEPTOR(void *, valloc, size_t size) { | ||
| 163 | COMMON_MALLOC_ENTER(); | ||
| 164 | COMMON_MALLOC_VALLOC(size); | ||
| 165 | return p; | ||
| 166 | } | ||
| 167 | |||
| 168 | INTERCEPTOR(size_t, malloc_good_size, size_t size) { | ||
| 169 | COMMON_MALLOC_ENTER(); | ||
| 170 | return sanitizer_zone.introspect->good_size(&sanitizer_zone, size); | ||
| 171 | } | ||
| 172 | |||
| 173 | INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) { | ||
| 174 | COMMON_MALLOC_ENTER(); | ||
| 175 | CHECK(memptr); | ||
| 176 | COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size); | ||
| 177 | return res; | ||
| 178 | } | ||
| 179 | |||
| 180 | namespace { | ||
| 181 | |||
| 182 | // TODO(glider): the __sanitizer_mz_* functions should be united with the Linux | ||
| 183 | // wrappers, as they are basically copied from there. | ||
| 184 | extern "C" | ||
| 185 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 186 | size_t __sanitizer_mz_size(malloc_zone_t* zone, const void* ptr) { | ||
| 187 | COMMON_MALLOC_SIZE(ptr); | ||
| 188 | return size; | ||
| 189 | } | ||
| 190 | |||
| 191 | extern "C" | ||
| 192 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 193 | void *__sanitizer_mz_malloc(malloc_zone_t *zone, uptr size) { | ||
| 194 | COMMON_MALLOC_ENTER(); | ||
| 195 | COMMON_MALLOC_MALLOC(size); | ||
| 196 | return p; | ||
| 197 | } | ||
| 198 | |||
| 199 | extern "C" | ||
| 200 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 201 | void *__sanitizer_mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) { | ||
| 202 | if (UNLIKELY(!COMMON_MALLOC_SANITIZER_INITIALIZED)) { | ||
| 203 | // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. | ||
| 204 | const size_t kCallocPoolSize = 1024; | ||
| 205 | static uptr calloc_memory_for_dlsym[kCallocPoolSize]; | ||
| 206 | static size_t allocated; | ||
| 207 | size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize; | ||
| 208 | void *mem = (void*)&calloc_memory_for_dlsym[allocated]; | ||
| 209 | allocated += size_in_words; | ||
| 210 | CHECK(allocated < kCallocPoolSize); | ||
| 211 | return mem; | ||
| 212 | } | ||
| 213 | COMMON_MALLOC_CALLOC(nmemb, size); | ||
| 214 | return p; | ||
| 215 | } | ||
| 216 | |||
| 217 | extern "C" | ||
| 218 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 219 | void *__sanitizer_mz_valloc(malloc_zone_t *zone, size_t size) { | ||
| 220 | COMMON_MALLOC_ENTER(); | ||
| 221 | COMMON_MALLOC_VALLOC(size); | ||
| 222 | return p; | ||
| 223 | } | ||
| 224 | |||
| 225 | // TODO(glider): the allocation callbacks need to be refactored. | ||
| 226 | extern "C" | ||
| 227 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 228 | void __sanitizer_mz_free(malloc_zone_t *zone, void *ptr) { | ||
| 229 | if (!ptr) return; | ||
| 230 | COMMON_MALLOC_FREE(ptr); | ||
| 231 | } | ||
| 232 | |||
| 233 | #define GET_ZONE_FOR_PTR(ptr) \ | ||
| 234 | malloc_zone_t *zone_ptr = WRAP(malloc_zone_from_ptr)(ptr); \ | ||
| 235 | const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name | ||
| 236 | |||
| 237 | extern "C" | ||
| 238 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 239 | void *__sanitizer_mz_realloc(malloc_zone_t *zone, void *ptr, size_t new_size) { | ||
| 240 | if (!ptr) { | ||
| 241 | COMMON_MALLOC_MALLOC(new_size); | ||
| 242 | return p; | ||
| 243 | } else { | ||
| 244 | COMMON_MALLOC_SIZE(ptr); | ||
| 245 | if (size) { | ||
| 246 | COMMON_MALLOC_REALLOC(ptr, new_size); | ||
| 247 | return p; | ||
| 248 | } else { | ||
| 249 | // We can't recover from reallocating an unknown address, because | ||
| 250 | // this would require reading at most |new_size| bytes from | ||
| 251 | // potentially unaccessible memory. | ||
| 252 | GET_ZONE_FOR_PTR(ptr); | ||
| 253 | COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name); | ||
| 254 | return nullptr; | ||
| 255 | } | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | extern "C" | ||
| 260 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 261 | void __sanitizer_mz_destroy(malloc_zone_t* zone) { | ||
| 262 | // A no-op -- we will not be destroyed! | ||
| 263 | Report("__sanitizer_mz_destroy() called -- ignoring\n"); | ||
| 264 | } | ||
| 265 | |||
| 266 | extern "C" | ||
| 267 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 268 | void *__sanitizer_mz_memalign(malloc_zone_t *zone, size_t align, size_t size) { | ||
| 269 | COMMON_MALLOC_ENTER(); | ||
| 270 | COMMON_MALLOC_MEMALIGN(align, size); | ||
| 271 | return p; | ||
| 272 | } | ||
| 273 | |||
| 274 | // This public API exists purely for testing purposes. | ||
| 275 | extern "C" | ||
| 276 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 277 | malloc_zone_t* __sanitizer_mz_default_zone() { | ||
| 278 | return &sanitizer_zone; | ||
| 279 | } | ||
| 280 | |||
| 281 | // This function is currently unused, and we build with -Werror. | ||
| 282 | #if 0 | ||
| 283 | void __sanitizer_mz_free_definite_size( | ||
| 284 | malloc_zone_t* zone, void *ptr, size_t size) { | ||
| 285 | // TODO(glider): check that |size| is valid. | ||
| 286 | UNIMPLEMENTED(); | ||
| 287 | } | ||
| 288 | #endif | ||
| 289 | |||
| 290 | #ifndef COMMON_MALLOC_HAS_ZONE_ENUMERATOR | ||
| 291 | #error "COMMON_MALLOC_HAS_ZONE_ENUMERATOR must be defined" | ||
| 292 | #endif | ||
| 293 | static_assert((COMMON_MALLOC_HAS_ZONE_ENUMERATOR) == 0 || | ||
| 294 | (COMMON_MALLOC_HAS_ZONE_ENUMERATOR) == 1, | ||
| 295 | "COMMON_MALLOC_HAS_ZONE_ENUMERATOR must be 0 or 1"); | ||
| 296 | |||
| 297 | #if COMMON_MALLOC_HAS_ZONE_ENUMERATOR | ||
| 298 | // Forward declare and expect the implementation to provided by | ||
| 299 | // includer. | ||
| 300 | kern_return_t mi_enumerator(task_t task, void *, unsigned type_mask, | ||
| 301 | vm_address_t zone_address, memory_reader_t reader, | ||
| 302 | vm_range_recorder_t recorder); | ||
| 303 | #else | ||
| 304 | // Provide stub implementation that fails. | ||
| 305 | kern_return_t mi_enumerator(task_t task, void *, unsigned type_mask, | ||
| 306 | vm_address_t zone_address, memory_reader_t reader, | ||
| 307 | vm_range_recorder_t recorder) { | ||
| 308 | // Not supported. | ||
| 309 | return KERN_FAILURE; | ||
| 310 | } | ||
| 311 | #endif | ||
| 312 | |||
| 313 | #ifndef COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT | ||
| 314 | #error "COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT must be defined" | ||
| 315 | #endif | ||
| 316 | static_assert((COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT) == 0 || | ||
| 317 | (COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT) == 1, | ||
| 318 | "COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT must be 0 or 1"); | ||
| 319 | #if COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT | ||
| 320 | // Forward declare and expect the implementation to provided by | ||
| 321 | // includer. | ||
| 322 | void mi_extra_init( | ||
| 323 | sanitizer_malloc_introspection_t *mi); | ||
| 324 | #else | ||
| 325 | void mi_extra_init( | ||
| 326 | sanitizer_malloc_introspection_t *mi) { | ||
| 327 | // Just zero initialize the fields. | ||
| 328 | mi->allocator_ptr = 0; | ||
| 329 | mi->allocator_size = 0; | ||
| 330 | } | ||
| 331 | #endif | ||
| 332 | |||
| 333 | size_t mi_good_size(malloc_zone_t *zone, size_t size) { | ||
| 334 | // I think it's always safe to return size, but we maybe could do better. | ||
| 335 | return size; | ||
| 336 | } | ||
| 337 | |||
| 338 | boolean_t mi_check(malloc_zone_t *zone) { | ||
| 339 | UNIMPLEMENTED(); | ||
| 340 | } | ||
| 341 | |||
| 342 | void mi_print(malloc_zone_t *zone, boolean_t verbose) { | ||
| 343 | UNIMPLEMENTED(); | ||
| 344 | } | ||
| 345 | |||
| 346 | void mi_log(malloc_zone_t *zone, void *address) { | ||
| 347 | // I don't think we support anything like this | ||
| 348 | } | ||
| 349 | |||
| 350 | void mi_force_lock(malloc_zone_t *zone) { | ||
| 351 | COMMON_MALLOC_FORCE_LOCK(); | ||
| 352 | } | ||
| 353 | |||
| 354 | void mi_force_unlock(malloc_zone_t *zone) { | ||
| 355 | COMMON_MALLOC_FORCE_UNLOCK(); | ||
| 356 | } | ||
| 357 | |||
| 358 | void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) { | ||
| 359 | COMMON_MALLOC_FILL_STATS(zone, stats); | ||
| 360 | } | ||
| 361 | |||
| 362 | boolean_t mi_zone_locked(malloc_zone_t *zone) { | ||
| 363 | // UNIMPLEMENTED(); | ||
| 364 | return false; | ||
| 365 | } | ||
| 366 | |||
| 367 | } // unnamed namespace | ||
| 368 | |||
| 369 | namespace COMMON_MALLOC_NAMESPACE { | ||
| 370 | |||
| 371 | void InitMallocZoneFields() { | ||
| 372 | static sanitizer_malloc_introspection_t sanitizer_zone_introspection; | ||
| 373 | // Ok to use internal_memset, these places are not performance-critical. | ||
| 374 | internal_memset(&sanitizer_zone_introspection, 0, | ||
| 375 | sizeof(sanitizer_zone_introspection)); | ||
| 376 | |||
| 377 | sanitizer_zone_introspection.enumerator = &mi_enumerator; | ||
| 378 | sanitizer_zone_introspection.good_size = &mi_good_size; | ||
| 379 | sanitizer_zone_introspection.check = &mi_check; | ||
| 380 | sanitizer_zone_introspection.print = &mi_print; | ||
| 381 | sanitizer_zone_introspection.log = &mi_log; | ||
| 382 | sanitizer_zone_introspection.force_lock = &mi_force_lock; | ||
| 383 | sanitizer_zone_introspection.force_unlock = &mi_force_unlock; | ||
| 384 | sanitizer_zone_introspection.statistics = &mi_statistics; | ||
| 385 | sanitizer_zone_introspection.zone_locked = &mi_zone_locked; | ||
| 386 | |||
| 387 | // Set current allocator enumeration version. | ||
| 388 | sanitizer_zone_introspection.allocator_enumeration_version = | ||
| 389 | GetMallocZoneAllocatorEnumerationVersion(); | ||
| 390 | |||
| 391 | // Perform any sanitizer specific initialization. | ||
| 392 | mi_extra_init(&sanitizer_zone_introspection); | ||
| 393 | |||
| 394 | internal_memset(&sanitizer_zone, 0, sizeof(malloc_zone_t)); | ||
| 395 | |||
| 396 | // Use version 6 for OSX >= 10.6. | ||
| 397 | sanitizer_zone.version = 6; | ||
| 398 | sanitizer_zone.zone_name = COMMON_MALLOC_ZONE_NAME; | ||
| 399 | sanitizer_zone.size = &__sanitizer_mz_size; | ||
| 400 | sanitizer_zone.malloc = &__sanitizer_mz_malloc; | ||
| 401 | sanitizer_zone.calloc = &__sanitizer_mz_calloc; | ||
| 402 | sanitizer_zone.valloc = &__sanitizer_mz_valloc; | ||
| 403 | sanitizer_zone.free = &__sanitizer_mz_free; | ||
| 404 | sanitizer_zone.realloc = &__sanitizer_mz_realloc; | ||
| 405 | sanitizer_zone.destroy = &__sanitizer_mz_destroy; | ||
| 406 | sanitizer_zone.batch_malloc = 0; | ||
| 407 | sanitizer_zone.batch_free = 0; | ||
| 408 | sanitizer_zone.free_definite_size = 0; | ||
| 409 | sanitizer_zone.memalign = &__sanitizer_mz_memalign; | ||
| 410 | sanitizer_zone.introspect = &sanitizer_zone_introspection; | ||
| 411 | } | ||
| 412 | |||
| 413 | void ReplaceSystemMalloc() { | ||
| 414 | InitMallocZoneFields(); | ||
| 415 | |||
| 416 | // Register the zone. | ||
| 417 | malloc_zone_register(&sanitizer_zone); | ||
| 418 | } | ||
| 419 | |||
| 420 | } // namespace COMMON_MALLOC_NAMESPACE | ||
lib/tsan/sanitizer_common/sanitizer_mutex.h created+223| ... | @@ -0,0 +1,223 @@ | ||
| 1 | //===-- sanitizer_mutex.h ---------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer/AddressSanitizer runtime. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef SANITIZER_MUTEX_H | ||
| 14 | #define SANITIZER_MUTEX_H | ||
| 15 | |||
| 16 | #include "sanitizer_atomic.h" | ||
| 17 | #include "sanitizer_internal_defs.h" | ||
| 18 | #include "sanitizer_libc.h" | ||
| 19 | |||
| 20 | namespace __sanitizer { | ||
| 21 | |||
| 22 | class StaticSpinMutex { | ||
| 23 | public: | ||
| 24 | void Init() { | ||
| 25 | atomic_store(&state_, 0, memory_order_relaxed); | ||
| 26 | } | ||
| 27 | |||
| 28 | void Lock() { | ||
| 29 | if (TryLock()) | ||
| 30 | return; | ||
| 31 | LockSlow(); | ||
| 32 | } | ||
| 33 | |||
| 34 | bool TryLock() { | ||
| 35 | return atomic_exchange(&state_, 1, memory_order_acquire) == 0; | ||
| 36 | } | ||
| 37 | |||
| 38 | void Unlock() { | ||
| 39 | atomic_store(&state_, 0, memory_order_release); | ||
| 40 | } | ||
| 41 | |||
| 42 | void CheckLocked() { | ||
| 43 | CHECK_EQ(atomic_load(&state_, memory_order_relaxed), 1); | ||
| 44 | } | ||
| 45 | |||
| 46 | private: | ||
| 47 | atomic_uint8_t state_; | ||
| 48 | |||
| 49 | void NOINLINE LockSlow() { | ||
| 50 | for (int i = 0;; i++) { | ||
| 51 | if (i < 10) | ||
| 52 | proc_yield(10); | ||
| 53 | else | ||
| 54 | internal_sched_yield(); | ||
| 55 | if (atomic_load(&state_, memory_order_relaxed) == 0 | ||
| 56 | && atomic_exchange(&state_, 1, memory_order_acquire) == 0) | ||
| 57 | return; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | }; | ||
| 61 | |||
| 62 | class SpinMutex : public StaticSpinMutex { | ||
| 63 | public: | ||
| 64 | SpinMutex() { | ||
| 65 | Init(); | ||
| 66 | } | ||
| 67 | |||
| 68 | private: | ||
| 69 | SpinMutex(const SpinMutex&); | ||
| 70 | void operator=(const SpinMutex&); | ||
| 71 | }; | ||
| 72 | |||
| 73 | class BlockingMutex { | ||
| 74 | public: | ||
| 75 | explicit constexpr BlockingMutex(LinkerInitialized) | ||
| 76 | : opaque_storage_ {0, }, owner_ {0} {} | ||
| 77 | BlockingMutex(); | ||
| 78 | void Lock(); | ||
| 79 | void Unlock(); | ||
| 80 | |||
| 81 | // This function does not guarantee an explicit check that the calling thread | ||
| 82 | // is the thread which owns the mutex. This behavior, while more strictly | ||
| 83 | // correct, causes problems in cases like StopTheWorld, where a parent thread | ||
| 84 | // owns the mutex but a child checks that it is locked. Rather than | ||
| 85 | // maintaining complex state to work around those situations, the check only | ||
| 86 | // checks that the mutex is owned, and assumes callers to be generally | ||
| 87 | // well-behaved. | ||
| 88 | void CheckLocked(); | ||
| 89 | |||
| 90 | private: | ||
| 91 | // Solaris mutex_t has a member that requires 64-bit alignment. | ||
| 92 | ALIGNED(8) uptr opaque_storage_[10]; | ||
| 93 | uptr owner_; // for debugging | ||
| 94 | }; | ||
| 95 | |||
| 96 | // Reader-writer spin mutex. | ||
| 97 | class RWMutex { | ||
| 98 | public: | ||
| 99 | RWMutex() { | ||
| 100 | atomic_store(&state_, kUnlocked, memory_order_relaxed); | ||
| 101 | } | ||
| 102 | |||
| 103 | ~RWMutex() { | ||
| 104 | CHECK_EQ(atomic_load(&state_, memory_order_relaxed), kUnlocked); | ||
| 105 | } | ||
| 106 | |||
| 107 | void Lock() { | ||
| 108 | u32 cmp = kUnlocked; | ||
| 109 | if (atomic_compare_exchange_strong(&state_, &cmp, kWriteLock, | ||
| 110 | memory_order_acquire)) | ||
| 111 | return; | ||
| 112 | LockSlow(); | ||
| 113 | } | ||
| 114 | |||
| 115 | void Unlock() { | ||
| 116 | u32 prev = atomic_fetch_sub(&state_, kWriteLock, memory_order_release); | ||
| 117 | DCHECK_NE(prev & kWriteLock, 0); | ||
| 118 | (void)prev; | ||
| 119 | } | ||
| 120 | |||
| 121 | void ReadLock() { | ||
| 122 | u32 prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire); | ||
| 123 | if ((prev & kWriteLock) == 0) | ||
| 124 | return; | ||
| 125 | ReadLockSlow(); | ||
| 126 | } | ||
| 127 | |||
| 128 | void ReadUnlock() { | ||
| 129 | u32 prev = atomic_fetch_sub(&state_, kReadLock, memory_order_release); | ||
| 130 | DCHECK_EQ(prev & kWriteLock, 0); | ||
| 131 | DCHECK_GT(prev & ~kWriteLock, 0); | ||
| 132 | (void)prev; | ||
| 133 | } | ||
| 134 | |||
| 135 | void CheckLocked() { | ||
| 136 | CHECK_NE(atomic_load(&state_, memory_order_relaxed), kUnlocked); | ||
| 137 | } | ||
| 138 | |||
| 139 | private: | ||
| 140 | atomic_uint32_t state_; | ||
| 141 | |||
| 142 | enum { | ||
| 143 | kUnlocked = 0, | ||
| 144 | kWriteLock = 1, | ||
| 145 | kReadLock = 2 | ||
| 146 | }; | ||
| 147 | |||
| 148 | void NOINLINE LockSlow() { | ||
| 149 | for (int i = 0;; i++) { | ||
| 150 | if (i < 10) | ||
| 151 | proc_yield(10); | ||
| 152 | else | ||
| 153 | internal_sched_yield(); | ||
| 154 | u32 cmp = atomic_load(&state_, memory_order_relaxed); | ||
| 155 | if (cmp == kUnlocked && | ||
| 156 | atomic_compare_exchange_weak(&state_, &cmp, kWriteLock, | ||
| 157 | memory_order_acquire)) | ||
| 158 | return; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | void NOINLINE ReadLockSlow() { | ||
| 163 | for (int i = 0;; i++) { | ||
| 164 | if (i < 10) | ||
| 165 | proc_yield(10); | ||
| 166 | else | ||
| 167 | internal_sched_yield(); | ||
| 168 | u32 prev = atomic_load(&state_, memory_order_acquire); | ||
| 169 | if ((prev & kWriteLock) == 0) | ||
| 170 | return; | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | RWMutex(const RWMutex&); | ||
| 175 | void operator = (const RWMutex&); | ||
| 176 | }; | ||
| 177 | |||
| 178 | template<typename MutexType> | ||
| 179 | class GenericScopedLock { | ||
| 180 | public: | ||
| 181 | explicit GenericScopedLock(MutexType *mu) | ||
| 182 | : mu_(mu) { | ||
| 183 | mu_->Lock(); | ||
| 184 | } | ||
| 185 | |||
| 186 | ~GenericScopedLock() { | ||
| 187 | mu_->Unlock(); | ||
| 188 | } | ||
| 189 | |||
| 190 | private: | ||
| 191 | MutexType *mu_; | ||
| 192 | |||
| 193 | GenericScopedLock(const GenericScopedLock&); | ||
| 194 | void operator=(const GenericScopedLock&); | ||
| 195 | }; | ||
| 196 | |||
| 197 | template<typename MutexType> | ||
| 198 | class GenericScopedReadLock { | ||
| 199 | public: | ||
| 200 | explicit GenericScopedReadLock(MutexType *mu) | ||
| 201 | : mu_(mu) { | ||
| 202 | mu_->ReadLock(); | ||
| 203 | } | ||
| 204 | |||
| 205 | ~GenericScopedReadLock() { | ||
| 206 | mu_->ReadUnlock(); | ||
| 207 | } | ||
| 208 | |||
| 209 | private: | ||
| 210 | MutexType *mu_; | ||
| 211 | |||
| 212 | GenericScopedReadLock(const GenericScopedReadLock&); | ||
| 213 | void operator=(const GenericScopedReadLock&); | ||
| 214 | }; | ||
| 215 | |||
| 216 | typedef GenericScopedLock<StaticSpinMutex> SpinMutexLock; | ||
| 217 | typedef GenericScopedLock<BlockingMutex> BlockingMutexLock; | ||
| 218 | typedef GenericScopedLock<RWMutex> RWMutexLock; | ||
| 219 | typedef GenericScopedReadLock<RWMutex> RWMutexReadLock; | ||
| 220 | |||
| 221 | } // namespace __sanitizer | ||
| 222 | |||
| 223 | #endif // SANITIZER_MUTEX_H | ||
lib/tsan/sanitizer_common/sanitizer_netbsd.cpp created+343| ... | @@ -0,0 +1,343 @@ | ||
| 1 | //===-- sanitizer_netbsd.cpp ----------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between Sanitizer run-time libraries and implements | ||
| 10 | // NetBSD-specific functions from sanitizer_libc.h. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_platform.h" | ||
| 14 | |||
| 15 | #if SANITIZER_NETBSD | ||
| 16 | |||
| 17 | #include "sanitizer_common.h" | ||
| 18 | #include "sanitizer_flags.h" | ||
| 19 | #include "sanitizer_getauxval.h" | ||
| 20 | #include "sanitizer_internal_defs.h" | ||
| 21 | #include "sanitizer_libc.h" | ||
| 22 | #include "sanitizer_linux.h" | ||
| 23 | #include "sanitizer_mutex.h" | ||
| 24 | #include "sanitizer_placement_new.h" | ||
| 25 | #include "sanitizer_procmaps.h" | ||
| 26 | |||
| 27 | #include <sys/param.h> | ||
| 28 | #include <sys/types.h> | ||
| 29 | |||
| 30 | #include <sys/exec.h> | ||
| 31 | #include <sys/mman.h> | ||
| 32 | #include <sys/ptrace.h> | ||
| 33 | #include <sys/resource.h> | ||
| 34 | #include <sys/stat.h> | ||
| 35 | #include <sys/syscall.h> | ||
| 36 | #include <sys/sysctl.h> | ||
| 37 | #include <sys/time.h> | ||
| 38 | |||
| 39 | #include <dlfcn.h> | ||
| 40 | #include <errno.h> | ||
| 41 | #include <fcntl.h> | ||
| 42 | #include <limits.h> | ||
| 43 | #include <link.h> | ||
| 44 | #include <lwp.h> | ||
| 45 | #include <pthread.h> | ||
| 46 | #include <sched.h> | ||
| 47 | #include <signal.h> | ||
| 48 | #include <ucontext.h> | ||
| 49 | #include <unistd.h> | ||
| 50 | |||
| 51 | extern "C" void *__mmap(void *, size_t, int, int, int, int, | ||
| 52 | off_t) SANITIZER_WEAK_ATTRIBUTE; | ||
| 53 | extern "C" int __sysctl(const int *, unsigned int, void *, size_t *, | ||
| 54 | const void *, size_t) SANITIZER_WEAK_ATTRIBUTE; | ||
| 55 | extern "C" int _sys_close(int) SANITIZER_WEAK_ATTRIBUTE; | ||
| 56 | extern "C" int _sys_open(const char *, int, ...) SANITIZER_WEAK_ATTRIBUTE; | ||
| 57 | extern "C" ssize_t _sys_read(int, void *, size_t) SANITIZER_WEAK_ATTRIBUTE; | ||
| 58 | extern "C" ssize_t _sys_write(int, const void *, | ||
| 59 | size_t) SANITIZER_WEAK_ATTRIBUTE; | ||
| 60 | extern "C" int __ftruncate(int, int, off_t) SANITIZER_WEAK_ATTRIBUTE; | ||
| 61 | extern "C" ssize_t _sys_readlink(const char *, char *, | ||
| 62 | size_t) SANITIZER_WEAK_ATTRIBUTE; | ||
| 63 | extern "C" int _sys_sched_yield() SANITIZER_WEAK_ATTRIBUTE; | ||
| 64 | extern "C" int _sys___nanosleep50(const void *, | ||
| 65 | void *) SANITIZER_WEAK_ATTRIBUTE; | ||
| 66 | extern "C" int _sys_execve(const char *, char *const[], | ||
| 67 | char *const[]) SANITIZER_WEAK_ATTRIBUTE; | ||
| 68 | extern "C" off_t __lseek(int, int, off_t, int) SANITIZER_WEAK_ATTRIBUTE; | ||
| 69 | extern "C" int __fork() SANITIZER_WEAK_ATTRIBUTE; | ||
| 70 | extern "C" int _sys___sigprocmask14(int, const void *, | ||
| 71 | void *) SANITIZER_WEAK_ATTRIBUTE; | ||
| 72 | extern "C" int _sys___wait450(int wpid, int *, int, | ||
| 73 | void *) SANITIZER_WEAK_ATTRIBUTE; | ||
| 74 | |||
| 75 | namespace __sanitizer { | ||
| 76 | |||
| 77 | static void *GetRealLibcAddress(const char *symbol) { | ||
| 78 | void *real = dlsym(RTLD_NEXT, symbol); | ||
| 79 | if (!real) | ||
| 80 | real = dlsym(RTLD_DEFAULT, symbol); | ||
| 81 | if (!real) { | ||
| 82 | Printf("GetRealLibcAddress failed for symbol=%s", symbol); | ||
| 83 | Die(); | ||
| 84 | } | ||
| 85 | return real; | ||
| 86 | } | ||
| 87 | |||
| 88 | #define _REAL(func, ...) real##_##func(__VA_ARGS__) | ||
| 89 | #define DEFINE__REAL(ret_type, func, ...) \ | ||
| 90 | static ret_type (*real_##func)(__VA_ARGS__) = NULL; \ | ||
| 91 | if (!real_##func) { \ | ||
| 92 | real_##func = (ret_type(*)(__VA_ARGS__))GetRealLibcAddress(#func); \ | ||
| 93 | } \ | ||
| 94 | CHECK(real_##func); | ||
| 95 | |||
| 96 | // --------------- sanitizer_libc.h | ||
| 97 | uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, | ||
| 98 | u64 offset) { | ||
| 99 | CHECK(&__mmap); | ||
| 100 | return (uptr)__mmap(addr, length, prot, flags, fd, 0, offset); | ||
| 101 | } | ||
| 102 | |||
| 103 | uptr internal_munmap(void *addr, uptr length) { | ||
| 104 | DEFINE__REAL(int, munmap, void *a, uptr b); | ||
| 105 | return _REAL(munmap, addr, length); | ||
| 106 | } | ||
| 107 | |||
| 108 | int internal_mprotect(void *addr, uptr length, int prot) { | ||
| 109 | DEFINE__REAL(int, mprotect, void *a, uptr b, int c); | ||
| 110 | return _REAL(mprotect, addr, length, prot); | ||
| 111 | } | ||
| 112 | |||
| 113 | uptr internal_close(fd_t fd) { | ||
| 114 | CHECK(&_sys_close); | ||
| 115 | return _sys_close(fd); | ||
| 116 | } | ||
| 117 | |||
| 118 | uptr internal_open(const char *filename, int flags) { | ||
| 119 | CHECK(&_sys_open); | ||
| 120 | return _sys_open(filename, flags); | ||
| 121 | } | ||
| 122 | |||
| 123 | uptr internal_open(const char *filename, int flags, u32 mode) { | ||
| 124 | CHECK(&_sys_open); | ||
| 125 | return _sys_open(filename, flags, mode); | ||
| 126 | } | ||
| 127 | |||
| 128 | uptr internal_read(fd_t fd, void *buf, uptr count) { | ||
| 129 | sptr res; | ||
| 130 | CHECK(&_sys_read); | ||
| 131 | HANDLE_EINTR(res, (sptr)_sys_read(fd, buf, (size_t)count)); | ||
| 132 | return res; | ||
| 133 | } | ||
| 134 | |||
| 135 | uptr internal_write(fd_t fd, const void *buf, uptr count) { | ||
| 136 | sptr res; | ||
| 137 | CHECK(&_sys_write); | ||
| 138 | HANDLE_EINTR(res, (sptr)_sys_write(fd, buf, count)); | ||
| 139 | return res; | ||
| 140 | } | ||
| 141 | |||
| 142 | uptr internal_ftruncate(fd_t fd, uptr size) { | ||
| 143 | sptr res; | ||
| 144 | CHECK(&__ftruncate); | ||
| 145 | HANDLE_EINTR(res, __ftruncate(fd, 0, (s64)size)); | ||
| 146 | return res; | ||
| 147 | } | ||
| 148 | |||
| 149 | uptr internal_stat(const char *path, void *buf) { | ||
| 150 | DEFINE__REAL(int, __stat50, const char *a, void *b); | ||
| 151 | return _REAL(__stat50, path, buf); | ||
| 152 | } | ||
| 153 | |||
| 154 | uptr internal_lstat(const char *path, void *buf) { | ||
| 155 | DEFINE__REAL(int, __lstat50, const char *a, void *b); | ||
| 156 | return _REAL(__lstat50, path, buf); | ||
| 157 | } | ||
| 158 | |||
| 159 | uptr internal_fstat(fd_t fd, void *buf) { | ||
| 160 | DEFINE__REAL(int, __fstat50, int a, void *b); | ||
| 161 | return _REAL(__fstat50, fd, buf); | ||
| 162 | } | ||
| 163 | |||
| 164 | uptr internal_filesize(fd_t fd) { | ||
| 165 | struct stat st; | ||
| 166 | if (internal_fstat(fd, &st)) | ||
| 167 | return -1; | ||
| 168 | return (uptr)st.st_size; | ||
| 169 | } | ||
| 170 | |||
| 171 | uptr internal_dup(int oldfd) { | ||
| 172 | DEFINE__REAL(int, dup, int a); | ||
| 173 | return _REAL(dup, oldfd); | ||
| 174 | } | ||
| 175 | |||
| 176 | uptr internal_dup2(int oldfd, int newfd) { | ||
| 177 | DEFINE__REAL(int, dup2, int a, int b); | ||
| 178 | return _REAL(dup2, oldfd, newfd); | ||
| 179 | } | ||
| 180 | |||
| 181 | uptr internal_readlink(const char *path, char *buf, uptr bufsize) { | ||
| 182 | CHECK(&_sys_readlink); | ||
| 183 | return (uptr)_sys_readlink(path, buf, bufsize); | ||
| 184 | } | ||
| 185 | |||
| 186 | uptr internal_unlink(const char *path) { | ||
| 187 | DEFINE__REAL(int, unlink, const char *a); | ||
| 188 | return _REAL(unlink, path); | ||
| 189 | } | ||
| 190 | |||
| 191 | uptr internal_rename(const char *oldpath, const char *newpath) { | ||
| 192 | DEFINE__REAL(int, rename, const char *a, const char *b); | ||
| 193 | return _REAL(rename, oldpath, newpath); | ||
| 194 | } | ||
| 195 | |||
| 196 | uptr internal_sched_yield() { | ||
| 197 | CHECK(&_sys_sched_yield); | ||
| 198 | return _sys_sched_yield(); | ||
| 199 | } | ||
| 200 | |||
| 201 | void internal__exit(int exitcode) { | ||
| 202 | DEFINE__REAL(void, _exit, int a); | ||
| 203 | _REAL(_exit, exitcode); | ||
| 204 | Die(); // Unreachable. | ||
| 205 | } | ||
| 206 | |||
| 207 | unsigned int internal_sleep(unsigned int seconds) { | ||
| 208 | struct timespec ts; | ||
| 209 | ts.tv_sec = seconds; | ||
| 210 | ts.tv_nsec = 0; | ||
| 211 | CHECK(&_sys___nanosleep50); | ||
| 212 | int res = _sys___nanosleep50(&ts, &ts); | ||
| 213 | if (res) | ||
| 214 | return ts.tv_sec; | ||
| 215 | return 0; | ||
| 216 | } | ||
| 217 | |||
| 218 | uptr internal_execve(const char *filename, char *const argv[], | ||
| 219 | char *const envp[]) { | ||
| 220 | CHECK(&_sys_execve); | ||
| 221 | return _sys_execve(filename, argv, envp); | ||
| 222 | } | ||
| 223 | |||
| 224 | tid_t GetTid() { | ||
| 225 | DEFINE__REAL(int, _lwp_self); | ||
| 226 | return _REAL(_lwp_self); | ||
| 227 | } | ||
| 228 | |||
| 229 | int TgKill(pid_t pid, tid_t tid, int sig) { | ||
| 230 | DEFINE__REAL(int, _lwp_kill, int a, int b); | ||
| 231 | (void)pid; | ||
| 232 | return _REAL(_lwp_kill, tid, sig); | ||
| 233 | } | ||
| 234 | |||
| 235 | u64 NanoTime() { | ||
| 236 | timeval tv; | ||
| 237 | DEFINE__REAL(int, __gettimeofday50, void *a, void *b); | ||
| 238 | internal_memset(&tv, 0, sizeof(tv)); | ||
| 239 | _REAL(__gettimeofday50, &tv, 0); | ||
| 240 | return (u64)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000; | ||
| 241 | } | ||
| 242 | |||
| 243 | uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { | ||
| 244 | DEFINE__REAL(int, __clock_gettime50, __sanitizer_clockid_t a, void *b); | ||
| 245 | return _REAL(__clock_gettime50, clk_id, tp); | ||
| 246 | } | ||
| 247 | |||
| 248 | uptr internal_ptrace(int request, int pid, void *addr, int data) { | ||
| 249 | DEFINE__REAL(int, ptrace, int a, int b, void *c, int d); | ||
| 250 | return _REAL(ptrace, request, pid, addr, data); | ||
| 251 | } | ||
| 252 | |||
| 253 | uptr internal_waitpid(int pid, int *status, int options) { | ||
| 254 | CHECK(&_sys___wait450); | ||
| 255 | return _sys___wait450(pid, status, options, 0 /* rusage */); | ||
| 256 | } | ||
| 257 | |||
| 258 | uptr internal_getpid() { | ||
| 259 | DEFINE__REAL(int, getpid); | ||
| 260 | return _REAL(getpid); | ||
| 261 | } | ||
| 262 | |||
| 263 | uptr internal_getppid() { | ||
| 264 | DEFINE__REAL(int, getppid); | ||
| 265 | return _REAL(getppid); | ||
| 266 | } | ||
| 267 | |||
| 268 | int internal_dlinfo(void *handle, int request, void *p) { | ||
| 269 | DEFINE__REAL(int, dlinfo, void *a, int b, void *c); | ||
| 270 | return _REAL(dlinfo, handle, request, p); | ||
| 271 | } | ||
| 272 | |||
| 273 | uptr internal_getdents(fd_t fd, void *dirp, unsigned int count) { | ||
| 274 | DEFINE__REAL(int, __getdents30, int a, void *b, size_t c); | ||
| 275 | return _REAL(__getdents30, fd, dirp, count); | ||
| 276 | } | ||
| 277 | |||
| 278 | uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { | ||
| 279 | CHECK(&__lseek); | ||
| 280 | return __lseek(fd, 0, offset, whence); | ||
| 281 | } | ||
| 282 | |||
| 283 | uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { | ||
| 284 | Printf("internal_prctl not implemented for NetBSD"); | ||
| 285 | Die(); | ||
| 286 | return 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | uptr internal_sigaltstack(const void *ss, void *oss) { | ||
| 290 | DEFINE__REAL(int, __sigaltstack14, const void *a, void *b); | ||
| 291 | return _REAL(__sigaltstack14, ss, oss); | ||
| 292 | } | ||
| 293 | |||
| 294 | int internal_fork() { | ||
| 295 | CHECK(&__fork); | ||
| 296 | return __fork(); | ||
| 297 | } | ||
| 298 | |||
| 299 | int internal_sysctl(const int *name, unsigned int namelen, void *oldp, | ||
| 300 | uptr *oldlenp, const void *newp, uptr newlen) { | ||
| 301 | CHECK(&__sysctl); | ||
| 302 | return __sysctl(name, namelen, oldp, (size_t *)oldlenp, newp, (size_t)newlen); | ||
| 303 | } | ||
| 304 | |||
| 305 | int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, | ||
| 306 | const void *newp, uptr newlen) { | ||
| 307 | DEFINE__REAL(int, sysctlbyname, const char *a, void *b, size_t *c, | ||
| 308 | const void *d, size_t e); | ||
| 309 | return _REAL(sysctlbyname, sname, oldp, (size_t *)oldlenp, newp, | ||
| 310 | (size_t)newlen); | ||
| 311 | } | ||
| 312 | |||
| 313 | uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, | ||
| 314 | __sanitizer_sigset_t *oldset) { | ||
| 315 | CHECK(&_sys___sigprocmask14); | ||
| 316 | return _sys___sigprocmask14(how, set, oldset); | ||
| 317 | } | ||
| 318 | |||
| 319 | void internal_sigfillset(__sanitizer_sigset_t *set) { | ||
| 320 | DEFINE__REAL(int, __sigfillset14, const void *a); | ||
| 321 | (void)_REAL(__sigfillset14, set); | ||
| 322 | } | ||
| 323 | |||
| 324 | void internal_sigemptyset(__sanitizer_sigset_t *set) { | ||
| 325 | DEFINE__REAL(int, __sigemptyset14, const void *a); | ||
| 326 | (void)_REAL(__sigemptyset14, set); | ||
| 327 | } | ||
| 328 | |||
| 329 | void internal_sigdelset(__sanitizer_sigset_t *set, int signo) { | ||
| 330 | DEFINE__REAL(int, __sigdelset14, const void *a, int b); | ||
| 331 | (void)_REAL(__sigdelset14, set, signo); | ||
| 332 | } | ||
| 333 | |||
| 334 | uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, | ||
| 335 | void *arg) { | ||
| 336 | DEFINE__REAL(int, clone, int (*a)(void *b), void *c, int d, void *e); | ||
| 337 | |||
| 338 | return _REAL(clone, fn, child_stack, flags, arg); | ||
| 339 | } | ||
| 340 | |||
| 341 | } // namespace __sanitizer | ||
| 342 | |||
| 343 | #endif | ||
lib/tsan/sanitizer_common/sanitizer_openbsd.cpp created+115| ... | @@ -0,0 +1,115 @@ | ||
| 1 | //===-- sanitizer_openbsd.cpp ---------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between various sanitizers' runtime libraries and | ||
| 10 | // implements Solaris-specific functions. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_platform.h" | ||
| 14 | #if SANITIZER_OPENBSD | ||
| 15 | |||
| 16 | #include <stdio.h> | ||
| 17 | |||
| 18 | #include "sanitizer_common.h" | ||
| 19 | #include "sanitizer_flags.h" | ||
| 20 | #include "sanitizer_internal_defs.h" | ||
| 21 | #include "sanitizer_libc.h" | ||
| 22 | #include "sanitizer_placement_new.h" | ||
| 23 | #include "sanitizer_platform_limits_posix.h" | ||
| 24 | #include "sanitizer_procmaps.h" | ||
| 25 | |||
| 26 | #include <errno.h> | ||
| 27 | #include <fcntl.h> | ||
| 28 | #include <limits.h> | ||
| 29 | #include <pthread.h> | ||
| 30 | #include <sched.h> | ||
| 31 | #include <signal.h> | ||
| 32 | #include <stdio.h> | ||
| 33 | #include <stdlib.h> | ||
| 34 | #include <sys/mman.h> | ||
| 35 | #include <sys/shm.h> | ||
| 36 | #include <sys/sysctl.h> | ||
| 37 | #include <sys/types.h> | ||
| 38 | #include <unistd.h> | ||
| 39 | |||
| 40 | extern char **environ; | ||
| 41 | |||
| 42 | namespace __sanitizer { | ||
| 43 | |||
| 44 | uptr internal_mmap(void *addr, size_t length, int prot, int flags, int fd, | ||
| 45 | u64 offset) { | ||
| 46 | return (uptr)mmap(addr, length, prot, flags, fd, offset); | ||
| 47 | } | ||
| 48 | |||
| 49 | uptr internal_munmap(void *addr, uptr length) { return munmap(addr, length); } | ||
| 50 | |||
| 51 | int internal_mprotect(void *addr, uptr length, int prot) { | ||
| 52 | return mprotect(addr, length, prot); | ||
| 53 | } | ||
| 54 | |||
| 55 | int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, | ||
| 56 | const void *newp, uptr newlen) { | ||
| 57 | Printf("internal_sysctlbyname not implemented for OpenBSD"); | ||
| 58 | Die(); | ||
| 59 | return 0; | ||
| 60 | } | ||
| 61 | |||
| 62 | uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { | ||
| 63 | // On OpenBSD we cannot get the full path | ||
| 64 | struct kinfo_proc kp; | ||
| 65 | uptr kl; | ||
| 66 | const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()}; | ||
| 67 | if (internal_sysctl(Mib, ARRAY_SIZE(Mib), &kp, &kl, NULL, 0) != -1) | ||
| 68 | return internal_snprintf(buf, | ||
| 69 | (KI_MAXCOMLEN < buf_len ? KI_MAXCOMLEN : buf_len), | ||
| 70 | "%s", kp.p_comm); | ||
| 71 | return (uptr)0; | ||
| 72 | } | ||
| 73 | |||
| 74 | static void GetArgsAndEnv(char ***argv, char ***envp) { | ||
| 75 | uptr nargv; | ||
| 76 | uptr nenv; | ||
| 77 | int argvmib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV}; | ||
| 78 | int envmib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ENV}; | ||
| 79 | if (internal_sysctl(argvmib, 4, NULL, &nargv, NULL, 0) == -1) { | ||
| 80 | Printf("sysctl KERN_PROC_NARGV failed\n"); | ||
| 81 | Die(); | ||
| 82 | } | ||
| 83 | if (internal_sysctl(envmib, 4, NULL, &nenv, NULL, 0) == -1) { | ||
| 84 | Printf("sysctl KERN_PROC_NENV failed\n"); | ||
| 85 | Die(); | ||
| 86 | } | ||
| 87 | if (internal_sysctl(argvmib, 4, &argv, &nargv, NULL, 0) == -1) { | ||
| 88 | Printf("sysctl KERN_PROC_ARGV failed\n"); | ||
| 89 | Die(); | ||
| 90 | } | ||
| 91 | if (internal_sysctl(envmib, 4, &envp, &nenv, NULL, 0) == -1) { | ||
| 92 | Printf("sysctl KERN_PROC_ENV failed\n"); | ||
| 93 | Die(); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | char **GetArgv() { | ||
| 98 | char **argv, **envp; | ||
| 99 | GetArgsAndEnv(&argv, &envp); | ||
| 100 | return argv; | ||
| 101 | } | ||
| 102 | |||
| 103 | char **GetEnviron() { | ||
| 104 | char **argv, **envp; | ||
| 105 | GetArgsAndEnv(&argv, &envp); | ||
| 106 | return envp; | ||
| 107 | } | ||
| 108 | |||
| 109 | void ReExec() { | ||
| 110 | UNIMPLEMENTED(); | ||
| 111 | } | ||
| 112 | |||
| 113 | } // namespace __sanitizer | ||
| 114 | |||
| 115 | #endif // SANITIZER_OPENBSD | ||
lib/tsan/sanitizer_common/sanitizer_persistent_allocator.cpp created+18| ... | @@ -0,0 +1,18 @@ | ||
| 1 | //===-- sanitizer_persistent_allocator.cpp ----------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer | ||
| 10 | // run-time libraries. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #include "sanitizer_persistent_allocator.h" | ||
| 13 | |||
| 14 | namespace __sanitizer { | ||
| 15 | |||
| 16 | PersistentAllocator thePersistentAllocator; | ||
| 17 | |||
| 18 | } // namespace __sanitizer | ||
lib/tsan/sanitizer_common/sanitizer_persistent_allocator.h created+71| ... | @@ -0,0 +1,71 @@ | ||
| 1 | //===-- sanitizer_persistent_allocator.h ------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // A fast memory allocator that does not support free() nor realloc(). | ||
| 10 | // All allocations are forever. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef SANITIZER_PERSISTENT_ALLOCATOR_H | ||
| 14 | #define SANITIZER_PERSISTENT_ALLOCATOR_H | ||
| 15 | |||
| 16 | #include "sanitizer_internal_defs.h" | ||
| 17 | #include "sanitizer_mutex.h" | ||
| 18 | #include "sanitizer_atomic.h" | ||
| 19 | #include "sanitizer_common.h" | ||
| 20 | |||
| 21 | namespace __sanitizer { | ||
| 22 | |||
| 23 | class PersistentAllocator { | ||
| 24 | public: | ||
| 25 | void *alloc(uptr size); | ||
| 26 | |||
| 27 | private: | ||
| 28 | void *tryAlloc(uptr size); | ||
| 29 | StaticSpinMutex mtx; // Protects alloc of new blocks for region allocator. | ||
| 30 | atomic_uintptr_t region_pos; // Region allocator for Node's. | ||
| 31 | atomic_uintptr_t region_end; | ||
| 32 | }; | ||
| 33 | |||
| 34 | inline void *PersistentAllocator::tryAlloc(uptr size) { | ||
| 35 | // Optimisic lock-free allocation, essentially try to bump the region ptr. | ||
| 36 | for (;;) { | ||
| 37 | uptr cmp = atomic_load(&region_pos, memory_order_acquire); | ||
| 38 | uptr end = atomic_load(&region_end, memory_order_acquire); | ||
| 39 | if (cmp == 0 || cmp + size > end) return nullptr; | ||
| 40 | if (atomic_compare_exchange_weak(&region_pos, &cmp, cmp + size, | ||
| 41 | memory_order_acquire)) | ||
| 42 | return (void *)cmp; | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | inline void *PersistentAllocator::alloc(uptr size) { | ||
| 47 | // First, try to allocate optimisitically. | ||
| 48 | void *s = tryAlloc(size); | ||
| 49 | if (s) return s; | ||
| 50 | // If failed, lock, retry and alloc new superblock. | ||
| 51 | SpinMutexLock l(&mtx); | ||
| 52 | for (;;) { | ||
| 53 | s = tryAlloc(size); | ||
| 54 | if (s) return s; | ||
| 55 | atomic_store(&region_pos, 0, memory_order_relaxed); | ||
| 56 | uptr allocsz = 64 * 1024; | ||
| 57 | if (allocsz < size) allocsz = size; | ||
| 58 | uptr mem = (uptr)MmapOrDie(allocsz, "stack depot"); | ||
| 59 | atomic_store(&region_end, mem + allocsz, memory_order_release); | ||
| 60 | atomic_store(&region_pos, mem, memory_order_release); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | extern PersistentAllocator thePersistentAllocator; | ||
| 65 | inline void *PersistentAlloc(uptr sz) { | ||
| 66 | return thePersistentAllocator.alloc(sz); | ||
| 67 | } | ||
| 68 | |||
| 69 | } // namespace __sanitizer | ||
| 70 | |||
| 71 | #endif // SANITIZER_PERSISTENT_ALLOCATOR_H | ||
lib/tsan/sanitizer_common/sanitizer_placement_new.h created+24| ... | @@ -0,0 +1,24 @@ | ||
| 1 | //===-- sanitizer_placement_new.h -------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer | ||
| 10 | // run-time libraries. | ||
| 11 | // | ||
| 12 | // The file provides 'placement new'. | ||
| 13 | // Do not include it into header files, only into source files. | ||
| 14 | //===----------------------------------------------------------------------===// | ||
| 15 | #ifndef SANITIZER_PLACEMENT_NEW_H | ||
| 16 | #define SANITIZER_PLACEMENT_NEW_H | ||
| 17 | |||
| 18 | #include "sanitizer_internal_defs.h" | ||
| 19 | |||
| 20 | inline void *operator new(__sanitizer::operator_new_size_type sz, void *p) { | ||
| 21 | return p; | ||
| 22 | } | ||
| 23 | |||
| 24 | #endif // SANITIZER_PLACEMENT_NEW_H | ||
lib/tsan/sanitizer_common/sanitizer_platform.h created+364| ... | @@ -0,0 +1,364 @@ | ||
| 1 | //===-- sanitizer_platform.h ------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Common platform macros. | ||
| 10 | //===----------------------------------------------------------------------===// | ||
| 11 | |||
| 12 | #ifndef SANITIZER_PLATFORM_H | ||
| 13 | #define SANITIZER_PLATFORM_H | ||
| 14 | |||
| 15 | #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ | ||
| 16 | !defined(__OpenBSD__) && !defined(__APPLE__) && !defined(_WIN32) && \ | ||
| 17 | !defined(__Fuchsia__) && !defined(__rtems__) && \ | ||
| 18 | !(defined(__sun__) && defined(__svr4__)) | ||
| 19 | # error "This operating system is not supported" | ||
| 20 | #endif | ||
| 21 | |||
| 22 | #if defined(__linux__) | ||
| 23 | # define SANITIZER_LINUX 1 | ||
| 24 | #else | ||
| 25 | # define SANITIZER_LINUX 0 | ||
| 26 | #endif | ||
| 27 | |||
| 28 | #if defined(__FreeBSD__) | ||
| 29 | # define SANITIZER_FREEBSD 1 | ||
| 30 | #else | ||
| 31 | # define SANITIZER_FREEBSD 0 | ||
| 32 | #endif | ||
| 33 | |||
| 34 | #if defined(__NetBSD__) | ||
| 35 | # define SANITIZER_NETBSD 1 | ||
| 36 | #else | ||
| 37 | # define SANITIZER_NETBSD 0 | ||
| 38 | #endif | ||
| 39 | |||
| 40 | #if defined(__OpenBSD__) | ||
| 41 | # define SANITIZER_OPENBSD 1 | ||
| 42 | #else | ||
| 43 | # define SANITIZER_OPENBSD 0 | ||
| 44 | #endif | ||
| 45 | |||
| 46 | #if defined(__sun__) && defined(__svr4__) | ||
| 47 | # define SANITIZER_SOLARIS 1 | ||
| 48 | #else | ||
| 49 | # define SANITIZER_SOLARIS 0 | ||
| 50 | #endif | ||
| 51 | |||
| 52 | #if defined(__APPLE__) | ||
| 53 | # define SANITIZER_MAC 1 | ||
| 54 | # include <TargetConditionals.h> | ||
| 55 | # if TARGET_OS_IPHONE | ||
| 56 | # define SANITIZER_IOS 1 | ||
| 57 | # else | ||
| 58 | # define SANITIZER_IOS 0 | ||
| 59 | # endif | ||
| 60 | # if TARGET_OS_SIMULATOR | ||
| 61 | # define SANITIZER_IOSSIM 1 | ||
| 62 | # else | ||
| 63 | # define SANITIZER_IOSSIM 0 | ||
| 64 | # endif | ||
| 65 | #else | ||
| 66 | # define SANITIZER_MAC 0 | ||
| 67 | # define SANITIZER_IOS 0 | ||
| 68 | # define SANITIZER_IOSSIM 0 | ||
| 69 | #endif | ||
| 70 | |||
| 71 | #if defined(__APPLE__) && TARGET_OS_IPHONE && TARGET_OS_WATCH | ||
| 72 | # define SANITIZER_WATCHOS 1 | ||
| 73 | #else | ||
| 74 | # define SANITIZER_WATCHOS 0 | ||
| 75 | #endif | ||
| 76 | |||
| 77 | #if defined(__APPLE__) && TARGET_OS_IPHONE && TARGET_OS_TV | ||
| 78 | # define SANITIZER_TVOS 1 | ||
| 79 | #else | ||
| 80 | # define SANITIZER_TVOS 0 | ||
| 81 | #endif | ||
| 82 | |||
| 83 | #if defined(_WIN32) | ||
| 84 | # define SANITIZER_WINDOWS 1 | ||
| 85 | #else | ||
| 86 | # define SANITIZER_WINDOWS 0 | ||
| 87 | #endif | ||
| 88 | |||
| 89 | #if defined(_WIN64) | ||
| 90 | # define SANITIZER_WINDOWS64 1 | ||
| 91 | #else | ||
| 92 | # define SANITIZER_WINDOWS64 0 | ||
| 93 | #endif | ||
| 94 | |||
| 95 | #if defined(__ANDROID__) | ||
| 96 | # define SANITIZER_ANDROID 1 | ||
| 97 | #else | ||
| 98 | # define SANITIZER_ANDROID 0 | ||
| 99 | #endif | ||
| 100 | |||
| 101 | #if defined(__Fuchsia__) | ||
| 102 | # define SANITIZER_FUCHSIA 1 | ||
| 103 | #else | ||
| 104 | # define SANITIZER_FUCHSIA 0 | ||
| 105 | #endif | ||
| 106 | |||
| 107 | #if defined(__rtems__) | ||
| 108 | # define SANITIZER_RTEMS 1 | ||
| 109 | #else | ||
| 110 | # define SANITIZER_RTEMS 0 | ||
| 111 | #endif | ||
| 112 | |||
| 113 | #define SANITIZER_POSIX \ | ||
| 114 | (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \ | ||
| 115 | SANITIZER_NETBSD || SANITIZER_OPENBSD || SANITIZER_SOLARIS) | ||
| 116 | |||
| 117 | #if __LP64__ || defined(_WIN64) | ||
| 118 | # define SANITIZER_WORDSIZE 64 | ||
| 119 | #else | ||
| 120 | # define SANITIZER_WORDSIZE 32 | ||
| 121 | #endif | ||
| 122 | |||
| 123 | #if SANITIZER_WORDSIZE == 64 | ||
| 124 | # define FIRST_32_SECOND_64(a, b) (b) | ||
| 125 | #else | ||
| 126 | # define FIRST_32_SECOND_64(a, b) (a) | ||
| 127 | #endif | ||
| 128 | |||
| 129 | #if defined(__x86_64__) && !defined(_LP64) | ||
| 130 | # define SANITIZER_X32 1 | ||
| 131 | #else | ||
| 132 | # define SANITIZER_X32 0 | ||
| 133 | #endif | ||
| 134 | |||
| 135 | #if defined(__i386__) || defined(_M_IX86) | ||
| 136 | # define SANITIZER_I386 1 | ||
| 137 | #else | ||
| 138 | # define SANITIZER_I386 0 | ||
| 139 | #endif | ||
| 140 | |||
| 141 | #if defined(__mips__) | ||
| 142 | # define SANITIZER_MIPS 1 | ||
| 143 | # if defined(__mips64) | ||
| 144 | # define SANITIZER_MIPS32 0 | ||
| 145 | # define SANITIZER_MIPS64 1 | ||
| 146 | # else | ||
| 147 | # define SANITIZER_MIPS32 1 | ||
| 148 | # define SANITIZER_MIPS64 0 | ||
| 149 | # endif | ||
| 150 | #else | ||
| 151 | # define SANITIZER_MIPS 0 | ||
| 152 | # define SANITIZER_MIPS32 0 | ||
| 153 | # define SANITIZER_MIPS64 0 | ||
| 154 | #endif | ||
| 155 | |||
| 156 | #if defined(__s390__) | ||
| 157 | # define SANITIZER_S390 1 | ||
| 158 | # if defined(__s390x__) | ||
| 159 | # define SANITIZER_S390_31 0 | ||
| 160 | # define SANITIZER_S390_64 1 | ||
| 161 | # else | ||
| 162 | # define SANITIZER_S390_31 1 | ||
| 163 | # define SANITIZER_S390_64 0 | ||
| 164 | # endif | ||
| 165 | #else | ||
| 166 | # define SANITIZER_S390 0 | ||
| 167 | # define SANITIZER_S390_31 0 | ||
| 168 | # define SANITIZER_S390_64 0 | ||
| 169 | #endif | ||
| 170 | |||
| 171 | #if defined(__powerpc__) | ||
| 172 | # define SANITIZER_PPC 1 | ||
| 173 | # if defined(__powerpc64__) | ||
| 174 | # define SANITIZER_PPC32 0 | ||
| 175 | # define SANITIZER_PPC64 1 | ||
| 176 | // 64-bit PPC has two ABIs (v1 and v2). The old powerpc64 target is | ||
| 177 | // big-endian, and uses v1 ABI (known for its function descriptors), | ||
| 178 | // while the new powerpc64le target is little-endian and uses v2. | ||
| 179 | // In theory, you could convince gcc to compile for their evil twins | ||
| 180 | // (eg. big-endian v2), but you won't find such combinations in the wild | ||
| 181 | // (it'd require bootstrapping a whole system, which would be quite painful | ||
| 182 | // - there's no target triple for that). LLVM doesn't support them either. | ||
| 183 | # if _CALL_ELF == 2 | ||
| 184 | # define SANITIZER_PPC64V1 0 | ||
| 185 | # define SANITIZER_PPC64V2 1 | ||
| 186 | # else | ||
| 187 | # define SANITIZER_PPC64V1 1 | ||
| 188 | # define SANITIZER_PPC64V2 0 | ||
| 189 | # endif | ||
| 190 | # else | ||
| 191 | # define SANITIZER_PPC32 1 | ||
| 192 | # define SANITIZER_PPC64 0 | ||
| 193 | # define SANITIZER_PPC64V1 0 | ||
| 194 | # define SANITIZER_PPC64V2 0 | ||
| 195 | # endif | ||
| 196 | #else | ||
| 197 | # define SANITIZER_PPC 0 | ||
| 198 | # define SANITIZER_PPC32 0 | ||
| 199 | # define SANITIZER_PPC64 0 | ||
| 200 | # define SANITIZER_PPC64V1 0 | ||
| 201 | # define SANITIZER_PPC64V2 0 | ||
| 202 | #endif | ||
| 203 | |||
| 204 | #if defined(__arm__) | ||
| 205 | # define SANITIZER_ARM 1 | ||
| 206 | #else | ||
| 207 | # define SANITIZER_ARM 0 | ||
| 208 | #endif | ||
| 209 | |||
| 210 | #if SANITIZER_SOLARIS && SANITIZER_WORDSIZE == 32 | ||
| 211 | # define SANITIZER_SOLARIS32 1 | ||
| 212 | #else | ||
| 213 | # define SANITIZER_SOLARIS32 0 | ||
| 214 | #endif | ||
| 215 | |||
| 216 | #if defined(__myriad2__) | ||
| 217 | # define SANITIZER_MYRIAD2 1 | ||
| 218 | #else | ||
| 219 | # define SANITIZER_MYRIAD2 0 | ||
| 220 | #endif | ||
| 221 | |||
| 222 | // By default we allow to use SizeClassAllocator64 on 64-bit platform. | ||
| 223 | // But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64 | ||
| 224 | // does not work well and we need to fallback to SizeClassAllocator32. | ||
| 225 | // For such platforms build this code with -DSANITIZER_CAN_USE_ALLOCATOR64=0 or | ||
| 226 | // change the definition of SANITIZER_CAN_USE_ALLOCATOR64 here. | ||
| 227 | #ifndef SANITIZER_CAN_USE_ALLOCATOR64 | ||
| 228 | # if (SANITIZER_ANDROID && defined(__aarch64__)) || SANITIZER_FUCHSIA | ||
| 229 | # define SANITIZER_CAN_USE_ALLOCATOR64 1 | ||
| 230 | # elif defined(__mips64) || defined(__aarch64__) | ||
| 231 | # define SANITIZER_CAN_USE_ALLOCATOR64 0 | ||
| 232 | # else | ||
| 233 | # define SANITIZER_CAN_USE_ALLOCATOR64 (SANITIZER_WORDSIZE == 64) | ||
| 234 | # endif | ||
| 235 | #endif | ||
| 236 | |||
| 237 | // The range of addresses which can be returned my mmap. | ||
| 238 | // FIXME: this value should be different on different platforms. Larger values | ||
| 239 | // will still work but will consume more memory for TwoLevelByteMap. | ||
| 240 | #if defined(__mips__) | ||
| 241 | # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 40) | ||
| 242 | #elif defined(__aarch64__) | ||
| 243 | # if SANITIZER_MAC | ||
| 244 | // Darwin iOS/ARM64 has a 36-bit VMA, 64GiB VM | ||
| 245 | # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 36) | ||
| 246 | # else | ||
| 247 | # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 48) | ||
| 248 | # endif | ||
| 249 | #elif defined(__sparc__) | ||
| 250 | #define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 52) | ||
| 251 | #else | ||
| 252 | # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47) | ||
| 253 | #endif | ||
| 254 | |||
| 255 | // Whether the addresses are sign-extended from the VMA range to the word. | ||
| 256 | // The SPARC64 Linux port implements this to split the VMA space into two | ||
| 257 | // non-contiguous halves with a huge hole in the middle. | ||
| 258 | #if defined(__sparc__) && SANITIZER_WORDSIZE == 64 | ||
| 259 | #define SANITIZER_SIGN_EXTENDED_ADDRESSES 1 | ||
| 260 | #else | ||
| 261 | #define SANITIZER_SIGN_EXTENDED_ADDRESSES 0 | ||
| 262 | #endif | ||
| 263 | |||
| 264 | // The AArch64 and RISC-V linux ports use the canonical syscall set as | ||
| 265 | // mandated by the upstream linux community for all new ports. Other ports | ||
| 266 | // may still use legacy syscalls. | ||
| 267 | #ifndef SANITIZER_USES_CANONICAL_LINUX_SYSCALLS | ||
| 268 | # if (defined(__aarch64__) || defined(__riscv)) && SANITIZER_LINUX | ||
| 269 | # define SANITIZER_USES_CANONICAL_LINUX_SYSCALLS 1 | ||
| 270 | # else | ||
| 271 | # define SANITIZER_USES_CANONICAL_LINUX_SYSCALLS 0 | ||
| 272 | # endif | ||
| 273 | #endif | ||
| 274 | |||
| 275 | // udi16 syscalls can only be used when the following conditions are | ||
| 276 | // met: | ||
| 277 | // * target is one of arm32, x86-32, sparc32, sh or m68k | ||
| 278 | // * libc version is libc5, glibc-2.0, glibc-2.1 or glibc-2.2 to 2.15 | ||
| 279 | // built against > linux-2.2 kernel headers | ||
| 280 | // Since we don't want to include libc headers here, we check the | ||
| 281 | // target only. | ||
| 282 | #if defined(__arm__) || SANITIZER_X32 || defined(__sparc__) | ||
| 283 | #define SANITIZER_USES_UID16_SYSCALLS 1 | ||
| 284 | #else | ||
| 285 | #define SANITIZER_USES_UID16_SYSCALLS 0 | ||
| 286 | #endif | ||
| 287 | |||
| 288 | #if defined(__mips__) | ||
| 289 | # define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 10) | ||
| 290 | #else | ||
| 291 | # define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 12) | ||
| 292 | #endif | ||
| 293 | |||
| 294 | /// \macro MSC_PREREQ | ||
| 295 | /// \brief Is the compiler MSVC of at least the specified version? | ||
| 296 | /// The common \param version values to check for are: | ||
| 297 | /// * 1800: Microsoft Visual Studio 2013 / 12.0 | ||
| 298 | /// * 1900: Microsoft Visual Studio 2015 / 14.0 | ||
| 299 | #ifdef _MSC_VER | ||
| 300 | # define MSC_PREREQ(version) (_MSC_VER >= (version)) | ||
| 301 | #else | ||
| 302 | # define MSC_PREREQ(version) 0 | ||
| 303 | #endif | ||
| 304 | |||
| 305 | #if SANITIZER_MAC && !(defined(__arm64__) && SANITIZER_IOS) | ||
| 306 | # define SANITIZER_NON_UNIQUE_TYPEINFO 0 | ||
| 307 | #else | ||
| 308 | # define SANITIZER_NON_UNIQUE_TYPEINFO 1 | ||
| 309 | #endif | ||
| 310 | |||
| 311 | // On linux, some architectures had an ABI transition from 64-bit long double | ||
| 312 | // (ie. same as double) to 128-bit long double. On those, glibc symbols | ||
| 313 | // involving long doubles come in two versions, and we need to pass the | ||
| 314 | // correct one to dlvsym when intercepting them. | ||
| 315 | #if SANITIZER_LINUX && (SANITIZER_S390 || SANITIZER_PPC32 || SANITIZER_PPC64V1) | ||
| 316 | #define SANITIZER_NLDBL_VERSION "GLIBC_2.4" | ||
| 317 | #endif | ||
| 318 | |||
| 319 | #if SANITIZER_GO == 0 | ||
| 320 | # define SANITIZER_GO 0 | ||
| 321 | #endif | ||
| 322 | |||
| 323 | // On PowerPC and ARM Thumb, calling pthread_exit() causes LSan to detect leaks. | ||
| 324 | // pthread_exit() performs unwinding that leads to dlopen'ing libgcc_s.so. | ||
| 325 | // dlopen mallocs "libgcc_s.so" string which confuses LSan, it fails to realize | ||
| 326 | // that this allocation happens in dynamic linker and should be ignored. | ||
| 327 | #if SANITIZER_PPC || defined(__thumb__) | ||
| 328 | # define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 1 | ||
| 329 | #else | ||
| 330 | # define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 0 | ||
| 331 | #endif | ||
| 332 | |||
| 333 | #if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD || \ | ||
| 334 | SANITIZER_OPENBSD || SANITIZER_SOLARIS | ||
| 335 | # define SANITIZER_MADVISE_DONTNEED MADV_FREE | ||
| 336 | #else | ||
| 337 | # define SANITIZER_MADVISE_DONTNEED MADV_DONTNEED | ||
| 338 | #endif | ||
| 339 | |||
| 340 | // Older gcc have issues aligning to a constexpr, and require an integer. | ||
| 341 | // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56859 among others. | ||
| 342 | #if defined(__powerpc__) || defined(__powerpc64__) | ||
| 343 | # define SANITIZER_CACHE_LINE_SIZE 128 | ||
| 344 | #else | ||
| 345 | # define SANITIZER_CACHE_LINE_SIZE 64 | ||
| 346 | #endif | ||
| 347 | |||
| 348 | // Enable offline markup symbolizer for Fuchsia and RTEMS. | ||
| 349 | #if SANITIZER_FUCHSIA || SANITIZER_RTEMS | ||
| 350 | #define SANITIZER_SYMBOLIZER_MARKUP 1 | ||
| 351 | #else | ||
| 352 | #define SANITIZER_SYMBOLIZER_MARKUP 0 | ||
| 353 | #endif | ||
| 354 | |||
| 355 | // Enable ability to support sanitizer initialization that is | ||
| 356 | // compatible with the sanitizer library being loaded via | ||
| 357 | // `dlopen()`. | ||
| 358 | #if SANITIZER_MAC | ||
| 359 | #define SANITIZER_SUPPORTS_INIT_FOR_DLOPEN 1 | ||
| 360 | #else | ||
| 361 | #define SANITIZER_SUPPORTS_INIT_FOR_DLOPEN 0 | ||
| 362 | #endif | ||
| 363 | |||
| 364 | #endif // SANITIZER_PLATFORM_H | ||
lib/tsan/sanitizer_common/sanitizer_platform_interceptors.h created+609| ... | @@ -0,0 +1,609 @@ | ||
| 1 | //===-- sanitizer_platform_interceptors.h -----------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file defines macro telling whether sanitizer tools can/should intercept | ||
| 10 | // given library functions on a given platform. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H | ||
| 14 | #define SANITIZER_PLATFORM_INTERCEPTORS_H | ||
| 15 | |||
| 16 | #include "sanitizer_glibc_version.h" | ||
| 17 | #include "sanitizer_internal_defs.h" | ||
| 18 | |||
| 19 | #if SANITIZER_POSIX | ||
| 20 | # define SI_POSIX 1 | ||
| 21 | #else | ||
| 22 | # define SI_POSIX 0 | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #if !SANITIZER_WINDOWS | ||
| 26 | # define SI_WINDOWS 0 | ||
| 27 | #else | ||
| 28 | # define SI_WINDOWS 1 | ||
| 29 | #endif | ||
| 30 | |||
| 31 | #if SI_WINDOWS && SI_POSIX | ||
| 32 | # error "Windows is not POSIX!" | ||
| 33 | #endif | ||
| 34 | |||
| 35 | #if SI_POSIX | ||
| 36 | # include "sanitizer_platform_limits_freebsd.h" | ||
| 37 | # include "sanitizer_platform_limits_netbsd.h" | ||
| 38 | # include "sanitizer_platform_limits_openbsd.h" | ||
| 39 | # include "sanitizer_platform_limits_posix.h" | ||
| 40 | # include "sanitizer_platform_limits_solaris.h" | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 44 | # define SI_LINUX_NOT_ANDROID 1 | ||
| 45 | #else | ||
| 46 | # define SI_LINUX_NOT_ANDROID 0 | ||
| 47 | #endif | ||
| 48 | |||
| 49 | #if SANITIZER_ANDROID | ||
| 50 | # define SI_ANDROID 1 | ||
| 51 | #else | ||
| 52 | # define SI_ANDROID 0 | ||
| 53 | #endif | ||
| 54 | |||
| 55 | #if SANITIZER_FREEBSD | ||
| 56 | # define SI_FREEBSD 1 | ||
| 57 | #else | ||
| 58 | # define SI_FREEBSD 0 | ||
| 59 | #endif | ||
| 60 | |||
| 61 | #if SANITIZER_NETBSD | ||
| 62 | # define SI_NETBSD 1 | ||
| 63 | #else | ||
| 64 | # define SI_NETBSD 0 | ||
| 65 | #endif | ||
| 66 | |||
| 67 | #if SANITIZER_OPENBSD | ||
| 68 | #define SI_OPENBSD 1 | ||
| 69 | #else | ||
| 70 | #define SI_OPENBSD 0 | ||
| 71 | #endif | ||
| 72 | |||
| 73 | #if SANITIZER_LINUX | ||
| 74 | # define SI_LINUX 1 | ||
| 75 | #else | ||
| 76 | # define SI_LINUX 0 | ||
| 77 | #endif | ||
| 78 | |||
| 79 | #if SANITIZER_MAC | ||
| 80 | # define SI_MAC 1 | ||
| 81 | # define SI_NOT_MAC 0 | ||
| 82 | #else | ||
| 83 | # define SI_MAC 0 | ||
| 84 | # define SI_NOT_MAC 1 | ||
| 85 | #endif | ||
| 86 | |||
| 87 | #if SANITIZER_IOS | ||
| 88 | # define SI_IOS 1 | ||
| 89 | #else | ||
| 90 | # define SI_IOS 0 | ||
| 91 | #endif | ||
| 92 | |||
| 93 | #if SANITIZER_IOSSIM | ||
| 94 | # define SI_IOSSIM 1 | ||
| 95 | #else | ||
| 96 | # define SI_IOSSIM 0 | ||
| 97 | #endif | ||
| 98 | |||
| 99 | #if SANITIZER_WATCHOS | ||
| 100 | # define SI_WATCHOS 1 | ||
| 101 | #else | ||
| 102 | # define SI_WATCHOS 0 | ||
| 103 | #endif | ||
| 104 | |||
| 105 | #if SANITIZER_TVOS | ||
| 106 | # define SI_TVOS 1 | ||
| 107 | #else | ||
| 108 | # define SI_TVOS 0 | ||
| 109 | #endif | ||
| 110 | |||
| 111 | #if SANITIZER_FUCHSIA | ||
| 112 | # define SI_NOT_FUCHSIA 0 | ||
| 113 | #else | ||
| 114 | # define SI_NOT_FUCHSIA 1 | ||
| 115 | #endif | ||
| 116 | |||
| 117 | #if SANITIZER_RTEMS | ||
| 118 | # define SI_NOT_RTEMS 0 | ||
| 119 | #else | ||
| 120 | # define SI_NOT_RTEMS 1 | ||
| 121 | #endif | ||
| 122 | |||
| 123 | #if SANITIZER_SOLARIS | ||
| 124 | # define SI_SOLARIS 1 | ||
| 125 | #else | ||
| 126 | # define SI_SOLARIS 0 | ||
| 127 | #endif | ||
| 128 | |||
| 129 | #if SANITIZER_SOLARIS32 | ||
| 130 | # define SI_SOLARIS32 1 | ||
| 131 | #else | ||
| 132 | # define SI_SOLARIS32 0 | ||
| 133 | #endif | ||
| 134 | |||
| 135 | #if SANITIZER_POSIX && !SANITIZER_MAC | ||
| 136 | # define SI_POSIX_NOT_MAC 1 | ||
| 137 | #else | ||
| 138 | # define SI_POSIX_NOT_MAC 0 | ||
| 139 | #endif | ||
| 140 | |||
| 141 | #if SANITIZER_LINUX && !SANITIZER_FREEBSD | ||
| 142 | # define SI_LINUX_NOT_FREEBSD 1 | ||
| 143 | # else | ||
| 144 | # define SI_LINUX_NOT_FREEBSD 0 | ||
| 145 | #endif | ||
| 146 | |||
| 147 | #define SANITIZER_INTERCEPT_STRLEN SI_NOT_FUCHSIA | ||
| 148 | #define SANITIZER_INTERCEPT_STRNLEN (SI_NOT_MAC && SI_NOT_FUCHSIA) | ||
| 149 | #define SANITIZER_INTERCEPT_STRCMP SI_NOT_FUCHSIA | ||
| 150 | #define SANITIZER_INTERCEPT_STRSTR SI_NOT_FUCHSIA | ||
| 151 | #define SANITIZER_INTERCEPT_STRCASESTR SI_POSIX | ||
| 152 | #define SANITIZER_INTERCEPT_STRTOK SI_NOT_FUCHSIA | ||
| 153 | #define SANITIZER_INTERCEPT_STRCHR SI_NOT_FUCHSIA | ||
| 154 | #define SANITIZER_INTERCEPT_STRCHRNUL SI_POSIX_NOT_MAC | ||
| 155 | #define SANITIZER_INTERCEPT_STRRCHR SI_NOT_FUCHSIA | ||
| 156 | #define SANITIZER_INTERCEPT_STRSPN SI_NOT_FUCHSIA | ||
| 157 | #define SANITIZER_INTERCEPT_STRPBRK SI_NOT_FUCHSIA | ||
| 158 | #define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID || SI_SOLARIS | ||
| 159 | #define SANITIZER_INTERCEPT_STRCASECMP SI_POSIX | ||
| 160 | #define SANITIZER_INTERCEPT_MEMSET 1 | ||
| 161 | #define SANITIZER_INTERCEPT_MEMMOVE 1 | ||
| 162 | #define SANITIZER_INTERCEPT_MEMCPY 1 | ||
| 163 | #define SANITIZER_INTERCEPT_MEMCMP SI_NOT_FUCHSIA | ||
| 164 | #define SANITIZER_INTERCEPT_BCMP \ | ||
| 165 | SANITIZER_INTERCEPT_MEMCMP && \ | ||
| 166 | ((SI_POSIX && _GNU_SOURCE) || SI_NETBSD || SI_OPENBSD || SI_FREEBSD) | ||
| 167 | #define SANITIZER_INTERCEPT_STRNDUP SI_POSIX | ||
| 168 | #define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD | ||
| 169 | #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ | ||
| 170 | __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 | ||
| 171 | # define SI_MAC_DEPLOYMENT_BELOW_10_7 1 | ||
| 172 | #else | ||
| 173 | # define SI_MAC_DEPLOYMENT_BELOW_10_7 0 | ||
| 174 | #endif | ||
| 175 | // memmem on Darwin doesn't exist on 10.6 | ||
| 176 | // FIXME: enable memmem on Windows. | ||
| 177 | #define SANITIZER_INTERCEPT_MEMMEM (SI_POSIX && !SI_MAC_DEPLOYMENT_BELOW_10_7) | ||
| 178 | #define SANITIZER_INTERCEPT_MEMCHR SI_NOT_FUCHSIA | ||
| 179 | #define SANITIZER_INTERCEPT_MEMRCHR \ | ||
| 180 | (SI_FREEBSD || SI_LINUX || SI_NETBSD || SI_OPENBSD) | ||
| 181 | |||
| 182 | #define SANITIZER_INTERCEPT_READ SI_POSIX | ||
| 183 | #define SANITIZER_INTERCEPT_PREAD SI_POSIX | ||
| 184 | #define SANITIZER_INTERCEPT_WRITE SI_POSIX | ||
| 185 | #define SANITIZER_INTERCEPT_PWRITE SI_POSIX | ||
| 186 | |||
| 187 | #define SANITIZER_INTERCEPT_FREAD SI_POSIX | ||
| 188 | #define SANITIZER_INTERCEPT_FWRITE SI_POSIX | ||
| 189 | #define SANITIZER_INTERCEPT_FGETS SI_POSIX | ||
| 190 | #define SANITIZER_INTERCEPT_FPUTS SI_POSIX | ||
| 191 | #define SANITIZER_INTERCEPT_PUTS SI_POSIX | ||
| 192 | |||
| 193 | #define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32 | ||
| 194 | #define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32 | ||
| 195 | |||
| 196 | #define SANITIZER_INTERCEPT_READV SI_POSIX | ||
| 197 | #define SANITIZER_INTERCEPT_WRITEV SI_POSIX | ||
| 198 | |||
| 199 | #define SANITIZER_INTERCEPT_PREADV \ | ||
| 200 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID) | ||
| 201 | #define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID | ||
| 202 | #define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID | ||
| 203 | #define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID | ||
| 204 | |||
| 205 | #define SANITIZER_INTERCEPT_PRCTL SI_LINUX | ||
| 206 | |||
| 207 | #define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_POSIX | ||
| 208 | #define SANITIZER_INTERCEPT_STRPTIME SI_POSIX | ||
| 209 | |||
| 210 | #define SANITIZER_INTERCEPT_SCANF SI_POSIX | ||
| 211 | #define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX_NOT_ANDROID | ||
| 212 | |||
| 213 | #ifndef SANITIZER_INTERCEPT_PRINTF | ||
| 214 | # define SANITIZER_INTERCEPT_PRINTF SI_POSIX | ||
| 215 | # define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD) | ||
| 216 | # define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID | ||
| 217 | #endif | ||
| 218 | |||
| 219 | #define SANITIZER_INTERCEPT___PRINTF_CHK \ | ||
| 220 | (SANITIZER_INTERCEPT_PRINTF && SI_LINUX_NOT_ANDROID) | ||
| 221 | |||
| 222 | #define SANITIZER_INTERCEPT_FREXP SI_NOT_FUCHSIA | ||
| 223 | #define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_POSIX | ||
| 224 | |||
| 225 | #define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_POSIX | ||
| 226 | #define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \ | ||
| 227 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ | ||
| 228 | SI_SOLARIS) | ||
| 229 | #define SANITIZER_INTERCEPT_GETPWENT \ | ||
| 230 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ | ||
| 231 | SI_SOLARIS) | ||
| 232 | #define SANITIZER_INTERCEPT_FGETGRENT_R \ | ||
| 233 | (SI_FREEBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 234 | #define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID || SI_SOLARIS | ||
| 235 | #define SANITIZER_INTERCEPT_GETPWENT_R \ | ||
| 236 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 237 | #define SANITIZER_INTERCEPT_FGETPWENT_R \ | ||
| 238 | (SI_FREEBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 239 | #define SANITIZER_INTERCEPT_SETPWENT \ | ||
| 240 | (SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 241 | #define SANITIZER_INTERCEPT_CLOCK_GETTIME \ | ||
| 242 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX || SI_SOLARIS) | ||
| 243 | #define SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID SI_LINUX | ||
| 244 | #define SANITIZER_INTERCEPT_GETITIMER SI_POSIX | ||
| 245 | #define SANITIZER_INTERCEPT_TIME SI_POSIX | ||
| 246 | #define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID || SI_SOLARIS | ||
| 247 | #define SANITIZER_INTERCEPT_GLOB64 SI_LINUX_NOT_ANDROID | ||
| 248 | #define SANITIZER_INTERCEPT_WAIT SI_POSIX | ||
| 249 | #define SANITIZER_INTERCEPT_INET SI_POSIX | ||
| 250 | #define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM (SI_POSIX && !SI_OPENBSD) | ||
| 251 | #define SANITIZER_INTERCEPT_GETADDRINFO SI_POSIX | ||
| 252 | #define SANITIZER_INTERCEPT_GETNAMEINFO SI_POSIX | ||
| 253 | #define SANITIZER_INTERCEPT_GETSOCKNAME SI_POSIX | ||
| 254 | #define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_POSIX | ||
| 255 | #define SANITIZER_INTERCEPT_GETHOSTBYNAME2 SI_POSIX && !SI_SOLARIS | ||
| 256 | #define SANITIZER_INTERCEPT_GETHOSTBYNAME_R \ | ||
| 257 | (SI_FREEBSD || SI_LINUX || SI_SOLARIS) | ||
| 258 | #define SANITIZER_INTERCEPT_GETHOSTBYNAME2_R \ | ||
| 259 | (SI_FREEBSD || SI_LINUX_NOT_ANDROID) | ||
| 260 | #define SANITIZER_INTERCEPT_GETHOSTBYADDR_R \ | ||
| 261 | (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 262 | #define SANITIZER_INTERCEPT_GETHOSTENT_R \ | ||
| 263 | (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 264 | #define SANITIZER_INTERCEPT_GETSOCKOPT SI_POSIX | ||
| 265 | #define SANITIZER_INTERCEPT_ACCEPT SI_POSIX | ||
| 266 | #define SANITIZER_INTERCEPT_ACCEPT4 \ | ||
| 267 | (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_OPENBSD) | ||
| 268 | #define SANITIZER_INTERCEPT_PACCEPT SI_NETBSD | ||
| 269 | #define SANITIZER_INTERCEPT_MODF SI_POSIX | ||
| 270 | #define SANITIZER_INTERCEPT_RECVMSG SI_POSIX | ||
| 271 | #define SANITIZER_INTERCEPT_SENDMSG SI_POSIX | ||
| 272 | #define SANITIZER_INTERCEPT_RECVMMSG SI_LINUX | ||
| 273 | #define SANITIZER_INTERCEPT_SENDMMSG SI_LINUX | ||
| 274 | #define SANITIZER_INTERCEPT_SYSMSG SI_LINUX_NOT_ANDROID | ||
| 275 | #define SANITIZER_INTERCEPT_GETPEERNAME SI_POSIX | ||
| 276 | #define SANITIZER_INTERCEPT_IOCTL SI_POSIX | ||
| 277 | #define SANITIZER_INTERCEPT_INET_ATON SI_POSIX | ||
| 278 | #define SANITIZER_INTERCEPT_SYSINFO SI_LINUX | ||
| 279 | #define SANITIZER_INTERCEPT_READDIR SI_POSIX | ||
| 280 | #define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32 | ||
| 281 | #if SI_LINUX_NOT_ANDROID && \ | ||
| 282 | (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ | ||
| 283 | defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ | ||
| 284 | defined(__s390__)) | ||
| 285 | #define SANITIZER_INTERCEPT_PTRACE 1 | ||
| 286 | #else | ||
| 287 | #define SANITIZER_INTERCEPT_PTRACE 0 | ||
| 288 | #endif | ||
| 289 | #define SANITIZER_INTERCEPT_SETLOCALE SI_POSIX | ||
| 290 | #define SANITIZER_INTERCEPT_GETCWD SI_POSIX | ||
| 291 | #define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID | ||
| 292 | #define SANITIZER_INTERCEPT_STRTOIMAX SI_POSIX | ||
| 293 | #define SANITIZER_INTERCEPT_MBSTOWCS SI_POSIX | ||
| 294 | #define SANITIZER_INTERCEPT_MBSNRTOWCS \ | ||
| 295 | (SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 296 | #define SANITIZER_INTERCEPT_WCSTOMBS SI_POSIX | ||
| 297 | #define SANITIZER_INTERCEPT_STRXFRM SI_POSIX | ||
| 298 | #define SANITIZER_INTERCEPT___STRXFRM_L SI_LINUX | ||
| 299 | #define SANITIZER_INTERCEPT_WCSXFRM SI_POSIX | ||
| 300 | #define SANITIZER_INTERCEPT___WCSXFRM_L SI_LINUX | ||
| 301 | #define SANITIZER_INTERCEPT_WCSNRTOMBS \ | ||
| 302 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ | ||
| 303 | SI_SOLARIS) | ||
| 304 | #define SANITIZER_INTERCEPT_WCRTOMB \ | ||
| 305 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ | ||
| 306 | SI_SOLARIS) | ||
| 307 | #define SANITIZER_INTERCEPT_WCTOMB \ | ||
| 308 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ | ||
| 309 | SI_SOLARIS) | ||
| 310 | #define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID || SI_SOLARIS | ||
| 311 | #define SANITIZER_INTERCEPT_REALPATH SI_POSIX | ||
| 312 | #define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME \ | ||
| 313 | (SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 314 | #define SANITIZER_INTERCEPT_CONFSTR \ | ||
| 315 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ | ||
| 316 | SI_SOLARIS) | ||
| 317 | #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID | ||
| 318 | #define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID || SI_SOLARIS | ||
| 319 | #define SANITIZER_INTERCEPT_STRERROR SI_POSIX | ||
| 320 | #define SANITIZER_INTERCEPT_STRERROR_R SI_POSIX | ||
| 321 | #define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID | ||
| 322 | #define SANITIZER_INTERCEPT_SCANDIR \ | ||
| 323 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 324 | #define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32 | ||
| 325 | #define SANITIZER_INTERCEPT_GETGROUPS SI_POSIX | ||
| 326 | #define SANITIZER_INTERCEPT_POLL SI_POSIX | ||
| 327 | #define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID || SI_SOLARIS | ||
| 328 | #define SANITIZER_INTERCEPT_WORDEXP \ | ||
| 329 | (SI_FREEBSD || SI_NETBSD || (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID || \ | ||
| 330 | SI_SOLARIS) | ||
| 331 | #define SANITIZER_INTERCEPT_SIGWAIT SI_POSIX | ||
| 332 | #define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID || SI_SOLARIS | ||
| 333 | #define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID || SI_SOLARIS | ||
| 334 | #define SANITIZER_INTERCEPT_SIGSETOPS \ | ||
| 335 | (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 336 | #define SANITIZER_INTERCEPT_SIGPENDING SI_POSIX | ||
| 337 | #define SANITIZER_INTERCEPT_SIGPROCMASK SI_POSIX | ||
| 338 | #define SANITIZER_INTERCEPT_PTHREAD_SIGMASK SI_POSIX | ||
| 339 | #define SANITIZER_INTERCEPT_BACKTRACE \ | ||
| 340 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 341 | #define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX | ||
| 342 | #define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID | ||
| 343 | #define SANITIZER_INTERCEPT_STATFS \ | ||
| 344 | (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 345 | #define SANITIZER_INTERCEPT_STATFS64 \ | ||
| 346 | (((SI_MAC && !TARGET_CPU_ARM64) && !SI_IOS) || SI_LINUX_NOT_ANDROID) | ||
| 347 | #define SANITIZER_INTERCEPT_STATVFS \ | ||
| 348 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID) | ||
| 349 | #define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID | ||
| 350 | #define SANITIZER_INTERCEPT_INITGROUPS SI_POSIX | ||
| 351 | #define SANITIZER_INTERCEPT_ETHER_NTOA_ATON (SI_POSIX && !SI_OPENBSD) | ||
| 352 | #define SANITIZER_INTERCEPT_ETHER_HOST \ | ||
| 353 | (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID) | ||
| 354 | #define SANITIZER_INTERCEPT_ETHER_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID) | ||
| 355 | #define SANITIZER_INTERCEPT_SHMCTL \ | ||
| 356 | (((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) || \ | ||
| 357 | SI_NETBSD || SI_OPENBSD || SI_SOLARIS) // NOLINT | ||
| 358 | #define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID | ||
| 359 | #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_POSIX | ||
| 360 | #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \ | ||
| 361 | (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 362 | #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID | ||
| 363 | #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED (SI_POSIX && !SI_OPENBSD) | ||
| 364 | #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED \ | ||
| 365 | (SI_POSIX && !SI_NETBSD && !SI_OPENBSD) | ||
| 366 | #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE (SI_POSIX && !SI_OPENBSD) | ||
| 367 | #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL \ | ||
| 368 | (SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 369 | #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING \ | ||
| 370 | (SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 371 | #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST \ | ||
| 372 | (SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 373 | #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID | ||
| 374 | #define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED \ | ||
| 375 | (SI_POSIX && !SI_NETBSD && !SI_OPENBSD) | ||
| 376 | #define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID | ||
| 377 | #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED \ | ||
| 378 | (SI_POSIX && !SI_NETBSD && !SI_OPENBSD) | ||
| 379 | #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK \ | ||
| 380 | (SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 381 | #define SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED \ | ||
| 382 | (SI_LINUX_NOT_ANDROID && !SI_NETBSD && !SI_OPENBSD) | ||
| 383 | #define SANITIZER_INTERCEPT_THR_EXIT SI_FREEBSD | ||
| 384 | #define SANITIZER_INTERCEPT_TMPNAM SI_POSIX | ||
| 385 | #define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID || SI_SOLARIS | ||
| 386 | #define SANITIZER_INTERCEPT_TTYNAME SI_POSIX | ||
| 387 | #define SANITIZER_INTERCEPT_TTYNAME_R SI_POSIX | ||
| 388 | #define SANITIZER_INTERCEPT_TEMPNAM SI_POSIX | ||
| 389 | #define SANITIZER_INTERCEPT_SINCOS SI_LINUX || SI_SOLARIS | ||
| 390 | #define SANITIZER_INTERCEPT_REMQUO SI_POSIX | ||
| 391 | #define SANITIZER_INTERCEPT_REMQUOL (SI_POSIX && !SI_NETBSD) | ||
| 392 | #define SANITIZER_INTERCEPT_LGAMMA SI_POSIX | ||
| 393 | #define SANITIZER_INTERCEPT_LGAMMAL (SI_POSIX && !SI_NETBSD) | ||
| 394 | #define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX || SI_SOLARIS) | ||
| 395 | #define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID || SI_SOLARIS | ||
| 396 | #define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID | ||
| 397 | #define SANITIZER_INTERCEPT_RAND_R \ | ||
| 398 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ | ||
| 399 | SI_SOLARIS) | ||
| 400 | #define SANITIZER_INTERCEPT_ICONV \ | ||
| 401 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 402 | #define SANITIZER_INTERCEPT_TIMES SI_POSIX | ||
| 403 | |||
| 404 | // FIXME: getline seems to be available on OSX 10.7 | ||
| 405 | #define SANITIZER_INTERCEPT_GETLINE \ | ||
| 406 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 407 | |||
| 408 | #define SANITIZER_INTERCEPT__EXIT \ | ||
| 409 | (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_SOLARIS) | ||
| 410 | |||
| 411 | #define SANITIZER_INTERCEPT_PTHREAD_MUTEX SI_POSIX | ||
| 412 | #define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_LINUX_NOT_ANDROID | ||
| 413 | #define SANITIZER_INTERCEPT___LIBC_MUTEX SI_NETBSD | ||
| 414 | #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \ | ||
| 415 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 416 | #define SANITIZER_INTERCEPT_PTHREAD_GETNAME_NP \ | ||
| 417 | (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 418 | |||
| 419 | #define SANITIZER_INTERCEPT_TLS_GET_ADDR \ | ||
| 420 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) | ||
| 421 | |||
| 422 | #define SANITIZER_INTERCEPT_LISTXATTR SI_LINUX | ||
| 423 | #define SANITIZER_INTERCEPT_GETXATTR SI_LINUX | ||
| 424 | #define SANITIZER_INTERCEPT_GETRESID SI_LINUX | ||
| 425 | #define SANITIZER_INTERCEPT_GETIFADDRS \ | ||
| 426 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_MAC || \ | ||
| 427 | SI_SOLARIS) | ||
| 428 | #define SANITIZER_INTERCEPT_IF_INDEXTONAME \ | ||
| 429 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_MAC || \ | ||
| 430 | SI_SOLARIS) | ||
| 431 | #define SANITIZER_INTERCEPT_CAPGET SI_LINUX_NOT_ANDROID | ||
| 432 | #if SI_LINUX && defined(__arm__) | ||
| 433 | #define SANITIZER_INTERCEPT_AEABI_MEM 1 | ||
| 434 | #else | ||
| 435 | #define SANITIZER_INTERCEPT_AEABI_MEM 0 | ||
| 436 | #endif | ||
| 437 | #define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_LINUX_NOT_ANDROID | ||
| 438 | #define SANITIZER_INTERCEPT_BZERO SI_LINUX_NOT_ANDROID | ||
| 439 | #define SANITIZER_INTERCEPT_FTIME \ | ||
| 440 | (!SI_FREEBSD && !SI_NETBSD && !SI_OPENBSD && SI_POSIX) | ||
| 441 | #define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID || SI_SOLARIS | ||
| 442 | #define SANITIZER_INTERCEPT_TSEARCH \ | ||
| 443 | (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_OPENBSD || SI_SOLARIS) | ||
| 444 | #define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID | ||
| 445 | #define SANITIZER_INTERCEPT_FOPEN SI_POSIX | ||
| 446 | #define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32 | ||
| 447 | #define SANITIZER_INTERCEPT_OPEN_MEMSTREAM \ | ||
| 448 | (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_OPENBSD || SI_SOLARIS) | ||
| 449 | #define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID | ||
| 450 | #define SANITIZER_INTERCEPT_FFLUSH SI_POSIX | ||
| 451 | #define SANITIZER_INTERCEPT_FCLOSE SI_POSIX | ||
| 452 | |||
| 453 | #ifndef SANITIZER_INTERCEPT_DLOPEN_DLCLOSE | ||
| 454 | #define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \ | ||
| 455 | (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_MAC || \ | ||
| 456 | SI_SOLARIS) | ||
| 457 | #endif | ||
| 458 | |||
| 459 | #define SANITIZER_INTERCEPT_GETPASS \ | ||
| 460 | (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_OPENBSD) | ||
| 461 | #define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID | ||
| 462 | |||
| 463 | #define SANITIZER_INTERCEPT_MLOCKX SI_POSIX | ||
| 464 | #define SANITIZER_INTERCEPT_FOPENCOOKIE SI_LINUX_NOT_ANDROID | ||
| 465 | #define SANITIZER_INTERCEPT_SEM \ | ||
| 466 | (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_SOLARIS) | ||
| 467 | #define SANITIZER_INTERCEPT_PTHREAD_SETCANCEL SI_POSIX | ||
| 468 | #define SANITIZER_INTERCEPT_MINCORE \ | ||
| 469 | (SI_LINUX || SI_NETBSD || SI_OPENBSD || SI_SOLARIS) | ||
| 470 | #define SANITIZER_INTERCEPT_PROCESS_VM_READV SI_LINUX | ||
| 471 | #define SANITIZER_INTERCEPT_CTERMID \ | ||
| 472 | (SI_LINUX || SI_MAC || SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_SOLARIS) | ||
| 473 | #define SANITIZER_INTERCEPT_CTERMID_R (SI_MAC || SI_FREEBSD || SI_SOLARIS) | ||
| 474 | |||
| 475 | #define SANITIZER_INTERCEPTOR_HOOKS \ | ||
| 476 | (SI_LINUX || SI_MAC || SI_WINDOWS || SI_NETBSD) | ||
| 477 | #define SANITIZER_INTERCEPT_RECV_RECVFROM SI_POSIX | ||
| 478 | #define SANITIZER_INTERCEPT_SEND_SENDTO SI_POSIX | ||
| 479 | #define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX | ||
| 480 | |||
| 481 | #define SANITIZER_INTERCEPT_STAT \ | ||
| 482 | (SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD || SI_OPENBSD || SI_SOLARIS) | ||
| 483 | #define SANITIZER_INTERCEPT_LSTAT (SI_NETBSD || SI_FREEBSD) | ||
| 484 | #define SANITIZER_INTERCEPT___XSTAT (!SANITIZER_INTERCEPT_STAT && SI_POSIX) | ||
| 485 | #define SANITIZER_INTERCEPT___XSTAT64 SI_LINUX_NOT_ANDROID | ||
| 486 | #define SANITIZER_INTERCEPT___LXSTAT SANITIZER_INTERCEPT___XSTAT | ||
| 487 | #define SANITIZER_INTERCEPT___LXSTAT64 SI_LINUX_NOT_ANDROID | ||
| 488 | |||
| 489 | #define SANITIZER_INTERCEPT_UTMP \ | ||
| 490 | (SI_POSIX && !SI_MAC && !SI_FREEBSD && !SI_NETBSD) | ||
| 491 | #define SANITIZER_INTERCEPT_UTMPX \ | ||
| 492 | (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD) | ||
| 493 | |||
| 494 | #define SANITIZER_INTERCEPT_GETLOADAVG \ | ||
| 495 | (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD || SI_OPENBSD) | ||
| 496 | |||
| 497 | #define SANITIZER_INTERCEPT_MMAP SI_POSIX | ||
| 498 | #define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID | ||
| 499 | #define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \ | ||
| 500 | (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_FUCHSIA && \ | ||
| 501 | SI_NOT_RTEMS) | ||
| 502 | #define SANITIZER_INTERCEPT_MEMALIGN \ | ||
| 503 | (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_RTEMS) | ||
| 504 | #define SANITIZER_INTERCEPT_PVALLOC \ | ||
| 505 | (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_FUCHSIA && \ | ||
| 506 | SI_NOT_RTEMS) | ||
| 507 | #define SANITIZER_INTERCEPT_CFREE \ | ||
| 508 | (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_FUCHSIA && \ | ||
| 509 | SI_NOT_RTEMS) | ||
| 510 | #define SANITIZER_INTERCEPT_REALLOCARRAY SI_POSIX | ||
| 511 | #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC && SI_NOT_RTEMS) | ||
| 512 | #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE \ | ||
| 513 | (!SI_MAC && !SI_OPENBSD && !SI_NETBSD) | ||
| 514 | #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID | ||
| 515 | #define SANITIZER_INTERCEPT_WCSCAT SI_POSIX | ||
| 516 | #define SANITIZER_INTERCEPT_WCSDUP SI_POSIX | ||
| 517 | #define SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION (!SI_WINDOWS && SI_NOT_FUCHSIA) | ||
| 518 | #define SANITIZER_INTERCEPT_BSD_SIGNAL SI_ANDROID | ||
| 519 | |||
| 520 | #define SANITIZER_INTERCEPT_ACCT (SI_NETBSD || SI_OPENBSD || SI_FREEBSD) | ||
| 521 | #define SANITIZER_INTERCEPT_USER_FROM_UID SI_NETBSD | ||
| 522 | #define SANITIZER_INTERCEPT_UID_FROM_USER SI_NETBSD | ||
| 523 | #define SANITIZER_INTERCEPT_GROUP_FROM_GID SI_NETBSD | ||
| 524 | #define SANITIZER_INTERCEPT_GID_FROM_GROUP SI_NETBSD | ||
| 525 | #define SANITIZER_INTERCEPT_ACCESS (SI_NETBSD || SI_OPENBSD || SI_FREEBSD) | ||
| 526 | #define SANITIZER_INTERCEPT_FACCESSAT (SI_NETBSD || SI_OPENBSD || SI_FREEBSD) | ||
| 527 | #define SANITIZER_INTERCEPT_GETGROUPLIST (SI_NETBSD || SI_OPENBSD) | ||
| 528 | #define SANITIZER_INTERCEPT_STRLCPY \ | ||
| 529 | (SI_NETBSD || SI_FREEBSD || SI_OPENBSD || SI_MAC || SI_ANDROID) | ||
| 530 | |||
| 531 | #define SANITIZER_INTERCEPT_NAME_TO_HANDLE_AT SI_LINUX_NOT_ANDROID | ||
| 532 | #define SANITIZER_INTERCEPT_OPEN_BY_HANDLE_AT SI_LINUX_NOT_ANDROID | ||
| 533 | |||
| 534 | #define SANITIZER_INTERCEPT_READLINK SI_POSIX | ||
| 535 | #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ | ||
| 536 | __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101000 | ||
| 537 | # define SI_MAC_DEPLOYMENT_BELOW_10_10 1 | ||
| 538 | #else | ||
| 539 | # define SI_MAC_DEPLOYMENT_BELOW_10_10 0 | ||
| 540 | #endif | ||
| 541 | #define SANITIZER_INTERCEPT_READLINKAT \ | ||
| 542 | (SI_POSIX && !SI_MAC_DEPLOYMENT_BELOW_10_10) | ||
| 543 | |||
| 544 | #define SANITIZER_INTERCEPT_DEVNAME (SI_NETBSD || SI_OPENBSD || SI_FREEBSD) | ||
| 545 | #define SANITIZER_INTERCEPT_DEVNAME_R (SI_NETBSD || SI_FREEBSD) | ||
| 546 | #define SANITIZER_INTERCEPT_FGETLN (SI_NETBSD || SI_FREEBSD) | ||
| 547 | #define SANITIZER_INTERCEPT_STRMODE (SI_NETBSD || SI_FREEBSD) | ||
| 548 | #define SANITIZER_INTERCEPT_TTYENT SI_NETBSD | ||
| 549 | #define SANITIZER_INTERCEPT_PROTOENT (SI_NETBSD || SI_LINUX) | ||
| 550 | #define SANITIZER_INTERCEPT_PROTOENT_R (SI_LINUX_NOT_ANDROID) | ||
| 551 | #define SANITIZER_INTERCEPT_NETENT SI_NETBSD | ||
| 552 | #define SANITIZER_INTERCEPT_SETVBUF (SI_NETBSD || SI_FREEBSD || \ | ||
| 553 | SI_LINUX || SI_MAC) | ||
| 554 | #define SANITIZER_INTERCEPT_GETMNTINFO (SI_NETBSD || SI_FREEBSD || SI_MAC) | ||
| 555 | #define SANITIZER_INTERCEPT_MI_VECTOR_HASH SI_NETBSD | ||
| 556 | #define SANITIZER_INTERCEPT_GETVFSSTAT SI_NETBSD | ||
| 557 | #define SANITIZER_INTERCEPT_REGEX (SI_NETBSD || SI_FREEBSD || SI_LINUX) | ||
| 558 | #define SANITIZER_INTERCEPT_REGEXSUB SI_NETBSD | ||
| 559 | #define SANITIZER_INTERCEPT_FTS (SI_NETBSD || SI_FREEBSD) | ||
| 560 | #define SANITIZER_INTERCEPT_SYSCTL (SI_NETBSD || SI_FREEBSD || SI_MAC) | ||
| 561 | #define SANITIZER_INTERCEPT_ASYSCTL SI_NETBSD | ||
| 562 | #define SANITIZER_INTERCEPT_SYSCTLGETMIBINFO SI_NETBSD | ||
| 563 | #define SANITIZER_INTERCEPT_NL_LANGINFO (SI_NETBSD || SI_FREEBSD || SI_MAC) | ||
| 564 | #define SANITIZER_INTERCEPT_MODCTL SI_NETBSD | ||
| 565 | #define SANITIZER_INTERCEPT_CAPSICUM SI_FREEBSD | ||
| 566 | #define SANITIZER_INTERCEPT_STRTONUM (SI_NETBSD || SI_FREEBSD) | ||
| 567 | #define SANITIZER_INTERCEPT_FPARSELN SI_NETBSD | ||
| 568 | #define SANITIZER_INTERCEPT_STATVFS1 SI_NETBSD | ||
| 569 | #define SANITIZER_INTERCEPT_STRTOI SI_NETBSD | ||
| 570 | #define SANITIZER_INTERCEPT_CAPSICUM SI_FREEBSD | ||
| 571 | #define SANITIZER_INTERCEPT_SHA1 SI_NETBSD | ||
| 572 | #define SANITIZER_INTERCEPT_MD4 SI_NETBSD | ||
| 573 | #define SANITIZER_INTERCEPT_RMD160 SI_NETBSD | ||
| 574 | #define SANITIZER_INTERCEPT_MD5 SI_NETBSD | ||
| 575 | #define SANITIZER_INTERCEPT_FSEEK (SI_NETBSD || SI_FREEBSD) | ||
| 576 | #define SANITIZER_INTERCEPT_MD2 SI_NETBSD | ||
| 577 | #define SANITIZER_INTERCEPT_SHA2 SI_NETBSD | ||
| 578 | #define SANITIZER_INTERCEPT_CDB SI_NETBSD | ||
| 579 | #define SANITIZER_INTERCEPT_VIS (SI_NETBSD || SI_FREEBSD) | ||
| 580 | #define SANITIZER_INTERCEPT_POPEN SI_POSIX | ||
| 581 | #define SANITIZER_INTERCEPT_POPENVE SI_NETBSD | ||
| 582 | #define SANITIZER_INTERCEPT_PCLOSE SI_POSIX | ||
| 583 | #define SANITIZER_INTERCEPT_FUNOPEN (SI_NETBSD || SI_FREEBSD) | ||
| 584 | #define SANITIZER_INTERCEPT_FUNOPEN2 SI_NETBSD | ||
| 585 | #define SANITIZER_INTERCEPT_GETFSENT (SI_FREEBSD || SI_NETBSD || SI_MAC) | ||
| 586 | #define SANITIZER_INTERCEPT_ARC4RANDOM (SI_FREEBSD || SI_NETBSD || SI_MAC) | ||
| 587 | #define SANITIZER_INTERCEPT_FDEVNAME SI_FREEBSD | ||
| 588 | #define SANITIZER_INTERCEPT_GETUSERSHELL (SI_POSIX && !SI_ANDROID) | ||
| 589 | #define SANITIZER_INTERCEPT_SL_INIT (SI_FREEBSD || SI_NETBSD) | ||
| 590 | #define SANITIZER_INTERCEPT_CRYPT (SI_POSIX && !SI_ANDROID) | ||
| 591 | #define SANITIZER_INTERCEPT_CRYPT_R (SI_LINUX && !SI_ANDROID) | ||
| 592 | |||
| 593 | #define SANITIZER_INTERCEPT_GETRANDOM \ | ||
| 594 | ((SI_LINUX && __GLIBC_PREREQ(2, 25)) || SI_FREEBSD) | ||
| 595 | #define SANITIZER_INTERCEPT___CXA_ATEXIT SI_NETBSD | ||
| 596 | #define SANITIZER_INTERCEPT_ATEXIT SI_NETBSD | ||
| 597 | #define SANITIZER_INTERCEPT_PTHREAD_ATFORK SI_NETBSD | ||
| 598 | #define SANITIZER_INTERCEPT_GETENTROPY SI_FREEBSD | ||
| 599 | #define SANITIZER_INTERCEPT_QSORT \ | ||
| 600 | (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID) | ||
| 601 | #define SANITIZER_INTERCEPT_QSORT_R (SI_LINUX && !SI_ANDROID) | ||
| 602 | // sigaltstack on i386 macOS cannot be intercepted due to setjmp() | ||
| 603 | // calling it and assuming that it does not clobber registers. | ||
| 604 | #define SANITIZER_INTERCEPT_SIGALTSTACK \ | ||
| 605 | (SI_POSIX && !(SANITIZER_MAC && SANITIZER_I386)) | ||
| 606 | #define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD) | ||
| 607 | #define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD | ||
| 608 | |||
| 609 | #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H | ||
lib/tsan/sanitizer_common/sanitizer_platform_limits_freebsd.cpp created+531| ... | @@ -0,0 +1,531 @@ | ||
| 1 | //===-- sanitizer_platform_limits_freebsd.cpp -----------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer common code. | ||
| 10 | // | ||
| 11 | // Sizes and layouts of platform-specific FreeBSD data structures. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_platform.h" | ||
| 15 | |||
| 16 | #if SANITIZER_FREEBSD | ||
| 17 | |||
| 18 | #include <sys/capsicum.h> | ||
| 19 | #include <sys/consio.h> | ||
| 20 | #include <sys/filio.h> | ||
| 21 | #include <sys/ipc.h> | ||
| 22 | #include <sys/kbio.h> | ||
| 23 | #include <sys/link_elf.h> | ||
| 24 | #include <sys/mman.h> | ||
| 25 | #include <sys/mount.h> | ||
| 26 | #include <sys/mqueue.h> | ||
| 27 | #include <sys/msg.h> | ||
| 28 | #include <sys/mtio.h> | ||
| 29 | #include <sys/ptrace.h> | ||
| 30 | #include <sys/resource.h> | ||
| 31 | #include <sys/signal.h> | ||
| 32 | #include <sys/socket.h> | ||
| 33 | #include <sys/sockio.h> | ||
| 34 | #include <sys/soundcard.h> | ||
| 35 | #include <sys/stat.h> | ||
| 36 | #include <sys/statvfs.h> | ||
| 37 | #include <sys/time.h> | ||
| 38 | #include <sys/timeb.h> | ||
| 39 | #include <sys/times.h> | ||
| 40 | #include <sys/timespec.h> | ||
| 41 | #include <sys/types.h> | ||
| 42 | #include <sys/ucontext.h> | ||
| 43 | #include <sys/utsname.h> | ||
| 44 | // | ||
| 45 | #include <arpa/inet.h> | ||
| 46 | #include <net/ethernet.h> | ||
| 47 | #include <net/if.h> | ||
| 48 | #include <net/ppp_defs.h> | ||
| 49 | #include <net/route.h> | ||
| 50 | #include <netdb.h> | ||
| 51 | #include <netinet/in.h> | ||
| 52 | #include <netinet/ip_mroute.h> | ||
| 53 | // | ||
| 54 | #include <dirent.h> | ||
| 55 | #include <dlfcn.h> | ||
| 56 | #include <fstab.h> | ||
| 57 | #include <fts.h> | ||
| 58 | #include <glob.h> | ||
| 59 | #include <grp.h> | ||
| 60 | #include <ifaddrs.h> | ||
| 61 | #include <limits.h> | ||
| 62 | #include <poll.h> | ||
| 63 | #include <pthread.h> | ||
| 64 | #include <pwd.h> | ||
| 65 | #include <regex.h> | ||
| 66 | #include <semaphore.h> | ||
| 67 | #include <signal.h> | ||
| 68 | #include <stddef.h> | ||
| 69 | #include <stdio.h> | ||
| 70 | #include <stringlist.h> | ||
| 71 | #include <term.h> | ||
| 72 | #include <termios.h> | ||
| 73 | #include <time.h> | ||
| 74 | #include <utime.h> | ||
| 75 | #include <utmpx.h> | ||
| 76 | #include <vis.h> | ||
| 77 | #include <wchar.h> | ||
| 78 | #include <wordexp.h> | ||
| 79 | |||
| 80 | #define _KERNEL // to declare 'shminfo' structure | ||
| 81 | #include <sys/shm.h> | ||
| 82 | #undef _KERNEL | ||
| 83 | |||
| 84 | #undef INLINE // to avoid clashes with sanitizers' definitions | ||
| 85 | |||
| 86 | #undef IOC_DIRMASK | ||
| 87 | |||
| 88 | // Include these after system headers to avoid name clashes and ambiguities. | ||
| 89 | #include "sanitizer_internal_defs.h" | ||
| 90 | #include "sanitizer_libc.h" | ||
| 91 | #include "sanitizer_platform_limits_freebsd.h" | ||
| 92 | |||
| 93 | namespace __sanitizer { | ||
| 94 | void *__sanitizer_get_link_map_by_dlopen_handle(void *handle) { | ||
| 95 | void *p = nullptr; | ||
| 96 | return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr; | ||
| 97 | } | ||
| 98 | |||
| 99 | unsigned struct_cap_rights_sz = sizeof(cap_rights_t); | ||
| 100 | unsigned struct_utsname_sz = sizeof(struct utsname); | ||
| 101 | unsigned struct_stat_sz = sizeof(struct stat); | ||
| 102 | unsigned struct_rusage_sz = sizeof(struct rusage); | ||
| 103 | unsigned struct_tm_sz = sizeof(struct tm); | ||
| 104 | unsigned struct_passwd_sz = sizeof(struct passwd); | ||
| 105 | unsigned struct_group_sz = sizeof(struct group); | ||
| 106 | unsigned siginfo_t_sz = sizeof(siginfo_t); | ||
| 107 | unsigned struct_sigaction_sz = sizeof(struct sigaction); | ||
| 108 | unsigned struct_stack_t_sz = sizeof(stack_t); | ||
| 109 | unsigned struct_itimerval_sz = sizeof(struct itimerval); | ||
| 110 | unsigned pthread_t_sz = sizeof(pthread_t); | ||
| 111 | unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); | ||
| 112 | unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); | ||
| 113 | unsigned pid_t_sz = sizeof(pid_t); | ||
| 114 | unsigned timeval_sz = sizeof(timeval); | ||
| 115 | unsigned uid_t_sz = sizeof(uid_t); | ||
| 116 | unsigned gid_t_sz = sizeof(gid_t); | ||
| 117 | unsigned fpos_t_sz = sizeof(fpos_t); | ||
| 118 | unsigned mbstate_t_sz = sizeof(mbstate_t); | ||
| 119 | unsigned sigset_t_sz = sizeof(sigset_t); | ||
| 120 | unsigned struct_timezone_sz = sizeof(struct timezone); | ||
| 121 | unsigned struct_tms_sz = sizeof(struct tms); | ||
| 122 | unsigned struct_sigevent_sz = sizeof(struct sigevent); | ||
| 123 | unsigned struct_sched_param_sz = sizeof(struct sched_param); | ||
| 124 | unsigned struct_statfs_sz = sizeof(struct statfs); | ||
| 125 | unsigned struct_sockaddr_sz = sizeof(struct sockaddr); | ||
| 126 | unsigned ucontext_t_sz = sizeof(ucontext_t); | ||
| 127 | unsigned struct_rlimit_sz = sizeof(struct rlimit); | ||
| 128 | unsigned struct_timespec_sz = sizeof(struct timespec); | ||
| 129 | unsigned struct_utimbuf_sz = sizeof(struct utimbuf); | ||
| 130 | unsigned struct_itimerspec_sz = sizeof(struct itimerspec); | ||
| 131 | unsigned struct_timeb_sz = sizeof(struct timeb); | ||
| 132 | unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); | ||
| 133 | unsigned struct_mq_attr_sz = sizeof(struct mq_attr); | ||
| 134 | unsigned struct_statvfs_sz = sizeof(struct statvfs); | ||
| 135 | unsigned struct_shminfo_sz = sizeof(struct shminfo); | ||
| 136 | unsigned struct_shm_info_sz = sizeof(struct shm_info); | ||
| 137 | unsigned struct_regmatch_sz = sizeof(regmatch_t); | ||
| 138 | unsigned struct_regex_sz = sizeof(regex_t); | ||
| 139 | unsigned struct_fstab_sz = sizeof(struct fstab); | ||
| 140 | unsigned struct_FTS_sz = sizeof(FTS); | ||
| 141 | unsigned struct_FTSENT_sz = sizeof(FTSENT); | ||
| 142 | unsigned struct_StringList_sz = sizeof(StringList); | ||
| 143 | |||
| 144 | const uptr sig_ign = (uptr)SIG_IGN; | ||
| 145 | const uptr sig_dfl = (uptr)SIG_DFL; | ||
| 146 | const uptr sig_err = (uptr)SIG_ERR; | ||
| 147 | const uptr sa_siginfo = (uptr)SA_SIGINFO; | ||
| 148 | |||
| 149 | int shmctl_ipc_stat = (int)IPC_STAT; | ||
| 150 | int shmctl_ipc_info = (int)IPC_INFO; | ||
| 151 | int shmctl_shm_info = (int)SHM_INFO; | ||
| 152 | int shmctl_shm_stat = (int)SHM_STAT; | ||
| 153 | unsigned struct_utmpx_sz = sizeof(struct utmpx); | ||
| 154 | |||
| 155 | int map_fixed = MAP_FIXED; | ||
| 156 | |||
| 157 | int af_inet = (int)AF_INET; | ||
| 158 | int af_inet6 = (int)AF_INET6; | ||
| 159 | |||
| 160 | uptr __sanitizer_in_addr_sz(int af) { | ||
| 161 | if (af == AF_INET) | ||
| 162 | return sizeof(struct in_addr); | ||
| 163 | else if (af == AF_INET6) | ||
| 164 | return sizeof(struct in6_addr); | ||
| 165 | else | ||
| 166 | return 0; | ||
| 167 | } | ||
| 168 | |||
| 169 | unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); | ||
| 170 | int glob_nomatch = GLOB_NOMATCH; | ||
| 171 | int glob_altdirfunc = GLOB_ALTDIRFUNC; | ||
| 172 | |||
| 173 | unsigned path_max = PATH_MAX; | ||
| 174 | |||
| 175 | // ioctl arguments | ||
| 176 | unsigned struct_ifreq_sz = sizeof(struct ifreq); | ||
| 177 | unsigned struct_termios_sz = sizeof(struct termios); | ||
| 178 | unsigned struct_winsize_sz = sizeof(struct winsize); | ||
| 179 | #if SOUND_VERSION >= 0x040000 | ||
| 180 | unsigned struct_copr_buffer_sz = 0; | ||
| 181 | unsigned struct_copr_debug_buf_sz = 0; | ||
| 182 | unsigned struct_copr_msg_sz = 0; | ||
| 183 | #else | ||
| 184 | unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer); | ||
| 185 | unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf); | ||
| 186 | unsigned struct_copr_msg_sz = sizeof(struct copr_msg); | ||
| 187 | #endif | ||
| 188 | unsigned struct_midi_info_sz = sizeof(struct midi_info); | ||
| 189 | unsigned struct_mtget_sz = sizeof(struct mtget); | ||
| 190 | unsigned struct_mtop_sz = sizeof(struct mtop); | ||
| 191 | unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument); | ||
| 192 | unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec); | ||
| 193 | unsigned struct_synth_info_sz = sizeof(struct synth_info); | ||
| 194 | unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); | ||
| 195 | unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); | ||
| 196 | unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); | ||
| 197 | unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); | ||
| 198 | const unsigned long __sanitizer_bufsiz = BUFSIZ; | ||
| 199 | |||
| 200 | const unsigned IOCTL_NOT_PRESENT = 0; | ||
| 201 | |||
| 202 | unsigned IOCTL_FIOASYNC = FIOASYNC; | ||
| 203 | unsigned IOCTL_FIOCLEX = FIOCLEX; | ||
| 204 | unsigned IOCTL_FIOGETOWN = FIOGETOWN; | ||
| 205 | unsigned IOCTL_FIONBIO = FIONBIO; | ||
| 206 | unsigned IOCTL_FIONCLEX = FIONCLEX; | ||
| 207 | unsigned IOCTL_FIOSETOWN = FIOSETOWN; | ||
| 208 | unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; | ||
| 209 | unsigned IOCTL_SIOCATMARK = SIOCATMARK; | ||
| 210 | unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; | ||
| 211 | unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; | ||
| 212 | unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; | ||
| 213 | unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; | ||
| 214 | unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; | ||
| 215 | unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; | ||
| 216 | unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; | ||
| 217 | unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; | ||
| 218 | unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; | ||
| 219 | unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; | ||
| 220 | unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; | ||
| 221 | unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; | ||
| 222 | unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; | ||
| 223 | unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; | ||
| 224 | unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; | ||
| 225 | unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; | ||
| 226 | unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; | ||
| 227 | unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; | ||
| 228 | unsigned IOCTL_TIOCCONS = TIOCCONS; | ||
| 229 | unsigned IOCTL_TIOCEXCL = TIOCEXCL; | ||
| 230 | unsigned IOCTL_TIOCGETD = TIOCGETD; | ||
| 231 | unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; | ||
| 232 | unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; | ||
| 233 | unsigned IOCTL_TIOCMBIC = TIOCMBIC; | ||
| 234 | unsigned IOCTL_TIOCMBIS = TIOCMBIS; | ||
| 235 | unsigned IOCTL_TIOCMGET = TIOCMGET; | ||
| 236 | unsigned IOCTL_TIOCMSET = TIOCMSET; | ||
| 237 | unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; | ||
| 238 | unsigned IOCTL_TIOCNXCL = TIOCNXCL; | ||
| 239 | unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; | ||
| 240 | unsigned IOCTL_TIOCPKT = TIOCPKT; | ||
| 241 | unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; | ||
| 242 | unsigned IOCTL_TIOCSETD = TIOCSETD; | ||
| 243 | unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; | ||
| 244 | unsigned IOCTL_TIOCSTI = TIOCSTI; | ||
| 245 | unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; | ||
| 246 | unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; | ||
| 247 | unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; | ||
| 248 | unsigned IOCTL_MTIOCGET = MTIOCGET; | ||
| 249 | unsigned IOCTL_MTIOCTOP = MTIOCTOP; | ||
| 250 | unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; | ||
| 251 | unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; | ||
| 252 | unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; | ||
| 253 | unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; | ||
| 254 | unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; | ||
| 255 | unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; | ||
| 256 | unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; | ||
| 257 | unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; | ||
| 258 | unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; | ||
| 259 | unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; | ||
| 260 | unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; | ||
| 261 | unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE; | ||
| 262 | unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR; | ||
| 263 | unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO; | ||
| 264 | unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME; | ||
| 265 | unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE; | ||
| 266 | unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT; | ||
| 267 | unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT; | ||
| 268 | unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS; | ||
| 269 | unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS; | ||
| 270 | unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND; | ||
| 271 | unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC; | ||
| 272 | unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE; | ||
| 273 | unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET; | ||
| 274 | unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES; | ||
| 275 | unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC; | ||
| 276 | unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI; | ||
| 277 | unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD; | ||
| 278 | unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO; | ||
| 279 | unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL; | ||
| 280 | unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE; | ||
| 281 | unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME; | ||
| 282 | unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT; | ||
| 283 | unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE; | ||
| 284 | unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START; | ||
| 285 | unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP; | ||
| 286 | unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO; | ||
| 287 | unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE; | ||
| 288 | unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM; | ||
| 289 | unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS; | ||
| 290 | unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS; | ||
| 291 | unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD; | ||
| 292 | unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK; | ||
| 293 | unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE; | ||
| 294 | unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN; | ||
| 295 | unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX; | ||
| 296 | unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE; | ||
| 297 | unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1; | ||
| 298 | unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2; | ||
| 299 | unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3; | ||
| 300 | unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD; | ||
| 301 | unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC; | ||
| 302 | unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE; | ||
| 303 | unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN; | ||
| 304 | unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM; | ||
| 305 | unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV; | ||
| 306 | unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK; | ||
| 307 | unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC; | ||
| 308 | unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER; | ||
| 309 | unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS; | ||
| 310 | unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH; | ||
| 311 | unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE; | ||
| 312 | unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME; | ||
| 313 | unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM; | ||
| 314 | unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS; | ||
| 315 | unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD; | ||
| 316 | unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE; | ||
| 317 | unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN; | ||
| 318 | unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX; | ||
| 319 | unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE; | ||
| 320 | unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1; | ||
| 321 | unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2; | ||
| 322 | unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3; | ||
| 323 | unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD; | ||
| 324 | unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC; | ||
| 325 | unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE; | ||
| 326 | unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN; | ||
| 327 | unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM; | ||
| 328 | unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV; | ||
| 329 | unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC; | ||
| 330 | unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER; | ||
| 331 | unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH; | ||
| 332 | unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE; | ||
| 333 | unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME; | ||
| 334 | unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; | ||
| 335 | unsigned IOCTL_VT_GETMODE = VT_GETMODE; | ||
| 336 | unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; | ||
| 337 | unsigned IOCTL_VT_RELDISP = VT_RELDISP; | ||
| 338 | unsigned IOCTL_VT_SETMODE = VT_SETMODE; | ||
| 339 | unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; | ||
| 340 | unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP; | ||
| 341 | unsigned IOCTL_KDDISABIO = KDDISABIO; | ||
| 342 | unsigned IOCTL_KDENABIO = KDENABIO; | ||
| 343 | unsigned IOCTL_KDGETLED = KDGETLED; | ||
| 344 | unsigned IOCTL_KDGETMODE = KDGETMODE; | ||
| 345 | unsigned IOCTL_KDGKBMODE = KDGKBMODE; | ||
| 346 | unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; | ||
| 347 | unsigned IOCTL_KDMKTONE = KDMKTONE; | ||
| 348 | unsigned IOCTL_KDSETLED = KDSETLED; | ||
| 349 | unsigned IOCTL_KDSETMODE = KDSETMODE; | ||
| 350 | unsigned IOCTL_KDSKBMODE = KDSKBMODE; | ||
| 351 | unsigned IOCTL_KIOCSOUND = KIOCSOUND; | ||
| 352 | unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP; | ||
| 353 | unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; | ||
| 354 | |||
| 355 | const int si_SEGV_MAPERR = SEGV_MAPERR; | ||
| 356 | const int si_SEGV_ACCERR = SEGV_ACCERR; | ||
| 357 | const int unvis_valid = UNVIS_VALID; | ||
| 358 | const int unvis_validpush = UNVIS_VALIDPUSH; | ||
| 359 | } // namespace __sanitizer | ||
| 360 | |||
| 361 | using namespace __sanitizer; | ||
| 362 | |||
| 363 | COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); | ||
| 364 | |||
| 365 | COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); | ||
| 366 | CHECK_TYPE_SIZE(pthread_key_t); | ||
| 367 | |||
| 368 | // There are more undocumented fields in dl_phdr_info that we are not interested | ||
| 369 | // in. | ||
| 370 | COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); | ||
| 371 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); | ||
| 372 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); | ||
| 373 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); | ||
| 374 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); | ||
| 375 | |||
| 376 | CHECK_TYPE_SIZE(glob_t); | ||
| 377 | CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); | ||
| 378 | CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); | ||
| 379 | CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); | ||
| 380 | CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); | ||
| 381 | CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); | ||
| 382 | CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); | ||
| 383 | CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); | ||
| 384 | CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); | ||
| 385 | CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); | ||
| 386 | |||
| 387 | CHECK_TYPE_SIZE(addrinfo); | ||
| 388 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); | ||
| 389 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); | ||
| 390 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); | ||
| 391 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); | ||
| 392 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); | ||
| 393 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); | ||
| 394 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); | ||
| 395 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); | ||
| 396 | |||
| 397 | CHECK_TYPE_SIZE(hostent); | ||
| 398 | CHECK_SIZE_AND_OFFSET(hostent, h_name); | ||
| 399 | CHECK_SIZE_AND_OFFSET(hostent, h_aliases); | ||
| 400 | CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); | ||
| 401 | CHECK_SIZE_AND_OFFSET(hostent, h_length); | ||
| 402 | CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); | ||
| 403 | |||
| 404 | CHECK_TYPE_SIZE(iovec); | ||
| 405 | CHECK_SIZE_AND_OFFSET(iovec, iov_base); | ||
| 406 | CHECK_SIZE_AND_OFFSET(iovec, iov_len); | ||
| 407 | |||
| 408 | CHECK_TYPE_SIZE(msghdr); | ||
| 409 | CHECK_SIZE_AND_OFFSET(msghdr, msg_name); | ||
| 410 | CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); | ||
| 411 | CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); | ||
| 412 | CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); | ||
| 413 | CHECK_SIZE_AND_OFFSET(msghdr, msg_control); | ||
| 414 | CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); | ||
| 415 | CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); | ||
| 416 | |||
| 417 | CHECK_TYPE_SIZE(cmsghdr); | ||
| 418 | CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); | ||
| 419 | CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); | ||
| 420 | CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); | ||
| 421 | |||
| 422 | COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); | ||
| 423 | CHECK_SIZE_AND_OFFSET(dirent, d_ino); | ||
| 424 | CHECK_SIZE_AND_OFFSET(dirent, d_reclen); | ||
| 425 | |||
| 426 | CHECK_TYPE_SIZE(ifconf); | ||
| 427 | CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); | ||
| 428 | CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); | ||
| 429 | |||
| 430 | CHECK_TYPE_SIZE(pollfd); | ||
| 431 | CHECK_SIZE_AND_OFFSET(pollfd, fd); | ||
| 432 | CHECK_SIZE_AND_OFFSET(pollfd, events); | ||
| 433 | CHECK_SIZE_AND_OFFSET(pollfd, revents); | ||
| 434 | |||
| 435 | CHECK_TYPE_SIZE(nfds_t); | ||
| 436 | |||
| 437 | CHECK_TYPE_SIZE(sigset_t); | ||
| 438 | |||
| 439 | COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); | ||
| 440 | // Can't write checks for sa_handler and sa_sigaction due to them being | ||
| 441 | // preprocessor macros. | ||
| 442 | CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); | ||
| 443 | |||
| 444 | CHECK_TYPE_SIZE(wordexp_t); | ||
| 445 | CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); | ||
| 446 | CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); | ||
| 447 | CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); | ||
| 448 | |||
| 449 | CHECK_TYPE_SIZE(tm); | ||
| 450 | CHECK_SIZE_AND_OFFSET(tm, tm_sec); | ||
| 451 | CHECK_SIZE_AND_OFFSET(tm, tm_min); | ||
| 452 | CHECK_SIZE_AND_OFFSET(tm, tm_hour); | ||
| 453 | CHECK_SIZE_AND_OFFSET(tm, tm_mday); | ||
| 454 | CHECK_SIZE_AND_OFFSET(tm, tm_mon); | ||
| 455 | CHECK_SIZE_AND_OFFSET(tm, tm_year); | ||
| 456 | CHECK_SIZE_AND_OFFSET(tm, tm_wday); | ||
| 457 | CHECK_SIZE_AND_OFFSET(tm, tm_yday); | ||
| 458 | CHECK_SIZE_AND_OFFSET(tm, tm_isdst); | ||
| 459 | CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); | ||
| 460 | CHECK_SIZE_AND_OFFSET(tm, tm_zone); | ||
| 461 | |||
| 462 | CHECK_TYPE_SIZE(ether_addr); | ||
| 463 | |||
| 464 | CHECK_TYPE_SIZE(ipc_perm); | ||
| 465 | CHECK_SIZE_AND_OFFSET(ipc_perm, key); | ||
| 466 | CHECK_SIZE_AND_OFFSET(ipc_perm, seq); | ||
| 467 | CHECK_SIZE_AND_OFFSET(ipc_perm, uid); | ||
| 468 | CHECK_SIZE_AND_OFFSET(ipc_perm, gid); | ||
| 469 | CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); | ||
| 470 | CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); | ||
| 471 | |||
| 472 | CHECK_TYPE_SIZE(shmid_ds); | ||
| 473 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); | ||
| 474 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); | ||
| 475 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); | ||
| 476 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); | ||
| 477 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); | ||
| 478 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); | ||
| 479 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); | ||
| 480 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); | ||
| 481 | |||
| 482 | CHECK_TYPE_SIZE(clock_t); | ||
| 483 | |||
| 484 | CHECK_TYPE_SIZE(ifaddrs); | ||
| 485 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); | ||
| 486 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); | ||
| 487 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); | ||
| 488 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); | ||
| 489 | #undef ifa_dstaddr | ||
| 490 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); | ||
| 491 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); | ||
| 492 | |||
| 493 | CHECK_TYPE_SIZE(timeb); | ||
| 494 | CHECK_SIZE_AND_OFFSET(timeb, time); | ||
| 495 | CHECK_SIZE_AND_OFFSET(timeb, millitm); | ||
| 496 | CHECK_SIZE_AND_OFFSET(timeb, timezone); | ||
| 497 | CHECK_SIZE_AND_OFFSET(timeb, dstflag); | ||
| 498 | |||
| 499 | CHECK_TYPE_SIZE(passwd); | ||
| 500 | CHECK_SIZE_AND_OFFSET(passwd, pw_name); | ||
| 501 | CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); | ||
| 502 | CHECK_SIZE_AND_OFFSET(passwd, pw_uid); | ||
| 503 | CHECK_SIZE_AND_OFFSET(passwd, pw_gid); | ||
| 504 | CHECK_SIZE_AND_OFFSET(passwd, pw_dir); | ||
| 505 | CHECK_SIZE_AND_OFFSET(passwd, pw_shell); | ||
| 506 | |||
| 507 | CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); | ||
| 508 | |||
| 509 | CHECK_TYPE_SIZE(group); | ||
| 510 | CHECK_SIZE_AND_OFFSET(group, gr_name); | ||
| 511 | CHECK_SIZE_AND_OFFSET(group, gr_passwd); | ||
| 512 | CHECK_SIZE_AND_OFFSET(group, gr_gid); | ||
| 513 | CHECK_SIZE_AND_OFFSET(group, gr_mem); | ||
| 514 | |||
| 515 | #if HAVE_RPC_XDR_H | ||
| 516 | CHECK_TYPE_SIZE(XDR); | ||
| 517 | CHECK_SIZE_AND_OFFSET(XDR, x_op); | ||
| 518 | CHECK_SIZE_AND_OFFSET(XDR, x_ops); | ||
| 519 | CHECK_SIZE_AND_OFFSET(XDR, x_public); | ||
| 520 | CHECK_SIZE_AND_OFFSET(XDR, x_private); | ||
| 521 | CHECK_SIZE_AND_OFFSET(XDR, x_base); | ||
| 522 | CHECK_SIZE_AND_OFFSET(XDR, x_handy); | ||
| 523 | COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE); | ||
| 524 | COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); | ||
| 525 | COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); | ||
| 526 | #endif | ||
| 527 | |||
| 528 | CHECK_TYPE_SIZE(sem_t); | ||
| 529 | |||
| 530 | COMPILER_CHECK(sizeof(__sanitizer_cap_rights_t) >= sizeof(cap_rights_t)); | ||
| 531 | #endif // SANITIZER_FREEBSD | ||
lib/tsan/sanitizer_common/sanitizer_platform_limits_freebsd.h created+656| ... | @@ -0,0 +1,656 @@ | ||
| 1 | //===-- sanitizer_platform_limits_freebsd.h -------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer common code. | ||
| 10 | // | ||
| 11 | // Sizes and layouts of platform-specific FreeBSD data structures. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_PLATFORM_LIMITS_FREEBSD_H | ||
| 15 | #define SANITIZER_PLATFORM_LIMITS_FREEBSD_H | ||
| 16 | |||
| 17 | #if SANITIZER_FREEBSD | ||
| 18 | |||
| 19 | #include "sanitizer_internal_defs.h" | ||
| 20 | #include "sanitizer_platform.h" | ||
| 21 | #include "sanitizer_platform_limits_posix.h" | ||
| 22 | |||
| 23 | // Get sys/_types.h, because that tells us whether 64-bit inodes are | ||
| 24 | // used in struct dirent below. | ||
| 25 | #include <sys/_types.h> | ||
| 26 | |||
| 27 | namespace __sanitizer { | ||
| 28 | void *__sanitizer_get_link_map_by_dlopen_handle(void *handle); | ||
| 29 | #define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ | ||
| 30 | (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle) | ||
| 31 | |||
| 32 | extern unsigned struct_utsname_sz; | ||
| 33 | extern unsigned struct_stat_sz; | ||
| 34 | #if defined(__powerpc64__) | ||
| 35 | const unsigned struct___old_kernel_stat_sz = 0; | ||
| 36 | #else | ||
| 37 | const unsigned struct___old_kernel_stat_sz = 32; | ||
| 38 | #endif | ||
| 39 | extern unsigned struct_rusage_sz; | ||
| 40 | extern unsigned siginfo_t_sz; | ||
| 41 | extern unsigned struct_itimerval_sz; | ||
| 42 | extern unsigned pthread_t_sz; | ||
| 43 | extern unsigned pthread_mutex_t_sz; | ||
| 44 | extern unsigned pthread_cond_t_sz; | ||
| 45 | extern unsigned pid_t_sz; | ||
| 46 | extern unsigned timeval_sz; | ||
| 47 | extern unsigned uid_t_sz; | ||
| 48 | extern unsigned gid_t_sz; | ||
| 49 | extern unsigned fpos_t_sz; | ||
| 50 | extern unsigned mbstate_t_sz; | ||
| 51 | extern unsigned struct_timezone_sz; | ||
| 52 | extern unsigned struct_tms_sz; | ||
| 53 | extern unsigned struct_itimerspec_sz; | ||
| 54 | extern unsigned struct_sigevent_sz; | ||
| 55 | extern unsigned struct_stack_t_sz; | ||
| 56 | extern unsigned struct_sched_param_sz; | ||
| 57 | extern unsigned struct_statfs64_sz; | ||
| 58 | extern unsigned struct_statfs_sz; | ||
| 59 | extern unsigned struct_sockaddr_sz; | ||
| 60 | extern unsigned ucontext_t_sz; | ||
| 61 | extern unsigned struct_rlimit_sz; | ||
| 62 | extern unsigned struct_utimbuf_sz; | ||
| 63 | extern unsigned struct_timespec_sz; | ||
| 64 | extern unsigned struct_regmatch_sz; | ||
| 65 | extern unsigned struct_regex_sz; | ||
| 66 | extern unsigned struct_FTS_sz; | ||
| 67 | extern unsigned struct_FTSENT_sz; | ||
| 68 | extern const int unvis_valid; | ||
| 69 | extern const int unvis_validpush; | ||
| 70 | |||
| 71 | struct __sanitizer_iocb { | ||
| 72 | u64 aio_data; | ||
| 73 | u32 aio_key_or_aio_reserved1; // Simply crazy. | ||
| 74 | u32 aio_reserved1_or_aio_key; // Luckily, we don't need these. | ||
| 75 | u16 aio_lio_opcode; | ||
| 76 | s16 aio_reqprio; | ||
| 77 | u32 aio_fildes; | ||
| 78 | u64 aio_buf; | ||
| 79 | u64 aio_nbytes; | ||
| 80 | s64 aio_offset; | ||
| 81 | u64 aio_reserved2; | ||
| 82 | u64 aio_reserved3; | ||
| 83 | }; | ||
| 84 | |||
| 85 | struct __sanitizer_io_event { | ||
| 86 | u64 data; | ||
| 87 | u64 obj; | ||
| 88 | u64 res; | ||
| 89 | u64 res2; | ||
| 90 | }; | ||
| 91 | |||
| 92 | const unsigned iocb_cmd_pread = 0; | ||
| 93 | const unsigned iocb_cmd_pwrite = 1; | ||
| 94 | const unsigned iocb_cmd_preadv = 7; | ||
| 95 | const unsigned iocb_cmd_pwritev = 8; | ||
| 96 | |||
| 97 | struct __sanitizer___sysctl_args { | ||
| 98 | int *name; | ||
| 99 | int nlen; | ||
| 100 | void *oldval; | ||
| 101 | uptr *oldlenp; | ||
| 102 | void *newval; | ||
| 103 | uptr newlen; | ||
| 104 | unsigned long ___unused[4]; | ||
| 105 | }; | ||
| 106 | |||
| 107 | struct __sanitizer_ipc_perm { | ||
| 108 | unsigned int cuid; | ||
| 109 | unsigned int cgid; | ||
| 110 | unsigned int uid; | ||
| 111 | unsigned int gid; | ||
| 112 | unsigned short mode; | ||
| 113 | unsigned short seq; | ||
| 114 | long key; | ||
| 115 | }; | ||
| 116 | |||
| 117 | #if !defined(__i386__) | ||
| 118 | typedef long long __sanitizer_time_t; | ||
| 119 | #else | ||
| 120 | typedef long __sanitizer_time_t; | ||
| 121 | #endif | ||
| 122 | |||
| 123 | struct __sanitizer_shmid_ds { | ||
| 124 | __sanitizer_ipc_perm shm_perm; | ||
| 125 | unsigned long shm_segsz; | ||
| 126 | unsigned int shm_lpid; | ||
| 127 | unsigned int shm_cpid; | ||
| 128 | int shm_nattch; | ||
| 129 | __sanitizer_time_t shm_atime; | ||
| 130 | __sanitizer_time_t shm_dtime; | ||
| 131 | __sanitizer_time_t shm_ctime; | ||
| 132 | }; | ||
| 133 | |||
| 134 | extern unsigned struct_msqid_ds_sz; | ||
| 135 | extern unsigned struct_mq_attr_sz; | ||
| 136 | extern unsigned struct_timeb_sz; | ||
| 137 | extern unsigned struct_statvfs_sz; | ||
| 138 | |||
| 139 | struct __sanitizer_iovec { | ||
| 140 | void *iov_base; | ||
| 141 | uptr iov_len; | ||
| 142 | }; | ||
| 143 | |||
| 144 | struct __sanitizer_ifaddrs { | ||
| 145 | struct __sanitizer_ifaddrs *ifa_next; | ||
| 146 | char *ifa_name; | ||
| 147 | unsigned int ifa_flags; | ||
| 148 | void *ifa_addr; // (struct sockaddr *) | ||
| 149 | void *ifa_netmask; // (struct sockaddr *) | ||
| 150 | #undef ifa_dstaddr | ||
| 151 | void *ifa_dstaddr; // (struct sockaddr *) | ||
| 152 | void *ifa_data; | ||
| 153 | }; | ||
| 154 | |||
| 155 | typedef unsigned __sanitizer_pthread_key_t; | ||
| 156 | |||
| 157 | struct __sanitizer_passwd { | ||
| 158 | char *pw_name; | ||
| 159 | char *pw_passwd; | ||
| 160 | int pw_uid; | ||
| 161 | int pw_gid; | ||
| 162 | __sanitizer_time_t pw_change; | ||
| 163 | char *pw_class; | ||
| 164 | char *pw_gecos; | ||
| 165 | char *pw_dir; | ||
| 166 | char *pw_shell; | ||
| 167 | __sanitizer_time_t pw_expire; | ||
| 168 | int pw_fields; | ||
| 169 | }; | ||
| 170 | |||
| 171 | struct __sanitizer_group { | ||
| 172 | char *gr_name; | ||
| 173 | char *gr_passwd; | ||
| 174 | int gr_gid; | ||
| 175 | char **gr_mem; | ||
| 176 | }; | ||
| 177 | |||
| 178 | typedef long __sanitizer_suseconds_t; | ||
| 179 | |||
| 180 | struct __sanitizer_timeval { | ||
| 181 | __sanitizer_time_t tv_sec; | ||
| 182 | __sanitizer_suseconds_t tv_usec; | ||
| 183 | }; | ||
| 184 | |||
| 185 | struct __sanitizer_itimerval { | ||
| 186 | struct __sanitizer_timeval it_interval; | ||
| 187 | struct __sanitizer_timeval it_value; | ||
| 188 | }; | ||
| 189 | |||
| 190 | struct __sanitizer_timeb { | ||
| 191 | __sanitizer_time_t time; | ||
| 192 | unsigned short millitm; | ||
| 193 | short timezone; | ||
| 194 | short dstflag; | ||
| 195 | }; | ||
| 196 | |||
| 197 | struct __sanitizer_ether_addr { | ||
| 198 | u8 octet[6]; | ||
| 199 | }; | ||
| 200 | |||
| 201 | struct __sanitizer_tm { | ||
| 202 | int tm_sec; | ||
| 203 | int tm_min; | ||
| 204 | int tm_hour; | ||
| 205 | int tm_mday; | ||
| 206 | int tm_mon; | ||
| 207 | int tm_year; | ||
| 208 | int tm_wday; | ||
| 209 | int tm_yday; | ||
| 210 | int tm_isdst; | ||
| 211 | long int tm_gmtoff; | ||
| 212 | const char *tm_zone; | ||
| 213 | }; | ||
| 214 | |||
| 215 | struct __sanitizer_msghdr { | ||
| 216 | void *msg_name; | ||
| 217 | unsigned msg_namelen; | ||
| 218 | struct __sanitizer_iovec *msg_iov; | ||
| 219 | unsigned msg_iovlen; | ||
| 220 | void *msg_control; | ||
| 221 | unsigned msg_controllen; | ||
| 222 | int msg_flags; | ||
| 223 | }; | ||
| 224 | |||
| 225 | struct __sanitizer_cmsghdr { | ||
| 226 | unsigned cmsg_len; | ||
| 227 | int cmsg_level; | ||
| 228 | int cmsg_type; | ||
| 229 | }; | ||
| 230 | |||
| 231 | struct __sanitizer_dirent { | ||
| 232 | #if defined(__INO64) | ||
| 233 | unsigned long long d_fileno; | ||
| 234 | unsigned long long d_off; | ||
| 235 | #else | ||
| 236 | unsigned int d_fileno; | ||
| 237 | #endif | ||
| 238 | unsigned short d_reclen; | ||
| 239 | // more fields that we don't care about | ||
| 240 | }; | ||
| 241 | |||
| 242 | // 'clock_t' is 32 bits wide on x64 FreeBSD | ||
| 243 | typedef int __sanitizer_clock_t; | ||
| 244 | typedef int __sanitizer_clockid_t; | ||
| 245 | |||
| 246 | #if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__) || \ | ||
| 247 | defined(__mips__) | ||
| 248 | typedef unsigned __sanitizer___kernel_uid_t; | ||
| 249 | typedef unsigned __sanitizer___kernel_gid_t; | ||
| 250 | #else | ||
| 251 | typedef unsigned short __sanitizer___kernel_uid_t; | ||
| 252 | typedef unsigned short __sanitizer___kernel_gid_t; | ||
| 253 | #endif | ||
| 254 | typedef long long __sanitizer___kernel_off_t; | ||
| 255 | |||
| 256 | #if defined(__powerpc__) || defined(__mips__) | ||
| 257 | typedef unsigned int __sanitizer___kernel_old_uid_t; | ||
| 258 | typedef unsigned int __sanitizer___kernel_old_gid_t; | ||
| 259 | #else | ||
| 260 | typedef unsigned short __sanitizer___kernel_old_uid_t; | ||
| 261 | typedef unsigned short __sanitizer___kernel_old_gid_t; | ||
| 262 | #endif | ||
| 263 | |||
| 264 | typedef long long __sanitizer___kernel_loff_t; | ||
| 265 | typedef struct { | ||
| 266 | unsigned long fds_bits[1024 / (8 * sizeof(long))]; | ||
| 267 | } __sanitizer___kernel_fd_set; | ||
| 268 | |||
| 269 | // This thing depends on the platform. We are only interested in the upper | ||
| 270 | // limit. Verified with a compiler assert in .cpp. | ||
| 271 | union __sanitizer_pthread_attr_t { | ||
| 272 | char size[128]; | ||
| 273 | void *align; | ||
| 274 | }; | ||
| 275 | |||
| 276 | const unsigned old_sigset_t_sz = sizeof(unsigned long); | ||
| 277 | |||
| 278 | struct __sanitizer_sigset_t { | ||
| 279 | // uint32_t * 4 | ||
| 280 | unsigned int __bits[4]; | ||
| 281 | }; | ||
| 282 | |||
| 283 | typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t; | ||
| 284 | |||
| 285 | struct __sanitizer_siginfo { | ||
| 286 | // The size is determined by looking at sizeof of real siginfo_t on linux. | ||
| 287 | u64 opaque[128 / sizeof(u64)]; | ||
| 288 | }; | ||
| 289 | |||
| 290 | using __sanitizer_sighandler_ptr = void (*)(int sig); | ||
| 291 | using __sanitizer_sigactionhandler_ptr = void (*)(int sig, | ||
| 292 | __sanitizer_siginfo *siginfo, | ||
| 293 | void *uctx); | ||
| 294 | |||
| 295 | struct __sanitizer_sigaction { | ||
| 296 | union { | ||
| 297 | __sanitizer_sigactionhandler_ptr sigaction; | ||
| 298 | __sanitizer_sighandler_ptr handler; | ||
| 299 | }; | ||
| 300 | int sa_flags; | ||
| 301 | __sanitizer_sigset_t sa_mask; | ||
| 302 | }; | ||
| 303 | |||
| 304 | struct __sanitizer_sem_t { | ||
| 305 | u32 data[4]; | ||
| 306 | }; | ||
| 307 | |||
| 308 | extern const uptr sig_ign; | ||
| 309 | extern const uptr sig_dfl; | ||
| 310 | extern const uptr sig_err; | ||
| 311 | extern const uptr sa_siginfo; | ||
| 312 | |||
| 313 | extern int af_inet; | ||
| 314 | extern int af_inet6; | ||
| 315 | uptr __sanitizer_in_addr_sz(int af); | ||
| 316 | |||
| 317 | struct __sanitizer_dl_phdr_info { | ||
| 318 | uptr dlpi_addr; | ||
| 319 | const char *dlpi_name; | ||
| 320 | const void *dlpi_phdr; | ||
| 321 | short dlpi_phnum; | ||
| 322 | }; | ||
| 323 | |||
| 324 | extern unsigned struct_ElfW_Phdr_sz; | ||
| 325 | |||
| 326 | struct __sanitizer_addrinfo { | ||
| 327 | int ai_flags; | ||
| 328 | int ai_family; | ||
| 329 | int ai_socktype; | ||
| 330 | int ai_protocol; | ||
| 331 | unsigned ai_addrlen; | ||
| 332 | char *ai_canonname; | ||
| 333 | void *ai_addr; | ||
| 334 | struct __sanitizer_addrinfo *ai_next; | ||
| 335 | }; | ||
| 336 | |||
| 337 | struct __sanitizer_hostent { | ||
| 338 | char *h_name; | ||
| 339 | char **h_aliases; | ||
| 340 | int h_addrtype; | ||
| 341 | int h_length; | ||
| 342 | char **h_addr_list; | ||
| 343 | }; | ||
| 344 | |||
| 345 | struct __sanitizer_pollfd { | ||
| 346 | int fd; | ||
| 347 | short events; | ||
| 348 | short revents; | ||
| 349 | }; | ||
| 350 | |||
| 351 | typedef unsigned __sanitizer_nfds_t; | ||
| 352 | |||
| 353 | struct __sanitizer_glob_t { | ||
| 354 | uptr gl_pathc; | ||
| 355 | uptr gl_matchc; | ||
| 356 | uptr gl_offs; | ||
| 357 | int gl_flags; | ||
| 358 | char **gl_pathv; | ||
| 359 | int (*gl_errfunc)(const char *, int); | ||
| 360 | void (*gl_closedir)(void *dirp); | ||
| 361 | struct dirent *(*gl_readdir)(void *dirp); | ||
| 362 | void *(*gl_opendir)(const char *); | ||
| 363 | int (*gl_lstat)(const char *, void * /* struct stat* */); | ||
| 364 | int (*gl_stat)(const char *, void * /* struct stat* */); | ||
| 365 | }; | ||
| 366 | |||
| 367 | extern int glob_nomatch; | ||
| 368 | extern int glob_altdirfunc; | ||
| 369 | |||
| 370 | extern unsigned path_max; | ||
| 371 | |||
| 372 | struct __sanitizer_wordexp_t { | ||
| 373 | uptr we_wordc; | ||
| 374 | char **we_wordv; | ||
| 375 | uptr we_offs; | ||
| 376 | char *we_strings; | ||
| 377 | uptr we_nbytes; | ||
| 378 | }; | ||
| 379 | |||
| 380 | typedef void __sanitizer_FILE; | ||
| 381 | |||
| 382 | extern unsigned struct_shminfo_sz; | ||
| 383 | extern unsigned struct_shm_info_sz; | ||
| 384 | extern int shmctl_ipc_stat; | ||
| 385 | extern int shmctl_ipc_info; | ||
| 386 | extern int shmctl_shm_info; | ||
| 387 | extern int shmctl_shm_stat; | ||
| 388 | |||
| 389 | extern unsigned struct_utmpx_sz; | ||
| 390 | |||
| 391 | extern int map_fixed; | ||
| 392 | |||
| 393 | // ioctl arguments | ||
| 394 | struct __sanitizer_ifconf { | ||
| 395 | int ifc_len; | ||
| 396 | union { | ||
| 397 | void *ifcu_req; | ||
| 398 | } ifc_ifcu; | ||
| 399 | }; | ||
| 400 | |||
| 401 | #define IOC_NRBITS 8 | ||
| 402 | #define IOC_TYPEBITS 8 | ||
| 403 | #if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__) | ||
| 404 | #define IOC_SIZEBITS 13 | ||
| 405 | #define IOC_DIRBITS 3 | ||
| 406 | #define IOC_NONE 1U | ||
| 407 | #define IOC_WRITE 4U | ||
| 408 | #define IOC_READ 2U | ||
| 409 | #else | ||
| 410 | #define IOC_SIZEBITS 14 | ||
| 411 | #define IOC_DIRBITS 2 | ||
| 412 | #define IOC_NONE 0U | ||
| 413 | #define IOC_WRITE 1U | ||
| 414 | #define IOC_READ 2U | ||
| 415 | #endif | ||
| 416 | #define IOC_NRMASK ((1 << IOC_NRBITS) - 1) | ||
| 417 | #define IOC_TYPEMASK ((1 << IOC_TYPEBITS) - 1) | ||
| 418 | #define IOC_SIZEMASK ((1 << IOC_SIZEBITS) - 1) | ||
| 419 | #if defined(IOC_DIRMASK) | ||
| 420 | #undef IOC_DIRMASK | ||
| 421 | #endif | ||
| 422 | #define IOC_DIRMASK ((1 << IOC_DIRBITS) - 1) | ||
| 423 | #define IOC_NRSHIFT 0 | ||
| 424 | #define IOC_TYPESHIFT (IOC_NRSHIFT + IOC_NRBITS) | ||
| 425 | #define IOC_SIZESHIFT (IOC_TYPESHIFT + IOC_TYPEBITS) | ||
| 426 | #define IOC_DIRSHIFT (IOC_SIZESHIFT + IOC_SIZEBITS) | ||
| 427 | #define EVIOC_EV_MAX 0x1f | ||
| 428 | #define EVIOC_ABS_MAX 0x3f | ||
| 429 | |||
| 430 | #define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK) | ||
| 431 | #define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK) | ||
| 432 | #define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK) | ||
| 433 | #define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) | ||
| 434 | |||
| 435 | extern unsigned struct_ifreq_sz; | ||
| 436 | extern unsigned struct_termios_sz; | ||
| 437 | extern unsigned struct_winsize_sz; | ||
| 438 | |||
| 439 | extern unsigned struct_copr_buffer_sz; | ||
| 440 | extern unsigned struct_copr_debug_buf_sz; | ||
| 441 | extern unsigned struct_copr_msg_sz; | ||
| 442 | extern unsigned struct_midi_info_sz; | ||
| 443 | extern unsigned struct_mtget_sz; | ||
| 444 | extern unsigned struct_mtop_sz; | ||
| 445 | extern unsigned struct_rtentry_sz; | ||
| 446 | extern unsigned struct_sbi_instrument_sz; | ||
| 447 | extern unsigned struct_seq_event_rec_sz; | ||
| 448 | extern unsigned struct_synth_info_sz; | ||
| 449 | extern unsigned struct_vt_mode_sz; | ||
| 450 | |||
| 451 | extern const unsigned long __sanitizer_bufsiz; | ||
| 452 | extern unsigned struct_audio_buf_info_sz; | ||
| 453 | extern unsigned struct_ppp_stats_sz; | ||
| 454 | extern unsigned struct_sioc_sg_req_sz; | ||
| 455 | extern unsigned struct_sioc_vif_req_sz; | ||
| 456 | |||
| 457 | // ioctl request identifiers | ||
| 458 | |||
| 459 | // A special value to mark ioctls that are not present on the target platform, | ||
| 460 | // when it can not be determined without including any system headers. | ||
| 461 | extern const unsigned IOCTL_NOT_PRESENT; | ||
| 462 | |||
| 463 | extern unsigned IOCTL_FIOASYNC; | ||
| 464 | extern unsigned IOCTL_FIOCLEX; | ||
| 465 | extern unsigned IOCTL_FIOGETOWN; | ||
| 466 | extern unsigned IOCTL_FIONBIO; | ||
| 467 | extern unsigned IOCTL_FIONCLEX; | ||
| 468 | extern unsigned IOCTL_FIOSETOWN; | ||
| 469 | extern unsigned IOCTL_SIOCADDMULTI; | ||
| 470 | extern unsigned IOCTL_SIOCATMARK; | ||
| 471 | extern unsigned IOCTL_SIOCDELMULTI; | ||
| 472 | extern unsigned IOCTL_SIOCGIFADDR; | ||
| 473 | extern unsigned IOCTL_SIOCGIFBRDADDR; | ||
| 474 | extern unsigned IOCTL_SIOCGIFCONF; | ||
| 475 | extern unsigned IOCTL_SIOCGIFDSTADDR; | ||
| 476 | extern unsigned IOCTL_SIOCGIFFLAGS; | ||
| 477 | extern unsigned IOCTL_SIOCGIFMETRIC; | ||
| 478 | extern unsigned IOCTL_SIOCGIFMTU; | ||
| 479 | extern unsigned IOCTL_SIOCGIFNETMASK; | ||
| 480 | extern unsigned IOCTL_SIOCGPGRP; | ||
| 481 | extern unsigned IOCTL_SIOCSIFADDR; | ||
| 482 | extern unsigned IOCTL_SIOCSIFBRDADDR; | ||
| 483 | extern unsigned IOCTL_SIOCSIFDSTADDR; | ||
| 484 | extern unsigned IOCTL_SIOCSIFFLAGS; | ||
| 485 | extern unsigned IOCTL_SIOCSIFMETRIC; | ||
| 486 | extern unsigned IOCTL_SIOCSIFMTU; | ||
| 487 | extern unsigned IOCTL_SIOCSIFNETMASK; | ||
| 488 | extern unsigned IOCTL_SIOCSPGRP; | ||
| 489 | extern unsigned IOCTL_TIOCCONS; | ||
| 490 | extern unsigned IOCTL_TIOCEXCL; | ||
| 491 | extern unsigned IOCTL_TIOCGETD; | ||
| 492 | extern unsigned IOCTL_TIOCGPGRP; | ||
| 493 | extern unsigned IOCTL_TIOCGWINSZ; | ||
| 494 | extern unsigned IOCTL_TIOCMBIC; | ||
| 495 | extern unsigned IOCTL_TIOCMBIS; | ||
| 496 | extern unsigned IOCTL_TIOCMGET; | ||
| 497 | extern unsigned IOCTL_TIOCMSET; | ||
| 498 | extern unsigned IOCTL_TIOCNOTTY; | ||
| 499 | extern unsigned IOCTL_TIOCNXCL; | ||
| 500 | extern unsigned IOCTL_TIOCOUTQ; | ||
| 501 | extern unsigned IOCTL_TIOCPKT; | ||
| 502 | extern unsigned IOCTL_TIOCSCTTY; | ||
| 503 | extern unsigned IOCTL_TIOCSETD; | ||
| 504 | extern unsigned IOCTL_TIOCSPGRP; | ||
| 505 | extern unsigned IOCTL_TIOCSTI; | ||
| 506 | extern unsigned IOCTL_TIOCSWINSZ; | ||
| 507 | extern unsigned IOCTL_SIOCGETSGCNT; | ||
| 508 | extern unsigned IOCTL_SIOCGETVIFCNT; | ||
| 509 | extern unsigned IOCTL_MTIOCGET; | ||
| 510 | extern unsigned IOCTL_MTIOCTOP; | ||
| 511 | extern unsigned IOCTL_SIOCADDRT; | ||
| 512 | extern unsigned IOCTL_SIOCDELRT; | ||
| 513 | extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; | ||
| 514 | extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; | ||
| 515 | extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; | ||
| 516 | extern unsigned IOCTL_SNDCTL_DSP_POST; | ||
| 517 | extern unsigned IOCTL_SNDCTL_DSP_RESET; | ||
| 518 | extern unsigned IOCTL_SNDCTL_DSP_SETFMT; | ||
| 519 | extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; | ||
| 520 | extern unsigned IOCTL_SNDCTL_DSP_SPEED; | ||
| 521 | extern unsigned IOCTL_SNDCTL_DSP_STEREO; | ||
| 522 | extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; | ||
| 523 | extern unsigned IOCTL_SNDCTL_DSP_SYNC; | ||
| 524 | extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE; | ||
| 525 | extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR; | ||
| 526 | extern unsigned IOCTL_SNDCTL_MIDI_INFO; | ||
| 527 | extern unsigned IOCTL_SNDCTL_MIDI_PRETIME; | ||
| 528 | extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE; | ||
| 529 | extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT; | ||
| 530 | extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT; | ||
| 531 | extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS; | ||
| 532 | extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS; | ||
| 533 | extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND; | ||
| 534 | extern unsigned IOCTL_SNDCTL_SEQ_PANIC; | ||
| 535 | extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE; | ||
| 536 | extern unsigned IOCTL_SNDCTL_SEQ_RESET; | ||
| 537 | extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES; | ||
| 538 | extern unsigned IOCTL_SNDCTL_SEQ_SYNC; | ||
| 539 | extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI; | ||
| 540 | extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD; | ||
| 541 | extern unsigned IOCTL_SNDCTL_SYNTH_INFO; | ||
| 542 | extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL; | ||
| 543 | extern unsigned IOCTL_SNDCTL_TMR_CONTINUE; | ||
| 544 | extern unsigned IOCTL_SNDCTL_TMR_METRONOME; | ||
| 545 | extern unsigned IOCTL_SNDCTL_TMR_SELECT; | ||
| 546 | extern unsigned IOCTL_SNDCTL_TMR_SOURCE; | ||
| 547 | extern unsigned IOCTL_SNDCTL_TMR_START; | ||
| 548 | extern unsigned IOCTL_SNDCTL_TMR_STOP; | ||
| 549 | extern unsigned IOCTL_SNDCTL_TMR_TEMPO; | ||
| 550 | extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE; | ||
| 551 | extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM; | ||
| 552 | extern unsigned IOCTL_SOUND_MIXER_READ_BASS; | ||
| 553 | extern unsigned IOCTL_SOUND_MIXER_READ_CAPS; | ||
| 554 | extern unsigned IOCTL_SOUND_MIXER_READ_CD; | ||
| 555 | extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK; | ||
| 556 | extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE; | ||
| 557 | extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN; | ||
| 558 | extern unsigned IOCTL_SOUND_MIXER_READ_IMIX; | ||
| 559 | extern unsigned IOCTL_SOUND_MIXER_READ_LINE1; | ||
| 560 | extern unsigned IOCTL_SOUND_MIXER_READ_LINE2; | ||
| 561 | extern unsigned IOCTL_SOUND_MIXER_READ_LINE3; | ||
| 562 | extern unsigned IOCTL_SOUND_MIXER_READ_LINE; | ||
| 563 | extern unsigned IOCTL_SOUND_MIXER_READ_LOUD; | ||
| 564 | extern unsigned IOCTL_SOUND_MIXER_READ_MIC; | ||
| 565 | extern unsigned IOCTL_SOUND_MIXER_READ_MUTE; | ||
| 566 | extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN; | ||
| 567 | extern unsigned IOCTL_SOUND_MIXER_READ_PCM; | ||
| 568 | extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV; | ||
| 569 | extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK; | ||
| 570 | extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC; | ||
| 571 | extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER; | ||
| 572 | extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS; | ||
| 573 | extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH; | ||
| 574 | extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE; | ||
| 575 | extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME; | ||
| 576 | extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM; | ||
| 577 | extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS; | ||
| 578 | extern unsigned IOCTL_SOUND_MIXER_WRITE_CD; | ||
| 579 | extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE; | ||
| 580 | extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN; | ||
| 581 | extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX; | ||
| 582 | extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1; | ||
| 583 | extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2; | ||
| 584 | extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3; | ||
| 585 | extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE; | ||
| 586 | extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD; | ||
| 587 | extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC; | ||
| 588 | extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE; | ||
| 589 | extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN; | ||
| 590 | extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM; | ||
| 591 | extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV; | ||
| 592 | extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC; | ||
| 593 | extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER; | ||
| 594 | extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH; | ||
| 595 | extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE; | ||
| 596 | extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME; | ||
| 597 | extern unsigned IOCTL_SOUND_PCM_READ_BITS; | ||
| 598 | extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; | ||
| 599 | extern unsigned IOCTL_SOUND_PCM_READ_FILTER; | ||
| 600 | extern unsigned IOCTL_SOUND_PCM_READ_RATE; | ||
| 601 | extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS; | ||
| 602 | extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; | ||
| 603 | extern unsigned IOCTL_VT_ACTIVATE; | ||
| 604 | extern unsigned IOCTL_VT_GETMODE; | ||
| 605 | extern unsigned IOCTL_VT_OPENQRY; | ||
| 606 | extern unsigned IOCTL_VT_RELDISP; | ||
| 607 | extern unsigned IOCTL_VT_SETMODE; | ||
| 608 | extern unsigned IOCTL_VT_WAITACTIVE; | ||
| 609 | extern unsigned IOCTL_GIO_SCRNMAP; | ||
| 610 | extern unsigned IOCTL_KDDISABIO; | ||
| 611 | extern unsigned IOCTL_KDENABIO; | ||
| 612 | extern unsigned IOCTL_KDGETLED; | ||
| 613 | extern unsigned IOCTL_KDGETMODE; | ||
| 614 | extern unsigned IOCTL_KDGKBMODE; | ||
| 615 | extern unsigned IOCTL_KDGKBTYPE; | ||
| 616 | extern unsigned IOCTL_KDMKTONE; | ||
| 617 | extern unsigned IOCTL_KDSETLED; | ||
| 618 | extern unsigned IOCTL_KDSETMODE; | ||
| 619 | extern unsigned IOCTL_KDSKBMODE; | ||
| 620 | |||
| 621 | extern const int si_SEGV_MAPERR; | ||
| 622 | extern const int si_SEGV_ACCERR; | ||
| 623 | |||
| 624 | struct __sanitizer_cap_rights { | ||
| 625 | u64 cr_rights[2]; | ||
| 626 | }; | ||
| 627 | |||
| 628 | typedef struct __sanitizer_cap_rights __sanitizer_cap_rights_t; | ||
| 629 | extern unsigned struct_cap_rights_sz; | ||
| 630 | |||
| 631 | extern unsigned struct_fstab_sz; | ||
| 632 | extern unsigned struct_StringList_sz; | ||
| 633 | } // namespace __sanitizer | ||
| 634 | |||
| 635 | #define CHECK_TYPE_SIZE(TYPE) \ | ||
| 636 | COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) | ||
| 637 | |||
| 638 | #define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ | ||
| 639 | COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \ | ||
| 640 | sizeof(((CLASS *)NULL)->MEMBER)); \ | ||
| 641 | COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ | ||
| 642 | offsetof(CLASS, MEMBER)) | ||
| 643 | |||
| 644 | // For sigaction, which is a function and struct at the same time, | ||
| 645 | // and thus requires explicit "struct" in sizeof() expression. | ||
| 646 | #define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ | ||
| 647 | COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \ | ||
| 648 | sizeof(((struct CLASS *)NULL)->MEMBER)); \ | ||
| 649 | COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ | ||
| 650 | offsetof(struct CLASS, MEMBER)) | ||
| 651 | |||
| 652 | #define SIGACTION_SYMNAME sigaction | ||
| 653 | |||
| 654 | #endif | ||
| 655 | |||
| 656 | #endif // SANITIZER_FREEBSD | ||
lib/tsan/sanitizer_common/sanitizer_platform_limits_linux.cpp created+108| ... | @@ -0,0 +1,108 @@ | ||
| 1 | //===-- sanitizer_platform_limits_linux.cpp -------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer common code. | ||
| 10 | // | ||
| 11 | // Sizes and layouts of linux kernel data structures. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | // This is a separate compilation unit for linux headers that conflict with | ||
| 15 | // userspace headers. | ||
| 16 | // Most "normal" includes go in sanitizer_platform_limits_posix.cpp | ||
| 17 | |||
| 18 | #include "sanitizer_platform.h" | ||
| 19 | #if SANITIZER_LINUX | ||
| 20 | |||
| 21 | #include "sanitizer_internal_defs.h" | ||
| 22 | #include "sanitizer_platform_limits_posix.h" | ||
| 23 | |||
| 24 | // For offsetof -> __builtin_offsetof definition. | ||
| 25 | #include <stddef.h> | ||
| 26 | |||
| 27 | // With old kernels (and even new kernels on powerpc) asm/stat.h uses types that | ||
| 28 | // are not defined anywhere in userspace headers. Fake them. This seems to work | ||
| 29 | // fine with newer headers, too. | ||
| 30 | #include <linux/posix_types.h> | ||
| 31 | #if defined(__x86_64__) || defined(__mips__) | ||
| 32 | #include <sys/stat.h> | ||
| 33 | #else | ||
| 34 | #define ino_t __kernel_ino_t | ||
| 35 | #define mode_t __kernel_mode_t | ||
| 36 | #define nlink_t __kernel_nlink_t | ||
| 37 | #define uid_t __kernel_uid_t | ||
| 38 | #define gid_t __kernel_gid_t | ||
| 39 | #define off_t __kernel_off_t | ||
| 40 | #define time_t __kernel_time_t | ||
| 41 | // This header seems to contain the definitions of _kernel_ stat* structs. | ||
| 42 | #include <asm/stat.h> | ||
| 43 | #undef ino_t | ||
| 44 | #undef mode_t | ||
| 45 | #undef nlink_t | ||
| 46 | #undef uid_t | ||
| 47 | #undef gid_t | ||
| 48 | #undef off_t | ||
| 49 | #endif | ||
| 50 | |||
| 51 | #include <linux/aio_abi.h> | ||
| 52 | |||
| 53 | #if !SANITIZER_ANDROID | ||
| 54 | #include <sys/statfs.h> | ||
| 55 | #include <linux/perf_event.h> | ||
| 56 | #endif | ||
| 57 | |||
| 58 | using namespace __sanitizer; | ||
| 59 | |||
| 60 | namespace __sanitizer { | ||
| 61 | #if !SANITIZER_ANDROID | ||
| 62 | unsigned struct_statfs64_sz = sizeof(struct statfs64); | ||
| 63 | #endif | ||
| 64 | } // namespace __sanitizer | ||
| 65 | |||
| 66 | #if !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__aarch64__)\ | ||
| 67 | && !defined(__mips__) && !defined(__s390__)\ | ||
| 68 | && !defined(__sparc__) && !defined(__riscv) | ||
| 69 | COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat)); | ||
| 70 | #endif | ||
| 71 | |||
| 72 | COMPILER_CHECK(struct_kernel_stat_sz == sizeof(struct stat)); | ||
| 73 | |||
| 74 | #if defined(__i386__) | ||
| 75 | COMPILER_CHECK(struct_kernel_stat64_sz == sizeof(struct stat64)); | ||
| 76 | #endif | ||
| 77 | |||
| 78 | CHECK_TYPE_SIZE(io_event); | ||
| 79 | CHECK_SIZE_AND_OFFSET(io_event, data); | ||
| 80 | CHECK_SIZE_AND_OFFSET(io_event, obj); | ||
| 81 | CHECK_SIZE_AND_OFFSET(io_event, res); | ||
| 82 | CHECK_SIZE_AND_OFFSET(io_event, res2); | ||
| 83 | |||
| 84 | #if !SANITIZER_ANDROID | ||
| 85 | COMPILER_CHECK(sizeof(struct __sanitizer_perf_event_attr) <= | ||
| 86 | sizeof(struct perf_event_attr)); | ||
| 87 | CHECK_SIZE_AND_OFFSET(perf_event_attr, type); | ||
| 88 | CHECK_SIZE_AND_OFFSET(perf_event_attr, size); | ||
| 89 | #endif | ||
| 90 | |||
| 91 | COMPILER_CHECK(iocb_cmd_pread == IOCB_CMD_PREAD); | ||
| 92 | COMPILER_CHECK(iocb_cmd_pwrite == IOCB_CMD_PWRITE); | ||
| 93 | #if !SANITIZER_ANDROID | ||
| 94 | COMPILER_CHECK(iocb_cmd_preadv == IOCB_CMD_PREADV); | ||
| 95 | COMPILER_CHECK(iocb_cmd_pwritev == IOCB_CMD_PWRITEV); | ||
| 96 | #endif | ||
| 97 | |||
| 98 | CHECK_TYPE_SIZE(iocb); | ||
| 99 | CHECK_SIZE_AND_OFFSET(iocb, aio_data); | ||
| 100 | // Skip aio_key, it's weird. | ||
| 101 | CHECK_SIZE_AND_OFFSET(iocb, aio_lio_opcode); | ||
| 102 | CHECK_SIZE_AND_OFFSET(iocb, aio_reqprio); | ||
| 103 | CHECK_SIZE_AND_OFFSET(iocb, aio_fildes); | ||
| 104 | CHECK_SIZE_AND_OFFSET(iocb, aio_buf); | ||
| 105 | CHECK_SIZE_AND_OFFSET(iocb, aio_nbytes); | ||
| 106 | CHECK_SIZE_AND_OFFSET(iocb, aio_offset); | ||
| 107 | |||
| 108 | #endif // SANITIZER_LINUX | ||
lib/tsan/sanitizer_common/sanitizer_platform_limits_netbsd.cpp created+2586| ... | @@ -0,0 +1,2586 @@ | ||
| 1 | //===-- sanitizer_platform_limits_netbsd.cpp ------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer common code. | ||
| 10 | // | ||
| 11 | // Sizes and layouts of platform-specific NetBSD data structures. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_platform.h" | ||
| 15 | |||
| 16 | #if SANITIZER_NETBSD | ||
| 17 | |||
| 18 | #define _KMEMUSER | ||
| 19 | #define RAY_DO_SIGLEV | ||
| 20 | #define __LEGACY_PT_LWPINFO | ||
| 21 | |||
| 22 | // clang-format off | ||
| 23 | #include <sys/param.h> | ||
| 24 | #include <sys/types.h> | ||
| 25 | #include <sys/sysctl.h> | ||
| 26 | #include <sys/disk.h> | ||
| 27 | #include <sys/disklabel.h> | ||
| 28 | #include <sys/mount.h> | ||
| 29 | #include <sys/agpio.h> | ||
| 30 | #include <sys/ataio.h> | ||
| 31 | #include <sys/audioio.h> | ||
| 32 | #include <sys/cdbr.h> | ||
| 33 | #include <sys/cdio.h> | ||
| 34 | #include <sys/chio.h> | ||
| 35 | #include <sys/clockctl.h> | ||
| 36 | #include <sys/cpuio.h> | ||
| 37 | #include <sys/dkio.h> | ||
| 38 | #include <sys/drvctlio.h> | ||
| 39 | #include <sys/dvdio.h> | ||
| 40 | #include <sys/envsys.h> | ||
| 41 | #include <sys/event.h> | ||
| 42 | #include <sys/fdio.h> | ||
| 43 | #include <sys/filio.h> | ||
| 44 | #include <sys/gpio.h> | ||
| 45 | #include <sys/ioctl.h> | ||
| 46 | #include <sys/ioctl_compat.h> | ||
| 47 | #include <sys/joystick.h> | ||
| 48 | #include <sys/ksyms.h> | ||
| 49 | #include <sys/lua.h> | ||
| 50 | #include <sys/midiio.h> | ||
| 51 | #include <sys/mtio.h> | ||
| 52 | #include <sys/power.h> | ||
| 53 | #include <sys/radioio.h> | ||
| 54 | #include <sys/rndio.h> | ||
| 55 | #include <sys/scanio.h> | ||
| 56 | #include <sys/scsiio.h> | ||
| 57 | #include <sys/sockio.h> | ||
| 58 | #include <sys/timepps.h> | ||
| 59 | #include <sys/ttycom.h> | ||
| 60 | #include <sys/verified_exec.h> | ||
| 61 | #include <sys/videoio.h> | ||
| 62 | #include <sys/wdog.h> | ||
| 63 | #include <sys/event.h> | ||
| 64 | #include <sys/filio.h> | ||
| 65 | #include <sys/ipc.h> | ||
| 66 | #include <sys/ipmi.h> | ||
| 67 | #include <sys/kcov.h> | ||
| 68 | #include <sys/mman.h> | ||
| 69 | #include <sys/module.h> | ||
| 70 | #include <sys/mount.h> | ||
| 71 | #include <sys/mqueue.h> | ||
| 72 | #include <sys/msg.h> | ||
| 73 | #include <sys/mtio.h> | ||
| 74 | #include <sys/ptrace.h> | ||
| 75 | |||
| 76 | // Compat for NetBSD < 9.99.30. | ||
| 77 | #ifndef PT_LWPSTATUS | ||
| 78 | #define PT_LWPSTATUS 24 | ||
| 79 | #endif | ||
| 80 | #ifndef PT_LWPNEXT | ||
| 81 | #define PT_LWPNEXT 25 | ||
| 82 | #endif | ||
| 83 | |||
| 84 | #include <sys/resource.h> | ||
| 85 | #include <sys/sem.h> | ||
| 86 | #include <sys/sha1.h> | ||
| 87 | #include <sys/sha2.h> | ||
| 88 | #include <sys/shm.h> | ||
| 89 | #include <sys/signal.h> | ||
| 90 | #include <sys/socket.h> | ||
| 91 | #include <sys/sockio.h> | ||
| 92 | #include <sys/soundcard.h> | ||
| 93 | #include <sys/stat.h> | ||
| 94 | #include <sys/statvfs.h> | ||
| 95 | #include <sys/time.h> | ||
| 96 | #include <sys/timeb.h> | ||
| 97 | #include <sys/times.h> | ||
| 98 | #include <sys/timespec.h> | ||
| 99 | #include <sys/timex.h> | ||
| 100 | #include <sys/types.h> | ||
| 101 | #include <sys/ucontext.h> | ||
| 102 | #include <sys/utsname.h> | ||
| 103 | #include <altq/altq.h> | ||
| 104 | #include <altq/altq_afmap.h> | ||
| 105 | #include <altq/altq_blue.h> | ||
| 106 | #include <altq/altq_cbq.h> | ||
| 107 | #include <altq/altq_cdnr.h> | ||
| 108 | #include <altq/altq_fifoq.h> | ||
| 109 | #include <altq/altq_hfsc.h> | ||
| 110 | #include <altq/altq_jobs.h> | ||
| 111 | #include <altq/altq_priq.h> | ||
| 112 | #include <altq/altq_red.h> | ||
| 113 | #include <altq/altq_rio.h> | ||
| 114 | #include <altq/altq_wfq.h> | ||
| 115 | #include <arpa/inet.h> | ||
| 116 | #include <crypto/cryptodev.h> | ||
| 117 | #include <dev/apm/apmio.h> | ||
| 118 | #include <dev/dm/netbsd-dm.h> | ||
| 119 | #include <dev/dmover/dmover_io.h> | ||
| 120 | #include <dev/dtv/dtvio_demux.h> | ||
| 121 | #include <dev/dtv/dtvio_frontend.h> | ||
| 122 | #if !__NetBSD_Prereq__(9, 99, 26) | ||
| 123 | #include <dev/filemon/filemon.h> | ||
| 124 | #else | ||
| 125 | #define FILEMON_SET_FD _IOWR('S', 1, int) | ||
| 126 | #define FILEMON_SET_PID _IOWR('S', 2, pid_t) | ||
| 127 | #endif | ||
| 128 | #include <dev/hdaudio/hdaudioio.h> | ||
| 129 | #include <dev/hdmicec/hdmicecio.h> | ||
| 130 | #include <dev/hpc/hpcfbio.h> | ||
| 131 | #include <dev/i2o/iopio.h> | ||
| 132 | #include <dev/ic/athioctl.h> | ||
| 133 | #include <dev/ic/bt8xx.h> | ||
| 134 | #include <dev/ic/icp_ioctl.h> | ||
| 135 | #include <dev/ic/isp_ioctl.h> | ||
| 136 | #include <dev/ic/mlxio.h> | ||
| 137 | #include <dev/ic/qemufwcfgio.h> | ||
| 138 | #include <dev/ic/nvmeio.h> | ||
| 139 | #include <dev/ir/irdaio.h> | ||
| 140 | #include <dev/isa/isvio.h> | ||
| 141 | #include <dev/isa/wtreg.h> | ||
| 142 | #include <dev/iscsi/iscsi_ioctl.h> | ||
| 143 | #include <dev/ofw/openfirmio.h> | ||
| 144 | #include <dev/pci/amrio.h> | ||
| 145 | #include <dev/pci/mlyreg.h> | ||
| 146 | #include <dev/pci/mlyio.h> | ||
| 147 | #include <dev/pci/pciio.h> | ||
| 148 | #include <dev/pci/tweio.h> | ||
| 149 | #include <dev/pcmcia/if_cnwioctl.h> | ||
| 150 | #include <net/bpf.h> | ||
| 151 | #include <net/if_gre.h> | ||
| 152 | #include <net/ppp_defs.h> | ||
| 153 | #include <net/if_ppp.h> | ||
| 154 | #include <net/if_pppoe.h> | ||
| 155 | #include <net/if_sppp.h> | ||
| 156 | #include <net/if_srt.h> | ||
| 157 | #include <net/if_tap.h> | ||
| 158 | #include <net/if_tun.h> | ||
| 159 | #include <net/npf.h> | ||
| 160 | #include <net/pfvar.h> | ||
| 161 | #include <net/slip.h> | ||
| 162 | #include <netbt/hci.h> | ||
| 163 | #include <netinet/ip_compat.h> | ||
| 164 | #if __has_include(<netinet/ip_fil.h>) | ||
| 165 | #include <netinet/ip_fil.h> | ||
| 166 | #include <netinet/ip_nat.h> | ||
| 167 | #include <netinet/ip_proxy.h> | ||
| 168 | #else | ||
| 169 | /* Fallback for MKIPFILTER=no */ | ||
| 170 | |||
| 171 | typedef struct ap_control { | ||
| 172 | char apc_label[16]; | ||
| 173 | char apc_config[16]; | ||
| 174 | unsigned char apc_p; | ||
| 175 | unsigned long apc_cmd; | ||
| 176 | unsigned long apc_arg; | ||
| 177 | void *apc_data; | ||
| 178 | size_t apc_dsize; | ||
| 179 | } ap_ctl_t; | ||
| 180 | |||
| 181 | typedef struct ipftq { | ||
| 182 | ipfmutex_t ifq_lock; | ||
| 183 | unsigned int ifq_ttl; | ||
| 184 | void *ifq_head; | ||
| 185 | void **ifq_tail; | ||
| 186 | void *ifq_next; | ||
| 187 | void **ifq_pnext; | ||
| 188 | int ifq_ref; | ||
| 189 | unsigned int ifq_flags; | ||
| 190 | } ipftq_t; | ||
| 191 | |||
| 192 | typedef struct ipfobj { | ||
| 193 | uint32_t ipfo_rev; | ||
| 194 | uint32_t ipfo_size; | ||
| 195 | void *ipfo_ptr; | ||
| 196 | int ipfo_type; | ||
| 197 | int ipfo_offset; | ||
| 198 | int ipfo_retval; | ||
| 199 | unsigned char ipfo_xxxpad[28]; | ||
| 200 | } ipfobj_t; | ||
| 201 | |||
| 202 | #define SIOCADNAT _IOW('r', 60, struct ipfobj) | ||
| 203 | #define SIOCRMNAT _IOW('r', 61, struct ipfobj) | ||
| 204 | #define SIOCGNATS _IOWR('r', 62, struct ipfobj) | ||
| 205 | #define SIOCGNATL _IOWR('r', 63, struct ipfobj) | ||
| 206 | #define SIOCPURGENAT _IOWR('r', 100, struct ipfobj) | ||
| 207 | #endif | ||
| 208 | #include <netinet6/in6_var.h> | ||
| 209 | #include <netinet6/nd6.h> | ||
| 210 | #if !__NetBSD_Prereq__(9, 99, 51) | ||
| 211 | #include <netsmb/smb_dev.h> | ||
| 212 | #else | ||
| 213 | struct smbioc_flags { | ||
| 214 | int ioc_level; | ||
| 215 | int ioc_mask; | ||
| 216 | int ioc_flags; | ||
| 217 | }; | ||
| 218 | struct smbioc_oshare { | ||
| 219 | int ioc_opt; | ||
| 220 | int ioc_stype; | ||
| 221 | char ioc_share[129]; | ||
| 222 | char ioc_password[129]; | ||
| 223 | uid_t ioc_owner; | ||
| 224 | gid_t ioc_group; | ||
| 225 | mode_t ioc_mode; | ||
| 226 | mode_t ioc_rights; | ||
| 227 | }; | ||
| 228 | struct smbioc_ossn { | ||
| 229 | int ioc_opt; | ||
| 230 | uint32_t ioc_svlen; | ||
| 231 | struct sockaddr *ioc_server; | ||
| 232 | uint32_t ioc_lolen; | ||
| 233 | struct sockaddr *ioc_local; | ||
| 234 | char ioc_srvname[16]; | ||
| 235 | int ioc_timeout; | ||
| 236 | int ioc_retrycount; | ||
| 237 | char ioc_localcs[16]; | ||
| 238 | char ioc_servercs[16]; | ||
| 239 | char ioc_user[129]; | ||
| 240 | char ioc_workgroup[129]; | ||
| 241 | char ioc_password[129]; | ||
| 242 | uid_t ioc_owner; | ||
| 243 | gid_t ioc_group; | ||
| 244 | mode_t ioc_mode; | ||
| 245 | mode_t ioc_rights; | ||
| 246 | }; | ||
| 247 | struct smbioc_lookup { | ||
| 248 | int ioc_level; | ||
| 249 | int ioc_flags; | ||
| 250 | struct smbioc_ossn ioc_ssn; | ||
| 251 | struct smbioc_oshare ioc_sh; | ||
| 252 | }; | ||
| 253 | struct smbioc_rq { | ||
| 254 | u_char ioc_cmd; | ||
| 255 | u_char ioc_twc; | ||
| 256 | void *ioc_twords; | ||
| 257 | u_short ioc_tbc; | ||
| 258 | void *ioc_tbytes; | ||
| 259 | int ioc_rpbufsz; | ||
| 260 | char *ioc_rpbuf; | ||
| 261 | u_char ioc_rwc; | ||
| 262 | u_short ioc_rbc; | ||
| 263 | }; | ||
| 264 | struct smbioc_rw { | ||
| 265 | u_int16_t ioc_fh; | ||
| 266 | char *ioc_base; | ||
| 267 | off_t ioc_offset; | ||
| 268 | int ioc_cnt; | ||
| 269 | }; | ||
| 270 | #define SMBIOC_OPENSESSION _IOW('n', 100, struct smbioc_ossn) | ||
| 271 | #define SMBIOC_OPENSHARE _IOW('n', 101, struct smbioc_oshare) | ||
| 272 | #define SMBIOC_REQUEST _IOWR('n', 102, struct smbioc_rq) | ||
| 273 | #define SMBIOC_T2RQ _IOWR('n', 103, struct smbioc_t2rq) | ||
| 274 | #define SMBIOC_SETFLAGS _IOW('n', 104, struct smbioc_flags) | ||
| 275 | #define SMBIOC_LOOKUP _IOW('n', 106, struct smbioc_lookup) | ||
| 276 | #define SMBIOC_READ _IOWR('n', 107, struct smbioc_rw) | ||
| 277 | #define SMBIOC_WRITE _IOWR('n', 108, struct smbioc_rw) | ||
| 278 | #endif | ||
| 279 | #include <dev/biovar.h> | ||
| 280 | #include <dev/bluetooth/btdev.h> | ||
| 281 | #include <dev/bluetooth/btsco.h> | ||
| 282 | #include <dev/ccdvar.h> | ||
| 283 | #include <dev/cgdvar.h> | ||
| 284 | #include <dev/fssvar.h> | ||
| 285 | #include <dev/kttcpio.h> | ||
| 286 | #include <dev/lockstat.h> | ||
| 287 | #include <dev/md.h> | ||
| 288 | #include <net/if_ether.h> | ||
| 289 | #include <dev/pcmcia/if_rayreg.h> | ||
| 290 | #include <stdio.h> | ||
| 291 | #include <dev/raidframe/raidframeio.h> | ||
| 292 | #include <dev/sbus/mbppio.h> | ||
| 293 | #include <dev/scsipi/ses.h> | ||
| 294 | #include <dev/spi/spi_io.h> | ||
| 295 | #include <dev/spkrio.h> | ||
| 296 | #include <dev/sun/disklabel.h> | ||
| 297 | #include <dev/sun/fbio.h> | ||
| 298 | #include <dev/sun/kbio.h> | ||
| 299 | #include <dev/sun/vuid_event.h> | ||
| 300 | #include <dev/tc/sticio.h> | ||
| 301 | #include <dev/usb/ukyopon.h> | ||
| 302 | #if !__NetBSD_Prereq__(9, 99, 44) | ||
| 303 | #include <dev/usb/urio.h> | ||
| 304 | #else | ||
| 305 | struct urio_command { | ||
| 306 | unsigned short length; | ||
| 307 | int request; | ||
| 308 | int requesttype; | ||
| 309 | int value; | ||
| 310 | int index; | ||
| 311 | void *buffer; | ||
| 312 | int timeout; | ||
| 313 | }; | ||
| 314 | #define URIO_SEND_COMMAND _IOWR('U', 200, struct urio_command) | ||
| 315 | #define URIO_RECV_COMMAND _IOWR('U', 201, struct urio_command) | ||
| 316 | #endif | ||
| 317 | #include <dev/usb/usb.h> | ||
| 318 | #include <dev/usb/utoppy.h> | ||
| 319 | #include <dev/vme/xio.h> | ||
| 320 | #include <dev/vndvar.h> | ||
| 321 | #include <dev/wscons/wsconsio.h> | ||
| 322 | #include <dev/wscons/wsdisplay_usl_io.h> | ||
| 323 | #include <fs/autofs/autofs_ioctl.h> | ||
| 324 | #include <dirent.h> | ||
| 325 | #include <dlfcn.h> | ||
| 326 | #include <glob.h> | ||
| 327 | #include <grp.h> | ||
| 328 | #include <ifaddrs.h> | ||
| 329 | #include <limits.h> | ||
| 330 | #include <link_elf.h> | ||
| 331 | #include <net/if.h> | ||
| 332 | #include <net/route.h> | ||
| 333 | #include <netdb.h> | ||
| 334 | #include <netinet/in.h> | ||
| 335 | #include <netinet/ip_mroute.h> | ||
| 336 | #include <netinet/sctp_uio.h> | ||
| 337 | #include <poll.h> | ||
| 338 | #include <pthread.h> | ||
| 339 | #include <pwd.h> | ||
| 340 | #include <semaphore.h> | ||
| 341 | #include <signal.h> | ||
| 342 | #include <stddef.h> | ||
| 343 | #include <md2.h> | ||
| 344 | #include <md4.h> | ||
| 345 | #include <md5.h> | ||
| 346 | #include <rmd160.h> | ||
| 347 | #include <soundcard.h> | ||
| 348 | #include <term.h> | ||
| 349 | #include <termios.h> | ||
| 350 | #include <time.h> | ||
| 351 | #include <ttyent.h> | ||
| 352 | #include <utime.h> | ||
| 353 | #include <utmp.h> | ||
| 354 | #include <utmpx.h> | ||
| 355 | #include <vis.h> | ||
| 356 | #include <wchar.h> | ||
| 357 | #include <wordexp.h> | ||
| 358 | #include <ttyent.h> | ||
| 359 | #include <fts.h> | ||
| 360 | #include <regex.h> | ||
| 361 | #include <fstab.h> | ||
| 362 | #include <stringlist.h> | ||
| 363 | |||
| 364 | #if defined(__x86_64__) | ||
| 365 | #include <nvmm.h> | ||
| 366 | #endif | ||
| 367 | // clang-format on | ||
| 368 | |||
| 369 | // Include these after system headers to avoid name clashes and ambiguities. | ||
| 370 | #include "sanitizer_internal_defs.h" | ||
| 371 | #include "sanitizer_libc.h" | ||
| 372 | #include "sanitizer_platform_limits_netbsd.h" | ||
| 373 | |||
| 374 | namespace __sanitizer { | ||
| 375 | void *__sanitizer_get_link_map_by_dlopen_handle(void* handle) { | ||
| 376 | void *p = nullptr; | ||
| 377 | return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr; | ||
| 378 | } | ||
| 379 | |||
| 380 | unsigned struct_utsname_sz = sizeof(struct utsname); | ||
| 381 | unsigned struct_stat_sz = sizeof(struct stat); | ||
| 382 | unsigned struct_rusage_sz = sizeof(struct rusage); | ||
| 383 | unsigned struct_tm_sz = sizeof(struct tm); | ||
| 384 | unsigned struct_passwd_sz = sizeof(struct passwd); | ||
| 385 | unsigned struct_group_sz = sizeof(struct group); | ||
| 386 | unsigned siginfo_t_sz = sizeof(siginfo_t); | ||
| 387 | unsigned struct_sigaction_sz = sizeof(struct sigaction); | ||
| 388 | unsigned struct_stack_t_sz = sizeof(stack_t); | ||
| 389 | unsigned struct_itimerval_sz = sizeof(struct itimerval); | ||
| 390 | unsigned pthread_t_sz = sizeof(pthread_t); | ||
| 391 | unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); | ||
| 392 | unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); | ||
| 393 | unsigned pid_t_sz = sizeof(pid_t); | ||
| 394 | unsigned timeval_sz = sizeof(timeval); | ||
| 395 | unsigned uid_t_sz = sizeof(uid_t); | ||
| 396 | unsigned gid_t_sz = sizeof(gid_t); | ||
| 397 | unsigned mbstate_t_sz = sizeof(mbstate_t); | ||
| 398 | unsigned sigset_t_sz = sizeof(sigset_t); | ||
| 399 | unsigned struct_timezone_sz = sizeof(struct timezone); | ||
| 400 | unsigned struct_tms_sz = sizeof(struct tms); | ||
| 401 | unsigned struct_sigevent_sz = sizeof(struct sigevent); | ||
| 402 | unsigned struct_sched_param_sz = sizeof(struct sched_param); | ||
| 403 | unsigned struct_sockaddr_sz = sizeof(struct sockaddr); | ||
| 404 | unsigned ucontext_t_sz = sizeof(ucontext_t); | ||
| 405 | unsigned struct_rlimit_sz = sizeof(struct rlimit); | ||
| 406 | unsigned struct_timespec_sz = sizeof(struct timespec); | ||
| 407 | unsigned struct_sembuf_sz = sizeof(struct sembuf); | ||
| 408 | unsigned struct_kevent_sz = sizeof(struct kevent); | ||
| 409 | unsigned struct_FTS_sz = sizeof(FTS); | ||
| 410 | unsigned struct_FTSENT_sz = sizeof(FTSENT); | ||
| 411 | unsigned struct_regex_sz = sizeof(regex_t); | ||
| 412 | unsigned struct_regmatch_sz = sizeof(regmatch_t); | ||
| 413 | unsigned struct_fstab_sz = sizeof(struct fstab); | ||
| 414 | unsigned struct_utimbuf_sz = sizeof(struct utimbuf); | ||
| 415 | unsigned struct_itimerspec_sz = sizeof(struct itimerspec); | ||
| 416 | unsigned struct_timex_sz = sizeof(struct timex); | ||
| 417 | unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); | ||
| 418 | unsigned struct_mq_attr_sz = sizeof(struct mq_attr); | ||
| 419 | unsigned struct_statvfs_sz = sizeof(struct statvfs); | ||
| 420 | unsigned struct_sigaltstack_sz = sizeof(stack_t); | ||
| 421 | |||
| 422 | const uptr sig_ign = (uptr)SIG_IGN; | ||
| 423 | const uptr sig_dfl = (uptr)SIG_DFL; | ||
| 424 | const uptr sig_err = (uptr)SIG_ERR; | ||
| 425 | const uptr sa_siginfo = (uptr)SA_SIGINFO; | ||
| 426 | |||
| 427 | const unsigned long __sanitizer_bufsiz = BUFSIZ; | ||
| 428 | |||
| 429 | int ptrace_pt_io = PT_IO; | ||
| 430 | int ptrace_pt_lwpinfo = PT_LWPINFO; | ||
| 431 | int ptrace_pt_set_event_mask = PT_SET_EVENT_MASK; | ||
| 432 | int ptrace_pt_get_event_mask = PT_GET_EVENT_MASK; | ||
| 433 | int ptrace_pt_get_process_state = PT_GET_PROCESS_STATE; | ||
| 434 | int ptrace_pt_set_siginfo = PT_SET_SIGINFO; | ||
| 435 | int ptrace_pt_get_siginfo = PT_GET_SIGINFO; | ||
| 436 | int ptrace_pt_lwpstatus = PT_LWPSTATUS; | ||
| 437 | int ptrace_pt_lwpnext = PT_LWPNEXT; | ||
| 438 | int ptrace_piod_read_d = PIOD_READ_D; | ||
| 439 | int ptrace_piod_write_d = PIOD_WRITE_D; | ||
| 440 | int ptrace_piod_read_i = PIOD_READ_I; | ||
| 441 | int ptrace_piod_write_i = PIOD_WRITE_I; | ||
| 442 | int ptrace_piod_read_auxv = PIOD_READ_AUXV; | ||
| 443 | |||
| 444 | #if defined(PT_SETREGS) && defined(PT_GETREGS) | ||
| 445 | int ptrace_pt_setregs = PT_SETREGS; | ||
| 446 | int ptrace_pt_getregs = PT_GETREGS; | ||
| 447 | #else | ||
| 448 | int ptrace_pt_setregs = -1; | ||
| 449 | int ptrace_pt_getregs = -1; | ||
| 450 | #endif | ||
| 451 | |||
| 452 | #if defined(PT_SETFPREGS) && defined(PT_GETFPREGS) | ||
| 453 | int ptrace_pt_setfpregs = PT_SETFPREGS; | ||
| 454 | int ptrace_pt_getfpregs = PT_GETFPREGS; | ||
| 455 | #else | ||
| 456 | int ptrace_pt_setfpregs = -1; | ||
| 457 | int ptrace_pt_getfpregs = -1; | ||
| 458 | #endif | ||
| 459 | |||
| 460 | #if defined(PT_SETDBREGS) && defined(PT_GETDBREGS) | ||
| 461 | int ptrace_pt_setdbregs = PT_SETDBREGS; | ||
| 462 | int ptrace_pt_getdbregs = PT_GETDBREGS; | ||
| 463 | #else | ||
| 464 | int ptrace_pt_setdbregs = -1; | ||
| 465 | int ptrace_pt_getdbregs = -1; | ||
| 466 | #endif | ||
| 467 | |||
| 468 | unsigned struct_ptrace_ptrace_io_desc_struct_sz = sizeof(struct ptrace_io_desc); | ||
| 469 | unsigned struct_ptrace_ptrace_lwpinfo_struct_sz = sizeof(struct ptrace_lwpinfo); | ||
| 470 | unsigned struct_ptrace_ptrace_lwpstatus_struct_sz = | ||
| 471 | sizeof(struct __sanitizer_ptrace_lwpstatus); | ||
| 472 | unsigned struct_ptrace_ptrace_event_struct_sz = sizeof(ptrace_event_t); | ||
| 473 | unsigned struct_ptrace_ptrace_siginfo_struct_sz = sizeof(ptrace_siginfo_t); | ||
| 474 | |||
| 475 | #if defined(PT_SETREGS) | ||
| 476 | unsigned struct_ptrace_reg_struct_sz = sizeof(struct reg); | ||
| 477 | #else | ||
| 478 | unsigned struct_ptrace_reg_struct_sz = -1; | ||
| 479 | #endif | ||
| 480 | |||
| 481 | #if defined(PT_SETFPREGS) | ||
| 482 | unsigned struct_ptrace_fpreg_struct_sz = sizeof(struct fpreg); | ||
| 483 | #else | ||
| 484 | unsigned struct_ptrace_fpreg_struct_sz = -1; | ||
| 485 | #endif | ||
| 486 | |||
| 487 | #if defined(PT_SETDBREGS) | ||
| 488 | unsigned struct_ptrace_dbreg_struct_sz = sizeof(struct dbreg); | ||
| 489 | #else | ||
| 490 | unsigned struct_ptrace_dbreg_struct_sz = -1; | ||
| 491 | #endif | ||
| 492 | |||
| 493 | int shmctl_ipc_stat = (int)IPC_STAT; | ||
| 494 | |||
| 495 | unsigned struct_utmp_sz = sizeof(struct utmp); | ||
| 496 | unsigned struct_utmpx_sz = sizeof(struct utmpx); | ||
| 497 | |||
| 498 | int map_fixed = MAP_FIXED; | ||
| 499 | |||
| 500 | int af_inet = (int)AF_INET; | ||
| 501 | int af_inet6 = (int)AF_INET6; | ||
| 502 | |||
| 503 | uptr __sanitizer_in_addr_sz(int af) { | ||
| 504 | if (af == AF_INET) | ||
| 505 | return sizeof(struct in_addr); | ||
| 506 | else if (af == AF_INET6) | ||
| 507 | return sizeof(struct in6_addr); | ||
| 508 | else | ||
| 509 | return 0; | ||
| 510 | } | ||
| 511 | |||
| 512 | unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); | ||
| 513 | |||
| 514 | int glob_nomatch = GLOB_NOMATCH; | ||
| 515 | int glob_altdirfunc = GLOB_ALTDIRFUNC; | ||
| 516 | |||
| 517 | unsigned path_max = PATH_MAX; | ||
| 518 | |||
| 519 | int struct_ttyent_sz = sizeof(struct ttyent); | ||
| 520 | |||
| 521 | struct __sanitizer_nvlist_ref_t { | ||
| 522 | void *buf; | ||
| 523 | uptr len; | ||
| 524 | int flags; | ||
| 525 | }; | ||
| 526 | |||
| 527 | typedef __sanitizer_nvlist_ref_t nvlist_ref_t; | ||
| 528 | |||
| 529 | // ioctl arguments | ||
| 530 | unsigned struct_altqreq_sz = sizeof(altqreq); | ||
| 531 | unsigned struct_amr_user_ioctl_sz = sizeof(amr_user_ioctl); | ||
| 532 | unsigned struct_ap_control_sz = sizeof(ap_control); | ||
| 533 | unsigned struct_apm_ctl_sz = sizeof(apm_ctl); | ||
| 534 | unsigned struct_apm_event_info_sz = sizeof(apm_event_info); | ||
| 535 | unsigned struct_apm_power_info_sz = sizeof(apm_power_info); | ||
| 536 | unsigned struct_atabusiodetach_args_sz = sizeof(atabusiodetach_args); | ||
| 537 | unsigned struct_atabusioscan_args_sz = sizeof(atabusioscan_args); | ||
| 538 | unsigned struct_ath_diag_sz = sizeof(ath_diag); | ||
| 539 | unsigned struct_atm_flowmap_sz = sizeof(atm_flowmap); | ||
| 540 | unsigned struct_audio_buf_info_sz = sizeof(audio_buf_info); | ||
| 541 | unsigned struct_audio_device_sz = sizeof(audio_device); | ||
| 542 | unsigned struct_audio_encoding_sz = sizeof(audio_encoding); | ||
| 543 | unsigned struct_audio_info_sz = sizeof(audio_info); | ||
| 544 | unsigned struct_audio_offset_sz = sizeof(audio_offset); | ||
| 545 | unsigned struct_bio_locate_sz = sizeof(bio_locate); | ||
| 546 | unsigned struct_bioc_alarm_sz = sizeof(bioc_alarm); | ||
| 547 | unsigned struct_bioc_blink_sz = sizeof(bioc_blink); | ||
| 548 | unsigned struct_bioc_disk_sz = sizeof(bioc_disk); | ||
| 549 | unsigned struct_bioc_inq_sz = sizeof(bioc_inq); | ||
| 550 | unsigned struct_bioc_setstate_sz = sizeof(bioc_setstate); | ||
| 551 | unsigned struct_bioc_vol_sz = sizeof(bioc_vol); | ||
| 552 | unsigned struct_bioc_volops_sz = sizeof(bioc_volops); | ||
| 553 | unsigned struct_bktr_chnlset_sz = sizeof(bktr_chnlset); | ||
| 554 | unsigned struct_bktr_remote_sz = sizeof(bktr_remote); | ||
| 555 | unsigned struct_blue_conf_sz = sizeof(blue_conf); | ||
| 556 | unsigned struct_blue_interface_sz = sizeof(blue_interface); | ||
| 557 | unsigned struct_blue_stats_sz = sizeof(blue_stats); | ||
| 558 | unsigned struct_bpf_dltlist_sz = sizeof(bpf_dltlist); | ||
| 559 | unsigned struct_bpf_program_sz = sizeof(bpf_program); | ||
| 560 | unsigned struct_bpf_stat_old_sz = sizeof(bpf_stat_old); | ||
| 561 | unsigned struct_bpf_stat_sz = sizeof(bpf_stat); | ||
| 562 | unsigned struct_bpf_version_sz = sizeof(bpf_version); | ||
| 563 | unsigned struct_btreq_sz = sizeof(btreq); | ||
| 564 | unsigned struct_btsco_info_sz = sizeof(btsco_info); | ||
| 565 | unsigned struct_buffmem_desc_sz = sizeof(buffmem_desc); | ||
| 566 | unsigned struct_cbq_add_class_sz = sizeof(cbq_add_class); | ||
| 567 | unsigned struct_cbq_add_filter_sz = sizeof(cbq_add_filter); | ||
| 568 | unsigned struct_cbq_delete_class_sz = sizeof(cbq_delete_class); | ||
| 569 | unsigned struct_cbq_delete_filter_sz = sizeof(cbq_delete_filter); | ||
| 570 | unsigned struct_cbq_getstats_sz = sizeof(cbq_getstats); | ||
| 571 | unsigned struct_cbq_interface_sz = sizeof(cbq_interface); | ||
| 572 | unsigned struct_cbq_modify_class_sz = sizeof(cbq_modify_class); | ||
| 573 | unsigned struct_ccd_ioctl_sz = sizeof(ccd_ioctl); | ||
| 574 | unsigned struct_cdnr_add_element_sz = sizeof(cdnr_add_element); | ||
| 575 | unsigned struct_cdnr_add_filter_sz = sizeof(cdnr_add_filter); | ||
| 576 | unsigned struct_cdnr_add_tbmeter_sz = sizeof(cdnr_add_tbmeter); | ||
| 577 | unsigned struct_cdnr_add_trtcm_sz = sizeof(cdnr_add_trtcm); | ||
| 578 | unsigned struct_cdnr_add_tswtcm_sz = sizeof(cdnr_add_tswtcm); | ||
| 579 | unsigned struct_cdnr_delete_element_sz = sizeof(cdnr_delete_element); | ||
| 580 | unsigned struct_cdnr_delete_filter_sz = sizeof(cdnr_delete_filter); | ||
| 581 | unsigned struct_cdnr_get_stats_sz = sizeof(cdnr_get_stats); | ||
| 582 | unsigned struct_cdnr_interface_sz = sizeof(cdnr_interface); | ||
| 583 | unsigned struct_cdnr_modify_tbmeter_sz = sizeof(cdnr_modify_tbmeter); | ||
| 584 | unsigned struct_cdnr_modify_trtcm_sz = sizeof(cdnr_modify_trtcm); | ||
| 585 | unsigned struct_cdnr_modify_tswtcm_sz = sizeof(cdnr_modify_tswtcm); | ||
| 586 | unsigned struct_cdnr_tbmeter_stats_sz = sizeof(cdnr_tbmeter_stats); | ||
| 587 | unsigned struct_cdnr_tcm_stats_sz = sizeof(cdnr_tcm_stats); | ||
| 588 | unsigned struct_cgd_ioctl_sz = sizeof(cgd_ioctl); | ||
| 589 | unsigned struct_cgd_user_sz = sizeof(cgd_user); | ||
| 590 | unsigned struct_changer_element_status_request_sz = | ||
| 591 | sizeof(changer_element_status_request); | ||
| 592 | unsigned struct_changer_exchange_request_sz = sizeof(changer_exchange_request); | ||
| 593 | unsigned struct_changer_move_request_sz = sizeof(changer_move_request); | ||
| 594 | unsigned struct_changer_params_sz = sizeof(changer_params); | ||
| 595 | unsigned struct_changer_position_request_sz = sizeof(changer_position_request); | ||
| 596 | unsigned struct_changer_set_voltag_request_sz = | ||
| 597 | sizeof(changer_set_voltag_request); | ||
| 598 | unsigned struct_clockctl_adjtime_sz = sizeof(clockctl_adjtime); | ||
| 599 | unsigned struct_clockctl_clock_settime_sz = sizeof(clockctl_clock_settime); | ||
| 600 | unsigned struct_clockctl_ntp_adjtime_sz = sizeof(clockctl_ntp_adjtime); | ||
| 601 | unsigned struct_clockctl_settimeofday_sz = sizeof(clockctl_settimeofday); | ||
| 602 | unsigned struct_cnwistats_sz = sizeof(cnwistats); | ||
| 603 | unsigned struct_cnwitrail_sz = sizeof(cnwitrail); | ||
| 604 | unsigned struct_cnwstatus_sz = sizeof(cnwstatus); | ||
| 605 | unsigned struct_count_info_sz = sizeof(count_info); | ||
| 606 | unsigned struct_cpu_ucode_sz = sizeof(cpu_ucode); | ||
| 607 | unsigned struct_cpu_ucode_version_sz = sizeof(cpu_ucode_version); | ||
| 608 | unsigned struct_crypt_kop_sz = sizeof(crypt_kop); | ||
| 609 | unsigned struct_crypt_mkop_sz = sizeof(crypt_mkop); | ||
| 610 | unsigned struct_crypt_mop_sz = sizeof(crypt_mop); | ||
| 611 | unsigned struct_crypt_op_sz = sizeof(crypt_op); | ||
| 612 | unsigned struct_crypt_result_sz = sizeof(crypt_result); | ||
| 613 | unsigned struct_crypt_sfop_sz = sizeof(crypt_sfop); | ||
| 614 | unsigned struct_crypt_sgop_sz = sizeof(crypt_sgop); | ||
| 615 | unsigned struct_cryptret_sz = sizeof(cryptret); | ||
| 616 | unsigned struct_devdetachargs_sz = sizeof(devdetachargs); | ||
| 617 | unsigned struct_devlistargs_sz = sizeof(devlistargs); | ||
| 618 | unsigned struct_devpmargs_sz = sizeof(devpmargs); | ||
| 619 | unsigned struct_devrescanargs_sz = sizeof(devrescanargs); | ||
| 620 | unsigned struct_disk_badsecinfo_sz = sizeof(disk_badsecinfo); | ||
| 621 | unsigned struct_disk_strategy_sz = sizeof(disk_strategy); | ||
| 622 | unsigned struct_disklabel_sz = sizeof(disklabel); | ||
| 623 | unsigned struct_dkbad_sz = sizeof(dkbad); | ||
| 624 | unsigned struct_dkwedge_info_sz = sizeof(dkwedge_info); | ||
| 625 | unsigned struct_dkwedge_list_sz = sizeof(dkwedge_list); | ||
| 626 | unsigned struct_dmio_setfunc_sz = sizeof(dmio_setfunc); | ||
| 627 | unsigned struct_dmx_pes_filter_params_sz = sizeof(dmx_pes_filter_params); | ||
| 628 | unsigned struct_dmx_sct_filter_params_sz = sizeof(dmx_sct_filter_params); | ||
| 629 | unsigned struct_dmx_stc_sz = sizeof(dmx_stc); | ||
| 630 | unsigned struct_dvb_diseqc_master_cmd_sz = sizeof(dvb_diseqc_master_cmd); | ||
| 631 | unsigned struct_dvb_diseqc_slave_reply_sz = sizeof(dvb_diseqc_slave_reply); | ||
| 632 | unsigned struct_dvb_frontend_event_sz = sizeof(dvb_frontend_event); | ||
| 633 | unsigned struct_dvb_frontend_info_sz = sizeof(dvb_frontend_info); | ||
| 634 | unsigned struct_dvb_frontend_parameters_sz = sizeof(dvb_frontend_parameters); | ||
| 635 | unsigned struct_eccapreq_sz = sizeof(eccapreq); | ||
| 636 | unsigned struct_fbcmap_sz = sizeof(fbcmap); | ||
| 637 | unsigned struct_fbcurpos_sz = sizeof(fbcurpos); | ||
| 638 | unsigned struct_fbcursor_sz = sizeof(fbcursor); | ||
| 639 | unsigned struct_fbgattr_sz = sizeof(fbgattr); | ||
| 640 | unsigned struct_fbsattr_sz = sizeof(fbsattr); | ||
| 641 | unsigned struct_fbtype_sz = sizeof(fbtype); | ||
| 642 | unsigned struct_fdformat_cmd_sz = sizeof(fdformat_cmd); | ||
| 643 | unsigned struct_fdformat_parms_sz = sizeof(fdformat_parms); | ||
| 644 | unsigned struct_fifoq_conf_sz = sizeof(fifoq_conf); | ||
| 645 | unsigned struct_fifoq_getstats_sz = sizeof(fifoq_getstats); | ||
| 646 | unsigned struct_fifoq_interface_sz = sizeof(fifoq_interface); | ||
| 647 | unsigned struct_format_op_sz = sizeof(format_op); | ||
| 648 | unsigned struct_fss_get_sz = sizeof(fss_get); | ||
| 649 | unsigned struct_fss_set_sz = sizeof(fss_set); | ||
| 650 | unsigned struct_gpio_attach_sz = sizeof(gpio_attach); | ||
| 651 | unsigned struct_gpio_info_sz = sizeof(gpio_info); | ||
| 652 | unsigned struct_gpio_req_sz = sizeof(gpio_req); | ||
| 653 | unsigned struct_gpio_set_sz = sizeof(gpio_set); | ||
| 654 | unsigned struct_hfsc_add_class_sz = sizeof(hfsc_add_class); | ||
| 655 | unsigned struct_hfsc_add_filter_sz = sizeof(hfsc_add_filter); | ||
| 656 | unsigned struct_hfsc_attach_sz = sizeof(hfsc_attach); | ||
| 657 | unsigned struct_hfsc_class_stats_sz = sizeof(hfsc_class_stats); | ||
| 658 | unsigned struct_hfsc_delete_class_sz = sizeof(hfsc_delete_class); | ||
| 659 | unsigned struct_hfsc_delete_filter_sz = sizeof(hfsc_delete_filter); | ||
| 660 | unsigned struct_hfsc_interface_sz = sizeof(hfsc_interface); | ||
| 661 | unsigned struct_hfsc_modify_class_sz = sizeof(hfsc_modify_class); | ||
| 662 | unsigned struct_hpcfb_dsp_op_sz = sizeof(hpcfb_dsp_op); | ||
| 663 | unsigned struct_hpcfb_dspconf_sz = sizeof(hpcfb_dspconf); | ||
| 664 | unsigned struct_hpcfb_fbconf_sz = sizeof(hpcfb_fbconf); | ||
| 665 | unsigned struct_if_addrprefreq_sz = sizeof(if_addrprefreq); | ||
| 666 | unsigned struct_if_clonereq_sz = sizeof(if_clonereq); | ||
| 667 | unsigned struct_if_laddrreq_sz = sizeof(if_laddrreq); | ||
| 668 | unsigned struct_ifaddr_sz = sizeof(ifaddr); | ||
| 669 | unsigned struct_ifaliasreq_sz = sizeof(ifaliasreq); | ||
| 670 | unsigned struct_ifcapreq_sz = sizeof(ifcapreq); | ||
| 671 | unsigned struct_ifconf_sz = sizeof(ifconf); | ||
| 672 | unsigned struct_ifdatareq_sz = sizeof(ifdatareq); | ||
| 673 | unsigned struct_ifdrv_sz = sizeof(ifdrv); | ||
| 674 | unsigned struct_ifmediareq_sz = sizeof(ifmediareq); | ||
| 675 | unsigned struct_ifpppcstatsreq_sz = sizeof(ifpppcstatsreq); | ||
| 676 | unsigned struct_ifpppstatsreq_sz = sizeof(ifpppstatsreq); | ||
| 677 | unsigned struct_ifreq_sz = sizeof(ifreq); | ||
| 678 | unsigned struct_in6_addrpolicy_sz = sizeof(in6_addrpolicy); | ||
| 679 | unsigned struct_in6_ndireq_sz = sizeof(in6_ndireq); | ||
| 680 | unsigned struct_ioc_load_unload_sz = sizeof(ioc_load_unload); | ||
| 681 | unsigned struct_ioc_patch_sz = sizeof(ioc_patch); | ||
| 682 | unsigned struct_ioc_play_blocks_sz = sizeof(ioc_play_blocks); | ||
| 683 | unsigned struct_ioc_play_msf_sz = sizeof(ioc_play_msf); | ||
| 684 | unsigned struct_ioc_play_track_sz = sizeof(ioc_play_track); | ||
| 685 | unsigned struct_ioc_read_subchannel_sz = sizeof(ioc_read_subchannel); | ||
| 686 | unsigned struct_ioc_read_toc_entry_sz = sizeof(ioc_read_toc_entry); | ||
| 687 | unsigned struct_ioc_toc_header_sz = sizeof(ioc_toc_header); | ||
| 688 | unsigned struct_ioc_vol_sz = sizeof(ioc_vol); | ||
| 689 | unsigned struct_ioctl_pt_sz = sizeof(ioctl_pt); | ||
| 690 | unsigned struct_ioppt_sz = sizeof(ioppt); | ||
| 691 | unsigned struct_iovec_sz = sizeof(iovec); | ||
| 692 | unsigned struct_ipfobj_sz = sizeof(ipfobj); | ||
| 693 | unsigned struct_irda_params_sz = sizeof(irda_params); | ||
| 694 | unsigned struct_isp_fc_device_sz = sizeof(isp_fc_device); | ||
| 695 | unsigned struct_isp_fc_tsk_mgmt_sz = sizeof(isp_fc_tsk_mgmt); | ||
| 696 | unsigned struct_isp_hba_device_sz = sizeof(isp_hba_device); | ||
| 697 | unsigned struct_isv_cmd_sz = sizeof(isv_cmd); | ||
| 698 | unsigned struct_jobs_add_class_sz = sizeof(jobs_add_class); | ||
| 699 | unsigned struct_jobs_add_filter_sz = sizeof(jobs_add_filter); | ||
| 700 | unsigned struct_jobs_attach_sz = sizeof(jobs_attach); | ||
| 701 | unsigned struct_jobs_class_stats_sz = sizeof(jobs_class_stats); | ||
| 702 | unsigned struct_jobs_delete_class_sz = sizeof(jobs_delete_class); | ||
| 703 | unsigned struct_jobs_delete_filter_sz = sizeof(jobs_delete_filter); | ||
| 704 | unsigned struct_jobs_interface_sz = sizeof(jobs_interface); | ||
| 705 | unsigned struct_jobs_modify_class_sz = sizeof(jobs_modify_class); | ||
| 706 | unsigned struct_kbentry_sz = sizeof(kbentry); | ||
| 707 | unsigned struct_kfilter_mapping_sz = sizeof(kfilter_mapping); | ||
| 708 | unsigned struct_kiockeymap_sz = sizeof(kiockeymap); | ||
| 709 | unsigned struct_ksyms_gsymbol_sz = sizeof(ksyms_gsymbol); | ||
| 710 | unsigned struct_ksyms_gvalue_sz = sizeof(ksyms_gvalue); | ||
| 711 | unsigned struct_ksyms_ogsymbol_sz = sizeof(ksyms_ogsymbol); | ||
| 712 | unsigned struct_kttcp_io_args_sz = sizeof(kttcp_io_args); | ||
| 713 | unsigned struct_ltchars_sz = sizeof(ltchars); | ||
| 714 | unsigned struct_lua_create_sz = sizeof(struct lua_create); | ||
| 715 | unsigned struct_lua_info_sz = sizeof(struct lua_info); | ||
| 716 | unsigned struct_lua_load_sz = sizeof(struct lua_load); | ||
| 717 | unsigned struct_lua_require_sz = sizeof(lua_require); | ||
| 718 | unsigned struct_mbpp_param_sz = sizeof(mbpp_param); | ||
| 719 | unsigned struct_md_conf_sz = sizeof(md_conf); | ||
| 720 | unsigned struct_meteor_capframe_sz = sizeof(meteor_capframe); | ||
| 721 | unsigned struct_meteor_counts_sz = sizeof(meteor_counts); | ||
| 722 | unsigned struct_meteor_geomet_sz = sizeof(meteor_geomet); | ||
| 723 | unsigned struct_meteor_pixfmt_sz = sizeof(meteor_pixfmt); | ||
| 724 | unsigned struct_meteor_video_sz = sizeof(meteor_video); | ||
| 725 | unsigned struct_mlx_cinfo_sz = sizeof(mlx_cinfo); | ||
| 726 | unsigned struct_mlx_pause_sz = sizeof(mlx_pause); | ||
| 727 | unsigned struct_mlx_rebuild_request_sz = sizeof(mlx_rebuild_request); | ||
| 728 | unsigned struct_mlx_rebuild_status_sz = sizeof(mlx_rebuild_status); | ||
| 729 | unsigned struct_mlx_usercommand_sz = sizeof(mlx_usercommand); | ||
| 730 | unsigned struct_mly_user_command_sz = sizeof(mly_user_command); | ||
| 731 | unsigned struct_mly_user_health_sz = sizeof(mly_user_health); | ||
| 732 | unsigned struct_mtget_sz = sizeof(mtget); | ||
| 733 | unsigned struct_mtop_sz = sizeof(mtop); | ||
| 734 | unsigned struct_npf_ioctl_table_sz = sizeof(npf_ioctl_table); | ||
| 735 | unsigned struct_npioctl_sz = sizeof(npioctl); | ||
| 736 | unsigned struct_nvme_pt_command_sz = sizeof(nvme_pt_command); | ||
| 737 | unsigned struct_ochanger_element_status_request_sz = | ||
| 738 | sizeof(ochanger_element_status_request); | ||
| 739 | unsigned struct_ofiocdesc_sz = sizeof(ofiocdesc); | ||
| 740 | unsigned struct_okiockey_sz = sizeof(okiockey); | ||
| 741 | unsigned struct_ortentry_sz = sizeof(ortentry); | ||
| 742 | unsigned struct_oscsi_addr_sz = sizeof(oscsi_addr); | ||
| 743 | unsigned struct_oss_audioinfo_sz = sizeof(oss_audioinfo); | ||
| 744 | unsigned struct_oss_sysinfo_sz = sizeof(oss_sysinfo); | ||
| 745 | unsigned struct_pciio_bdf_cfgreg_sz = sizeof(pciio_bdf_cfgreg); | ||
| 746 | unsigned struct_pciio_businfo_sz = sizeof(pciio_businfo); | ||
| 747 | unsigned struct_pciio_cfgreg_sz = sizeof(pciio_cfgreg); | ||
| 748 | unsigned struct_pciio_drvname_sz = sizeof(pciio_drvname); | ||
| 749 | unsigned struct_pciio_drvnameonbus_sz = sizeof(pciio_drvnameonbus); | ||
| 750 | unsigned struct_pcvtid_sz = sizeof(pcvtid); | ||
| 751 | unsigned struct_pf_osfp_ioctl_sz = sizeof(pf_osfp_ioctl); | ||
| 752 | unsigned struct_pf_status_sz = sizeof(pf_status); | ||
| 753 | unsigned struct_pfioc_altq_sz = sizeof(pfioc_altq); | ||
| 754 | unsigned struct_pfioc_if_sz = sizeof(pfioc_if); | ||
| 755 | unsigned struct_pfioc_iface_sz = sizeof(pfioc_iface); | ||
| 756 | unsigned struct_pfioc_limit_sz = sizeof(pfioc_limit); | ||
| 757 | unsigned struct_pfioc_natlook_sz = sizeof(pfioc_natlook); | ||
| 758 | unsigned struct_pfioc_pooladdr_sz = sizeof(pfioc_pooladdr); | ||
| 759 | unsigned struct_pfioc_qstats_sz = sizeof(pfioc_qstats); | ||
| 760 | unsigned struct_pfioc_rule_sz = sizeof(pfioc_rule); | ||
| 761 | unsigned struct_pfioc_ruleset_sz = sizeof(pfioc_ruleset); | ||
| 762 | unsigned struct_pfioc_src_node_kill_sz = sizeof(pfioc_src_node_kill); | ||
| 763 | unsigned struct_pfioc_src_nodes_sz = sizeof(pfioc_src_nodes); | ||
| 764 | unsigned struct_pfioc_state_kill_sz = sizeof(pfioc_state_kill); | ||
| 765 | unsigned struct_pfioc_state_sz = sizeof(pfioc_state); | ||
| 766 | unsigned struct_pfioc_states_sz = sizeof(pfioc_states); | ||
| 767 | unsigned struct_pfioc_table_sz = sizeof(pfioc_table); | ||
| 768 | unsigned struct_pfioc_tm_sz = sizeof(pfioc_tm); | ||
| 769 | unsigned struct_pfioc_trans_sz = sizeof(pfioc_trans); | ||
| 770 | unsigned struct_plistref_sz = sizeof(plistref); | ||
| 771 | unsigned struct_power_type_sz = sizeof(power_type); | ||
| 772 | unsigned struct_ppp_idle_sz = sizeof(ppp_idle); | ||
| 773 | unsigned struct_ppp_option_data_sz = sizeof(ppp_option_data); | ||
| 774 | unsigned struct_ppp_rawin_sz = sizeof(ppp_rawin); | ||
| 775 | unsigned struct_pppoeconnectionstate_sz = sizeof(pppoeconnectionstate); | ||
| 776 | unsigned struct_pppoediscparms_sz = sizeof(pppoediscparms); | ||
| 777 | unsigned struct_priq_add_class_sz = sizeof(priq_add_class); | ||
| 778 | unsigned struct_priq_add_filter_sz = sizeof(priq_add_filter); | ||
| 779 | unsigned struct_priq_class_stats_sz = sizeof(priq_class_stats); | ||
| 780 | unsigned struct_priq_delete_class_sz = sizeof(priq_delete_class); | ||
| 781 | unsigned struct_priq_delete_filter_sz = sizeof(priq_delete_filter); | ||
| 782 | unsigned struct_priq_interface_sz = sizeof(priq_interface); | ||
| 783 | unsigned struct_priq_modify_class_sz = sizeof(priq_modify_class); | ||
| 784 | unsigned struct_ptmget_sz = sizeof(ptmget); | ||
| 785 | unsigned struct_radio_info_sz = sizeof(radio_info); | ||
| 786 | unsigned struct_red_conf_sz = sizeof(red_conf); | ||
| 787 | unsigned struct_red_interface_sz = sizeof(red_interface); | ||
| 788 | unsigned struct_red_stats_sz = sizeof(red_stats); | ||
| 789 | unsigned struct_redparams_sz = sizeof(redparams); | ||
| 790 | unsigned struct_rf_pmparams_sz = sizeof(rf_pmparams); | ||
| 791 | unsigned struct_rf_pmstat_sz = sizeof(rf_pmstat); | ||
| 792 | unsigned struct_rf_recon_req_sz = sizeof(rf_recon_req); | ||
| 793 | unsigned struct_rio_conf_sz = sizeof(rio_conf); | ||
| 794 | unsigned struct_rio_interface_sz = sizeof(rio_interface); | ||
| 795 | unsigned struct_rio_stats_sz = sizeof(rio_stats); | ||
| 796 | unsigned struct_scan_io_sz = sizeof(scan_io); | ||
| 797 | unsigned struct_scbusaccel_args_sz = sizeof(scbusaccel_args); | ||
| 798 | unsigned struct_scbusiodetach_args_sz = sizeof(scbusiodetach_args); | ||
| 799 | unsigned struct_scbusioscan_args_sz = sizeof(scbusioscan_args); | ||
| 800 | unsigned struct_scsi_addr_sz = sizeof(scsi_addr); | ||
| 801 | unsigned struct_seq_event_rec_sz = sizeof(seq_event_rec); | ||
| 802 | unsigned struct_session_op_sz = sizeof(session_op); | ||
| 803 | unsigned struct_sgttyb_sz = sizeof(sgttyb); | ||
| 804 | unsigned struct_sioc_sg_req_sz = sizeof(sioc_sg_req); | ||
| 805 | unsigned struct_sioc_vif_req_sz = sizeof(sioc_vif_req); | ||
| 806 | unsigned struct_smbioc_flags_sz = sizeof(smbioc_flags); | ||
| 807 | unsigned struct_smbioc_lookup_sz = sizeof(smbioc_lookup); | ||
| 808 | unsigned struct_smbioc_oshare_sz = sizeof(smbioc_oshare); | ||
| 809 | unsigned struct_smbioc_ossn_sz = sizeof(smbioc_ossn); | ||
| 810 | unsigned struct_smbioc_rq_sz = sizeof(smbioc_rq); | ||
| 811 | unsigned struct_smbioc_rw_sz = sizeof(smbioc_rw); | ||
| 812 | unsigned struct_spppauthcfg_sz = sizeof(spppauthcfg); | ||
| 813 | unsigned struct_spppauthfailuresettings_sz = sizeof(spppauthfailuresettings); | ||
| 814 | unsigned struct_spppauthfailurestats_sz = sizeof(spppauthfailurestats); | ||
| 815 | unsigned struct_spppdnsaddrs_sz = sizeof(spppdnsaddrs); | ||
| 816 | unsigned struct_spppdnssettings_sz = sizeof(spppdnssettings); | ||
| 817 | unsigned struct_spppidletimeout_sz = sizeof(spppidletimeout); | ||
| 818 | unsigned struct_spppkeepalivesettings_sz = sizeof(spppkeepalivesettings); | ||
| 819 | unsigned struct_sppplcpcfg_sz = sizeof(sppplcpcfg); | ||
| 820 | unsigned struct_spppstatus_sz = sizeof(spppstatus); | ||
| 821 | unsigned struct_spppstatusncp_sz = sizeof(spppstatusncp); | ||
| 822 | unsigned struct_srt_rt_sz = sizeof(srt_rt); | ||
| 823 | unsigned struct_stic_xinfo_sz = sizeof(stic_xinfo); | ||
| 824 | unsigned struct_sun_dkctlr_sz = sizeof(sun_dkctlr); | ||
| 825 | unsigned struct_sun_dkgeom_sz = sizeof(sun_dkgeom); | ||
| 826 | unsigned struct_sun_dkpart_sz = sizeof(sun_dkpart); | ||
| 827 | unsigned struct_synth_info_sz = sizeof(synth_info); | ||
| 828 | unsigned struct_tbrreq_sz = sizeof(tbrreq); | ||
| 829 | unsigned struct_tchars_sz = sizeof(tchars); | ||
| 830 | unsigned struct_termios_sz = sizeof(termios); | ||
| 831 | unsigned struct_timeval_sz = sizeof(timeval); | ||
| 832 | unsigned struct_twe_drivecommand_sz = sizeof(twe_drivecommand); | ||
| 833 | unsigned struct_twe_paramcommand_sz = sizeof(twe_paramcommand); | ||
| 834 | unsigned struct_twe_usercommand_sz = sizeof(twe_usercommand); | ||
| 835 | unsigned struct_ukyopon_identify_sz = sizeof(ukyopon_identify); | ||
| 836 | unsigned struct_urio_command_sz = sizeof(urio_command); | ||
| 837 | unsigned struct_usb_alt_interface_sz = sizeof(usb_alt_interface); | ||
| 838 | unsigned struct_usb_bulk_ra_wb_opt_sz = sizeof(usb_bulk_ra_wb_opt); | ||
| 839 | unsigned struct_usb_config_desc_sz = sizeof(usb_config_desc); | ||
| 840 | unsigned struct_usb_ctl_report_desc_sz = sizeof(usb_ctl_report_desc); | ||
| 841 | unsigned struct_usb_ctl_report_sz = sizeof(usb_ctl_report); | ||
| 842 | unsigned struct_usb_ctl_request_sz = sizeof(usb_ctl_request); | ||
| 843 | #if defined(__x86_64__) | ||
| 844 | unsigned struct_nvmm_ioc_capability_sz = sizeof(nvmm_ioc_capability); | ||
| 845 | unsigned struct_nvmm_ioc_machine_create_sz = sizeof(nvmm_ioc_machine_create); | ||
| 846 | unsigned struct_nvmm_ioc_machine_destroy_sz = sizeof(nvmm_ioc_machine_destroy); | ||
| 847 | unsigned struct_nvmm_ioc_machine_configure_sz = | ||
| 848 | sizeof(nvmm_ioc_machine_configure); | ||
| 849 | unsigned struct_nvmm_ioc_vcpu_create_sz = sizeof(nvmm_ioc_vcpu_create); | ||
| 850 | unsigned struct_nvmm_ioc_vcpu_destroy_sz = sizeof(nvmm_ioc_vcpu_destroy); | ||
| 851 | unsigned struct_nvmm_ioc_vcpu_configure_sz = sizeof(nvmm_ioc_vcpu_configure); | ||
| 852 | unsigned struct_nvmm_ioc_vcpu_setstate_sz = sizeof(nvmm_ioc_vcpu_destroy); | ||
| 853 | unsigned struct_nvmm_ioc_vcpu_getstate_sz = sizeof(nvmm_ioc_vcpu_getstate); | ||
| 854 | unsigned struct_nvmm_ioc_vcpu_inject_sz = sizeof(nvmm_ioc_vcpu_inject); | ||
| 855 | unsigned struct_nvmm_ioc_vcpu_run_sz = sizeof(nvmm_ioc_vcpu_run); | ||
| 856 | unsigned struct_nvmm_ioc_gpa_map_sz = sizeof(nvmm_ioc_gpa_map); | ||
| 857 | unsigned struct_nvmm_ioc_gpa_unmap_sz = sizeof(nvmm_ioc_gpa_unmap); | ||
| 858 | unsigned struct_nvmm_ioc_hva_map_sz = sizeof(nvmm_ioc_hva_map); | ||
| 859 | unsigned struct_nvmm_ioc_hva_unmap_sz = sizeof(nvmm_ioc_hva_unmap); | ||
| 860 | unsigned struct_nvmm_ioc_ctl_sz = sizeof(nvmm_ioc_ctl); | ||
| 861 | #endif | ||
| 862 | unsigned struct_spi_ioctl_configure_sz = sizeof(spi_ioctl_configure); | ||
| 863 | unsigned struct_spi_ioctl_transfer_sz = sizeof(spi_ioctl_transfer); | ||
| 864 | unsigned struct_autofs_daemon_request_sz = sizeof(autofs_daemon_request); | ||
| 865 | unsigned struct_autofs_daemon_done_sz = sizeof(autofs_daemon_done); | ||
| 866 | unsigned struct_sctp_connectx_addrs_sz = sizeof(sctp_connectx_addrs); | ||
| 867 | unsigned struct_usb_device_info_old_sz = sizeof(usb_device_info_old); | ||
| 868 | unsigned struct_usb_device_info_sz = sizeof(usb_device_info); | ||
| 869 | unsigned struct_usb_device_stats_sz = sizeof(usb_device_stats); | ||
| 870 | unsigned struct_usb_endpoint_desc_sz = sizeof(usb_endpoint_desc); | ||
| 871 | unsigned struct_usb_full_desc_sz = sizeof(usb_full_desc); | ||
| 872 | unsigned struct_usb_interface_desc_sz = sizeof(usb_interface_desc); | ||
| 873 | unsigned struct_usb_string_desc_sz = sizeof(usb_string_desc); | ||
| 874 | unsigned struct_utoppy_readfile_sz = sizeof(utoppy_readfile); | ||
| 875 | unsigned struct_utoppy_rename_sz = sizeof(utoppy_rename); | ||
| 876 | unsigned struct_utoppy_stats_sz = sizeof(utoppy_stats); | ||
| 877 | unsigned struct_utoppy_writefile_sz = sizeof(utoppy_writefile); | ||
| 878 | unsigned struct_v4l2_audio_sz = sizeof(v4l2_audio); | ||
| 879 | unsigned struct_v4l2_audioout_sz = sizeof(v4l2_audioout); | ||
| 880 | unsigned struct_v4l2_buffer_sz = sizeof(v4l2_buffer); | ||
| 881 | unsigned struct_v4l2_capability_sz = sizeof(v4l2_capability); | ||
| 882 | unsigned struct_v4l2_control_sz = sizeof(v4l2_control); | ||
| 883 | unsigned struct_v4l2_crop_sz = sizeof(v4l2_crop); | ||
| 884 | unsigned struct_v4l2_cropcap_sz = sizeof(v4l2_cropcap); | ||
| 885 | unsigned struct_v4l2_fmtdesc_sz = sizeof(v4l2_fmtdesc); | ||
| 886 | unsigned struct_v4l2_format_sz = sizeof(v4l2_format); | ||
| 887 | unsigned struct_v4l2_framebuffer_sz = sizeof(v4l2_framebuffer); | ||
| 888 | unsigned struct_v4l2_frequency_sz = sizeof(v4l2_frequency); | ||
| 889 | unsigned struct_v4l2_frmivalenum_sz = sizeof(v4l2_frmivalenum); | ||
| 890 | unsigned struct_v4l2_frmsizeenum_sz = sizeof(v4l2_frmsizeenum); | ||
| 891 | unsigned struct_v4l2_input_sz = sizeof(v4l2_input); | ||
| 892 | unsigned struct_v4l2_jpegcompression_sz = sizeof(v4l2_jpegcompression); | ||
| 893 | unsigned struct_v4l2_modulator_sz = sizeof(v4l2_modulator); | ||
| 894 | unsigned struct_v4l2_output_sz = sizeof(v4l2_output); | ||
| 895 | unsigned struct_v4l2_queryctrl_sz = sizeof(v4l2_queryctrl); | ||
| 896 | unsigned struct_v4l2_querymenu_sz = sizeof(v4l2_querymenu); | ||
| 897 | unsigned struct_v4l2_requestbuffers_sz = sizeof(v4l2_requestbuffers); | ||
| 898 | unsigned struct_v4l2_standard_sz = sizeof(v4l2_standard); | ||
| 899 | unsigned struct_v4l2_streamparm_sz = sizeof(v4l2_streamparm); | ||
| 900 | unsigned struct_v4l2_tuner_sz = sizeof(v4l2_tuner); | ||
| 901 | unsigned struct_vnd_ioctl_sz = sizeof(vnd_ioctl); | ||
| 902 | unsigned struct_vnd_user_sz = sizeof(vnd_user); | ||
| 903 | unsigned struct_vt_stat_sz = sizeof(vt_stat); | ||
| 904 | unsigned struct_wdog_conf_sz = sizeof(wdog_conf); | ||
| 905 | unsigned struct_wdog_mode_sz = sizeof(wdog_mode); | ||
| 906 | unsigned struct_ipmi_recv_sz = sizeof(ipmi_recv); | ||
| 907 | unsigned struct_ipmi_req_sz = sizeof(ipmi_req); | ||
| 908 | unsigned struct_ipmi_cmdspec_sz = sizeof(ipmi_cmdspec); | ||
| 909 | unsigned struct_wfq_conf_sz = sizeof(wfq_conf); | ||
| 910 | unsigned struct_wfq_getqid_sz = sizeof(wfq_getqid); | ||
| 911 | unsigned struct_wfq_getstats_sz = sizeof(wfq_getstats); | ||
| 912 | unsigned struct_wfq_interface_sz = sizeof(wfq_interface); | ||
| 913 | unsigned struct_wfq_setweight_sz = sizeof(wfq_setweight); | ||
| 914 | unsigned struct_winsize_sz = sizeof(winsize); | ||
| 915 | unsigned struct_wscons_event_sz = sizeof(wscons_event); | ||
| 916 | unsigned struct_wsdisplay_addscreendata_sz = sizeof(wsdisplay_addscreendata); | ||
| 917 | unsigned struct_wsdisplay_char_sz = sizeof(wsdisplay_char); | ||
| 918 | unsigned struct_wsdisplay_cmap_sz = sizeof(wsdisplay_cmap); | ||
| 919 | unsigned struct_wsdisplay_curpos_sz = sizeof(wsdisplay_curpos); | ||
| 920 | unsigned struct_wsdisplay_cursor_sz = sizeof(wsdisplay_cursor); | ||
| 921 | unsigned struct_wsdisplay_delscreendata_sz = sizeof(wsdisplay_delscreendata); | ||
| 922 | unsigned struct_wsdisplay_fbinfo_sz = sizeof(wsdisplay_fbinfo); | ||
| 923 | unsigned struct_wsdisplay_font_sz = sizeof(wsdisplay_font); | ||
| 924 | unsigned struct_wsdisplay_kbddata_sz = sizeof(wsdisplay_kbddata); | ||
| 925 | unsigned struct_wsdisplay_msgattrs_sz = sizeof(wsdisplay_msgattrs); | ||
| 926 | unsigned struct_wsdisplay_param_sz = sizeof(wsdisplay_param); | ||
| 927 | unsigned struct_wsdisplay_scroll_data_sz = sizeof(wsdisplay_scroll_data); | ||
| 928 | unsigned struct_wsdisplay_usefontdata_sz = sizeof(wsdisplay_usefontdata); | ||
| 929 | unsigned struct_wsdisplayio_blit_sz = sizeof(wsdisplayio_blit); | ||
| 930 | unsigned struct_wsdisplayio_bus_id_sz = sizeof(wsdisplayio_bus_id); | ||
| 931 | unsigned struct_wsdisplayio_edid_info_sz = sizeof(wsdisplayio_edid_info); | ||
| 932 | unsigned struct_wsdisplayio_fbinfo_sz = sizeof(wsdisplayio_fbinfo); | ||
| 933 | unsigned struct_wskbd_bell_data_sz = sizeof(wskbd_bell_data); | ||
| 934 | unsigned struct_wskbd_keyrepeat_data_sz = sizeof(wskbd_keyrepeat_data); | ||
| 935 | unsigned struct_wskbd_map_data_sz = sizeof(wskbd_map_data); | ||
| 936 | unsigned struct_wskbd_scroll_data_sz = sizeof(wskbd_scroll_data); | ||
| 937 | unsigned struct_wsmouse_calibcoords_sz = sizeof(wsmouse_calibcoords); | ||
| 938 | unsigned struct_wsmouse_id_sz = sizeof(wsmouse_id); | ||
| 939 | unsigned struct_wsmouse_repeat_sz = sizeof(wsmouse_repeat); | ||
| 940 | unsigned struct_wsmux_device_list_sz = sizeof(wsmux_device_list); | ||
| 941 | unsigned struct_wsmux_device_sz = sizeof(wsmux_device); | ||
| 942 | unsigned struct_xd_iocmd_sz = sizeof(xd_iocmd); | ||
| 943 | |||
| 944 | unsigned struct_scsireq_sz = sizeof(struct scsireq); | ||
| 945 | unsigned struct_tone_sz = sizeof(tone_t); | ||
| 946 | unsigned union_twe_statrequest_sz = sizeof(union twe_statrequest); | ||
| 947 | unsigned struct_usb_device_descriptor_sz = sizeof(usb_device_descriptor_t); | ||
| 948 | unsigned struct_vt_mode_sz = sizeof(struct vt_mode); | ||
| 949 | unsigned struct__old_mixer_info_sz = sizeof(struct _old_mixer_info); | ||
| 950 | unsigned struct__agp_allocate_sz = sizeof(struct _agp_allocate); | ||
| 951 | unsigned struct__agp_bind_sz = sizeof(struct _agp_bind); | ||
| 952 | unsigned struct__agp_info_sz = sizeof(struct _agp_info); | ||
| 953 | unsigned struct__agp_setup_sz = sizeof(struct _agp_setup); | ||
| 954 | unsigned struct__agp_unbind_sz = sizeof(struct _agp_unbind); | ||
| 955 | unsigned struct_atareq_sz = sizeof(struct atareq); | ||
| 956 | unsigned struct_cpustate_sz = sizeof(struct cpustate); | ||
| 957 | unsigned struct_dmx_caps_sz = sizeof(struct dmx_caps); | ||
| 958 | unsigned enum_dmx_source_sz = sizeof(dmx_source_t); | ||
| 959 | unsigned union_dvd_authinfo_sz = sizeof(dvd_authinfo); | ||
| 960 | unsigned union_dvd_struct_sz = sizeof(dvd_struct); | ||
| 961 | unsigned enum_v4l2_priority_sz = sizeof(enum v4l2_priority); | ||
| 962 | unsigned struct_envsys_basic_info_sz = sizeof(struct envsys_basic_info); | ||
| 963 | unsigned struct_envsys_tre_data_sz = sizeof(struct envsys_tre_data); | ||
| 964 | unsigned enum_fe_sec_mini_cmd_sz = sizeof(enum fe_sec_mini_cmd); | ||
| 965 | unsigned enum_fe_sec_tone_mode_sz = sizeof(enum fe_sec_tone_mode); | ||
| 966 | unsigned enum_fe_sec_voltage_sz = sizeof(enum fe_sec_voltage); | ||
| 967 | unsigned enum_fe_status_sz = sizeof(enum fe_status); | ||
| 968 | unsigned struct_gdt_ctrt_sz = sizeof(struct gdt_ctrt); | ||
| 969 | unsigned struct_gdt_event_sz = sizeof(struct gdt_event); | ||
| 970 | unsigned struct_gdt_osv_sz = sizeof(struct gdt_osv); | ||
| 971 | unsigned struct_gdt_rescan_sz = sizeof(struct gdt_rescan); | ||
| 972 | unsigned struct_gdt_statist_sz = sizeof(struct gdt_statist); | ||
| 973 | unsigned struct_gdt_ucmd_sz = sizeof(struct gdt_ucmd); | ||
| 974 | unsigned struct_iscsi_conn_status_parameters_sz = | ||
| 975 | sizeof(iscsi_conn_status_parameters_t); | ||
| 976 | unsigned struct_iscsi_get_version_parameters_sz = | ||
| 977 | sizeof(iscsi_get_version_parameters_t); | ||
| 978 | unsigned struct_iscsi_iocommand_parameters_sz = | ||
| 979 | sizeof(iscsi_iocommand_parameters_t); | ||
| 980 | unsigned struct_iscsi_login_parameters_sz = sizeof(iscsi_login_parameters_t); | ||
| 981 | unsigned struct_iscsi_logout_parameters_sz = sizeof(iscsi_logout_parameters_t); | ||
| 982 | unsigned struct_iscsi_register_event_parameters_sz = | ||
| 983 | sizeof(iscsi_register_event_parameters_t); | ||
| 984 | unsigned struct_iscsi_remove_parameters_sz = sizeof(iscsi_remove_parameters_t); | ||
| 985 | unsigned struct_iscsi_send_targets_parameters_sz = | ||
| 986 | sizeof(iscsi_send_targets_parameters_t); | ||
| 987 | unsigned struct_iscsi_set_node_name_parameters_sz = | ||
| 988 | sizeof(iscsi_set_node_name_parameters_t); | ||
| 989 | unsigned struct_iscsi_wait_event_parameters_sz = | ||
| 990 | sizeof(iscsi_wait_event_parameters_t); | ||
| 991 | unsigned struct_isp_stats_sz = sizeof(isp_stats_t); | ||
| 992 | unsigned struct_lsenable_sz = sizeof(struct lsenable); | ||
| 993 | unsigned struct_lsdisable_sz = sizeof(struct lsdisable); | ||
| 994 | unsigned struct_audio_format_query_sz = sizeof(audio_format_query); | ||
| 995 | unsigned struct_mixer_ctrl_sz = sizeof(struct mixer_ctrl); | ||
| 996 | unsigned struct_mixer_devinfo_sz = sizeof(struct mixer_devinfo); | ||
| 997 | unsigned struct_mpu_command_rec_sz = sizeof(mpu_command_rec); | ||
| 998 | unsigned struct_rndstat_sz = sizeof(rndstat_t); | ||
| 999 | unsigned struct_rndstat_name_sz = sizeof(rndstat_name_t); | ||
| 1000 | unsigned struct_rndctl_sz = sizeof(rndctl_t); | ||
| 1001 | unsigned struct_rnddata_sz = sizeof(rnddata_t); | ||
| 1002 | unsigned struct_rndpoolstat_sz = sizeof(rndpoolstat_t); | ||
| 1003 | unsigned struct_rndstat_est_sz = sizeof(rndstat_est_t); | ||
| 1004 | unsigned struct_rndstat_est_name_sz = sizeof(rndstat_est_name_t); | ||
| 1005 | unsigned struct_pps_params_sz = sizeof(pps_params_t); | ||
| 1006 | unsigned struct_pps_info_sz = sizeof(pps_info_t); | ||
| 1007 | unsigned struct_mixer_info_sz = sizeof(struct mixer_info); | ||
| 1008 | unsigned struct_RF_SparetWait_sz = sizeof(RF_SparetWait_t); | ||
| 1009 | unsigned struct_RF_ComponentLabel_sz = sizeof(RF_ComponentLabel_t); | ||
| 1010 | unsigned struct_RF_SingleComponent_sz = sizeof(RF_SingleComponent_t); | ||
| 1011 | unsigned struct_RF_ProgressInfo_sz = sizeof(RF_ProgressInfo_t); | ||
| 1012 | unsigned struct_nvlist_ref_sz = sizeof(struct __sanitizer_nvlist_ref_t); | ||
| 1013 | unsigned struct_StringList_sz = sizeof(StringList); | ||
| 1014 | |||
| 1015 | const unsigned IOCTL_NOT_PRESENT = 0; | ||
| 1016 | |||
| 1017 | unsigned IOCTL_AFM_ADDFMAP = AFM_ADDFMAP; | ||
| 1018 | unsigned IOCTL_AFM_DELFMAP = AFM_DELFMAP; | ||
| 1019 | unsigned IOCTL_AFM_CLEANFMAP = AFM_CLEANFMAP; | ||
| 1020 | unsigned IOCTL_AFM_GETFMAP = AFM_GETFMAP; | ||
| 1021 | unsigned IOCTL_ALTQGTYPE = ALTQGTYPE; | ||
| 1022 | unsigned IOCTL_ALTQTBRSET = ALTQTBRSET; | ||
| 1023 | unsigned IOCTL_ALTQTBRGET = ALTQTBRGET; | ||
| 1024 | unsigned IOCTL_BLUE_IF_ATTACH = BLUE_IF_ATTACH; | ||
| 1025 | unsigned IOCTL_BLUE_IF_DETACH = BLUE_IF_DETACH; | ||
| 1026 | unsigned IOCTL_BLUE_ENABLE = BLUE_ENABLE; | ||
| 1027 | unsigned IOCTL_BLUE_DISABLE = BLUE_DISABLE; | ||
| 1028 | unsigned IOCTL_BLUE_CONFIG = BLUE_CONFIG; | ||
| 1029 | unsigned IOCTL_BLUE_GETSTATS = BLUE_GETSTATS; | ||
| 1030 | unsigned IOCTL_CBQ_IF_ATTACH = CBQ_IF_ATTACH; | ||
| 1031 | unsigned IOCTL_CBQ_IF_DETACH = CBQ_IF_DETACH; | ||
| 1032 | unsigned IOCTL_CBQ_ENABLE = CBQ_ENABLE; | ||
| 1033 | unsigned IOCTL_CBQ_DISABLE = CBQ_DISABLE; | ||
| 1034 | unsigned IOCTL_CBQ_CLEAR_HIERARCHY = CBQ_CLEAR_HIERARCHY; | ||
| 1035 | unsigned IOCTL_CBQ_ADD_CLASS = CBQ_ADD_CLASS; | ||
| 1036 | unsigned IOCTL_CBQ_DEL_CLASS = CBQ_DEL_CLASS; | ||
| 1037 | unsigned IOCTL_CBQ_MODIFY_CLASS = CBQ_MODIFY_CLASS; | ||
| 1038 | unsigned IOCTL_CBQ_ADD_FILTER = CBQ_ADD_FILTER; | ||
| 1039 | unsigned IOCTL_CBQ_DEL_FILTER = CBQ_DEL_FILTER; | ||
| 1040 | unsigned IOCTL_CBQ_GETSTATS = CBQ_GETSTATS; | ||
| 1041 | unsigned IOCTL_CDNR_IF_ATTACH = CDNR_IF_ATTACH; | ||
| 1042 | unsigned IOCTL_CDNR_IF_DETACH = CDNR_IF_DETACH; | ||
| 1043 | unsigned IOCTL_CDNR_ENABLE = CDNR_ENABLE; | ||
| 1044 | unsigned IOCTL_CDNR_DISABLE = CDNR_DISABLE; | ||
| 1045 | unsigned IOCTL_CDNR_ADD_FILTER = CDNR_ADD_FILTER; | ||
| 1046 | unsigned IOCTL_CDNR_DEL_FILTER = CDNR_DEL_FILTER; | ||
| 1047 | unsigned IOCTL_CDNR_GETSTATS = CDNR_GETSTATS; | ||
| 1048 | unsigned IOCTL_CDNR_ADD_ELEM = CDNR_ADD_ELEM; | ||
| 1049 | unsigned IOCTL_CDNR_DEL_ELEM = CDNR_DEL_ELEM; | ||
| 1050 | unsigned IOCTL_CDNR_ADD_TBM = CDNR_ADD_TBM; | ||
| 1051 | unsigned IOCTL_CDNR_MOD_TBM = CDNR_MOD_TBM; | ||
| 1052 | unsigned IOCTL_CDNR_TBM_STATS = CDNR_TBM_STATS; | ||
| 1053 | unsigned IOCTL_CDNR_ADD_TCM = CDNR_ADD_TCM; | ||
| 1054 | unsigned IOCTL_CDNR_MOD_TCM = CDNR_MOD_TCM; | ||
| 1055 | unsigned IOCTL_CDNR_TCM_STATS = CDNR_TCM_STATS; | ||
| 1056 | unsigned IOCTL_CDNR_ADD_TSW = CDNR_ADD_TSW; | ||
| 1057 | unsigned IOCTL_CDNR_MOD_TSW = CDNR_MOD_TSW; | ||
| 1058 | unsigned IOCTL_FIFOQ_IF_ATTACH = FIFOQ_IF_ATTACH; | ||
| 1059 | unsigned IOCTL_FIFOQ_IF_DETACH = FIFOQ_IF_DETACH; | ||
| 1060 | unsigned IOCTL_FIFOQ_ENABLE = FIFOQ_ENABLE; | ||
| 1061 | unsigned IOCTL_FIFOQ_DISABLE = FIFOQ_DISABLE; | ||
| 1062 | unsigned IOCTL_FIFOQ_CONFIG = FIFOQ_CONFIG; | ||
| 1063 | unsigned IOCTL_FIFOQ_GETSTATS = FIFOQ_GETSTATS; | ||
| 1064 | unsigned IOCTL_HFSC_IF_ATTACH = HFSC_IF_ATTACH; | ||
| 1065 | unsigned IOCTL_HFSC_IF_DETACH = HFSC_IF_DETACH; | ||
| 1066 | unsigned IOCTL_HFSC_ENABLE = HFSC_ENABLE; | ||
| 1067 | unsigned IOCTL_HFSC_DISABLE = HFSC_DISABLE; | ||
| 1068 | unsigned IOCTL_HFSC_CLEAR_HIERARCHY = HFSC_CLEAR_HIERARCHY; | ||
| 1069 | unsigned IOCTL_HFSC_ADD_CLASS = HFSC_ADD_CLASS; | ||
| 1070 | unsigned IOCTL_HFSC_DEL_CLASS = HFSC_DEL_CLASS; | ||
| 1071 | unsigned IOCTL_HFSC_MOD_CLASS = HFSC_MOD_CLASS; | ||
| 1072 | unsigned IOCTL_HFSC_ADD_FILTER = HFSC_ADD_FILTER; | ||
| 1073 | unsigned IOCTL_HFSC_DEL_FILTER = HFSC_DEL_FILTER; | ||
| 1074 | unsigned IOCTL_HFSC_GETSTATS = HFSC_GETSTATS; | ||
| 1075 | unsigned IOCTL_JOBS_IF_ATTACH = JOBS_IF_ATTACH; | ||
| 1076 | unsigned IOCTL_JOBS_IF_DETACH = JOBS_IF_DETACH; | ||
| 1077 | unsigned IOCTL_JOBS_ENABLE = JOBS_ENABLE; | ||
| 1078 | unsigned IOCTL_JOBS_DISABLE = JOBS_DISABLE; | ||
| 1079 | unsigned IOCTL_JOBS_CLEAR = JOBS_CLEAR; | ||
| 1080 | unsigned IOCTL_JOBS_ADD_CLASS = JOBS_ADD_CLASS; | ||
| 1081 | unsigned IOCTL_JOBS_DEL_CLASS = JOBS_DEL_CLASS; | ||
| 1082 | unsigned IOCTL_JOBS_MOD_CLASS = JOBS_MOD_CLASS; | ||
| 1083 | unsigned IOCTL_JOBS_ADD_FILTER = JOBS_ADD_FILTER; | ||
| 1084 | unsigned IOCTL_JOBS_DEL_FILTER = JOBS_DEL_FILTER; | ||
| 1085 | unsigned IOCTL_JOBS_GETSTATS = JOBS_GETSTATS; | ||
| 1086 | unsigned IOCTL_PRIQ_IF_ATTACH = PRIQ_IF_ATTACH; | ||
| 1087 | unsigned IOCTL_PRIQ_IF_DETACH = PRIQ_IF_DETACH; | ||
| 1088 | unsigned IOCTL_PRIQ_ENABLE = PRIQ_ENABLE; | ||
| 1089 | unsigned IOCTL_PRIQ_DISABLE = PRIQ_DISABLE; | ||
| 1090 | unsigned IOCTL_PRIQ_CLEAR = PRIQ_CLEAR; | ||
| 1091 | unsigned IOCTL_PRIQ_ADD_CLASS = PRIQ_ADD_CLASS; | ||
| 1092 | unsigned IOCTL_PRIQ_DEL_CLASS = PRIQ_DEL_CLASS; | ||
| 1093 | unsigned IOCTL_PRIQ_MOD_CLASS = PRIQ_MOD_CLASS; | ||
| 1094 | unsigned IOCTL_PRIQ_ADD_FILTER = PRIQ_ADD_FILTER; | ||
| 1095 | unsigned IOCTL_PRIQ_DEL_FILTER = PRIQ_DEL_FILTER; | ||
| 1096 | unsigned IOCTL_PRIQ_GETSTATS = PRIQ_GETSTATS; | ||
| 1097 | unsigned IOCTL_RED_IF_ATTACH = RED_IF_ATTACH; | ||
| 1098 | unsigned IOCTL_RED_IF_DETACH = RED_IF_DETACH; | ||
| 1099 | unsigned IOCTL_RED_ENABLE = RED_ENABLE; | ||
| 1100 | unsigned IOCTL_RED_DISABLE = RED_DISABLE; | ||
| 1101 | unsigned IOCTL_RED_CONFIG = RED_CONFIG; | ||
| 1102 | unsigned IOCTL_RED_GETSTATS = RED_GETSTATS; | ||
| 1103 | unsigned IOCTL_RED_SETDEFAULTS = RED_SETDEFAULTS; | ||
| 1104 | unsigned IOCTL_RIO_IF_ATTACH = RIO_IF_ATTACH; | ||
| 1105 | unsigned IOCTL_RIO_IF_DETACH = RIO_IF_DETACH; | ||
| 1106 | unsigned IOCTL_RIO_ENABLE = RIO_ENABLE; | ||
| 1107 | unsigned IOCTL_RIO_DISABLE = RIO_DISABLE; | ||
| 1108 | unsigned IOCTL_RIO_CONFIG = RIO_CONFIG; | ||
| 1109 | unsigned IOCTL_RIO_GETSTATS = RIO_GETSTATS; | ||
| 1110 | unsigned IOCTL_RIO_SETDEFAULTS = RIO_SETDEFAULTS; | ||
| 1111 | unsigned IOCTL_WFQ_IF_ATTACH = WFQ_IF_ATTACH; | ||
| 1112 | unsigned IOCTL_WFQ_IF_DETACH = WFQ_IF_DETACH; | ||
| 1113 | unsigned IOCTL_WFQ_ENABLE = WFQ_ENABLE; | ||
| 1114 | unsigned IOCTL_WFQ_DISABLE = WFQ_DISABLE; | ||
| 1115 | unsigned IOCTL_WFQ_CONFIG = WFQ_CONFIG; | ||
| 1116 | unsigned IOCTL_WFQ_GET_STATS = WFQ_GET_STATS; | ||
| 1117 | unsigned IOCTL_WFQ_GET_QID = WFQ_GET_QID; | ||
| 1118 | unsigned IOCTL_WFQ_SET_WEIGHT = WFQ_SET_WEIGHT; | ||
| 1119 | unsigned IOCTL_CRIOGET = CRIOGET; | ||
| 1120 | unsigned IOCTL_CIOCFSESSION = CIOCFSESSION; | ||
| 1121 | unsigned IOCTL_CIOCKEY = CIOCKEY; | ||
| 1122 | unsigned IOCTL_CIOCNFKEYM = CIOCNFKEYM; | ||
| 1123 | unsigned IOCTL_CIOCNFSESSION = CIOCNFSESSION; | ||
| 1124 | unsigned IOCTL_CIOCNCRYPTRETM = CIOCNCRYPTRETM; | ||
| 1125 | unsigned IOCTL_CIOCNCRYPTRET = CIOCNCRYPTRET; | ||
| 1126 | unsigned IOCTL_CIOCGSESSION = CIOCGSESSION; | ||
| 1127 | unsigned IOCTL_CIOCNGSESSION = CIOCNGSESSION; | ||
| 1128 | unsigned IOCTL_CIOCCRYPT = CIOCCRYPT; | ||
| 1129 | unsigned IOCTL_CIOCNCRYPTM = CIOCNCRYPTM; | ||
| 1130 | unsigned IOCTL_CIOCASYMFEAT = CIOCASYMFEAT; | ||
| 1131 | unsigned IOCTL_APM_IOC_REJECT = APM_IOC_REJECT; | ||
| 1132 | unsigned IOCTL_APM_IOC_STANDBY = APM_IOC_STANDBY; | ||
| 1133 | unsigned IOCTL_APM_IOC_SUSPEND = APM_IOC_SUSPEND; | ||
| 1134 | unsigned IOCTL_OAPM_IOC_GETPOWER = OAPM_IOC_GETPOWER; | ||
| 1135 | unsigned IOCTL_APM_IOC_GETPOWER = APM_IOC_GETPOWER; | ||
| 1136 | unsigned IOCTL_APM_IOC_NEXTEVENT = APM_IOC_NEXTEVENT; | ||
| 1137 | unsigned IOCTL_APM_IOC_DEV_CTL = APM_IOC_DEV_CTL; | ||
| 1138 | unsigned IOCTL_NETBSD_DM_IOCTL = NETBSD_DM_IOCTL; | ||
| 1139 | unsigned IOCTL_DMIO_SETFUNC = DMIO_SETFUNC; | ||
| 1140 | unsigned IOCTL_DMX_START = DMX_START; | ||
| 1141 | unsigned IOCTL_DMX_STOP = DMX_STOP; | ||
| 1142 | unsigned IOCTL_DMX_SET_FILTER = DMX_SET_FILTER; | ||
| 1143 | unsigned IOCTL_DMX_SET_PES_FILTER = DMX_SET_PES_FILTER; | ||
| 1144 | unsigned IOCTL_DMX_SET_BUFFER_SIZE = DMX_SET_BUFFER_SIZE; | ||
| 1145 | unsigned IOCTL_DMX_GET_STC = DMX_GET_STC; | ||
| 1146 | unsigned IOCTL_DMX_ADD_PID = DMX_ADD_PID; | ||
| 1147 | unsigned IOCTL_DMX_REMOVE_PID = DMX_REMOVE_PID; | ||
| 1148 | unsigned IOCTL_DMX_GET_CAPS = DMX_GET_CAPS; | ||
| 1149 | unsigned IOCTL_DMX_SET_SOURCE = DMX_SET_SOURCE; | ||
| 1150 | unsigned IOCTL_FE_READ_STATUS = FE_READ_STATUS; | ||
| 1151 | unsigned IOCTL_FE_READ_BER = FE_READ_BER; | ||
| 1152 | unsigned IOCTL_FE_READ_SNR = FE_READ_SNR; | ||
| 1153 | unsigned IOCTL_FE_READ_SIGNAL_STRENGTH = FE_READ_SIGNAL_STRENGTH; | ||
| 1154 | unsigned IOCTL_FE_READ_UNCORRECTED_BLOCKS = FE_READ_UNCORRECTED_BLOCKS; | ||
| 1155 | unsigned IOCTL_FE_SET_FRONTEND = FE_SET_FRONTEND; | ||
| 1156 | unsigned IOCTL_FE_GET_FRONTEND = FE_GET_FRONTEND; | ||
| 1157 | unsigned IOCTL_FE_GET_EVENT = FE_GET_EVENT; | ||
| 1158 | unsigned IOCTL_FE_GET_INFO = FE_GET_INFO; | ||
| 1159 | unsigned IOCTL_FE_DISEQC_RESET_OVERLOAD = FE_DISEQC_RESET_OVERLOAD; | ||
| 1160 | unsigned IOCTL_FE_DISEQC_SEND_MASTER_CMD = FE_DISEQC_SEND_MASTER_CMD; | ||
| 1161 | unsigned IOCTL_FE_DISEQC_RECV_SLAVE_REPLY = FE_DISEQC_RECV_SLAVE_REPLY; | ||
| 1162 | unsigned IOCTL_FE_DISEQC_SEND_BURST = FE_DISEQC_SEND_BURST; | ||
| 1163 | unsigned IOCTL_FE_SET_TONE = FE_SET_TONE; | ||
| 1164 | unsigned IOCTL_FE_SET_VOLTAGE = FE_SET_VOLTAGE; | ||
| 1165 | unsigned IOCTL_FE_ENABLE_HIGH_LNB_VOLTAGE = FE_ENABLE_HIGH_LNB_VOLTAGE; | ||
| 1166 | unsigned IOCTL_FE_SET_FRONTEND_TUNE_MODE = FE_SET_FRONTEND_TUNE_MODE; | ||
| 1167 | unsigned IOCTL_FE_DISHNETWORK_SEND_LEGACY_CMD = FE_DISHNETWORK_SEND_LEGACY_CMD; | ||
| 1168 | unsigned IOCTL_FILEMON_SET_FD = FILEMON_SET_FD; | ||
| 1169 | unsigned IOCTL_FILEMON_SET_PID = FILEMON_SET_PID; | ||
| 1170 | unsigned IOCTL_HDAUDIO_FGRP_INFO = HDAUDIO_FGRP_INFO; | ||
| 1171 | unsigned IOCTL_HDAUDIO_FGRP_GETCONFIG = HDAUDIO_FGRP_GETCONFIG; | ||
| 1172 | unsigned IOCTL_HDAUDIO_FGRP_SETCONFIG = HDAUDIO_FGRP_SETCONFIG; | ||
| 1173 | unsigned IOCTL_HDAUDIO_FGRP_WIDGET_INFO = HDAUDIO_FGRP_WIDGET_INFO; | ||
| 1174 | unsigned IOCTL_HDAUDIO_FGRP_CODEC_INFO = HDAUDIO_FGRP_CODEC_INFO; | ||
| 1175 | unsigned IOCTL_HDAUDIO_AFG_WIDGET_INFO = HDAUDIO_AFG_WIDGET_INFO; | ||
| 1176 | unsigned IOCTL_HDAUDIO_AFG_CODEC_INFO = HDAUDIO_AFG_CODEC_INFO; | ||
| 1177 | unsigned IOCTL_CEC_GET_PHYS_ADDR = CEC_GET_PHYS_ADDR; | ||
| 1178 | unsigned IOCTL_CEC_GET_LOG_ADDRS = CEC_GET_LOG_ADDRS; | ||
| 1179 | unsigned IOCTL_CEC_SET_LOG_ADDRS = CEC_SET_LOG_ADDRS; | ||
| 1180 | unsigned IOCTL_CEC_GET_VENDOR_ID = CEC_GET_VENDOR_ID; | ||
| 1181 | unsigned IOCTL_HPCFBIO_GCONF = HPCFBIO_GCONF; | ||
| 1182 | unsigned IOCTL_HPCFBIO_SCONF = HPCFBIO_SCONF; | ||
| 1183 | unsigned IOCTL_HPCFBIO_GDSPCONF = HPCFBIO_GDSPCONF; | ||
| 1184 | unsigned IOCTL_HPCFBIO_SDSPCONF = HPCFBIO_SDSPCONF; | ||
| 1185 | unsigned IOCTL_HPCFBIO_GOP = HPCFBIO_GOP; | ||
| 1186 | unsigned IOCTL_HPCFBIO_SOP = HPCFBIO_SOP; | ||
| 1187 | unsigned IOCTL_IOPIOCPT = IOPIOCPT; | ||
| 1188 | unsigned IOCTL_IOPIOCGLCT = IOPIOCGLCT; | ||
| 1189 | unsigned IOCTL_IOPIOCGSTATUS = IOPIOCGSTATUS; | ||
| 1190 | unsigned IOCTL_IOPIOCRECONFIG = IOPIOCRECONFIG; | ||
| 1191 | unsigned IOCTL_IOPIOCGTIDMAP = IOPIOCGTIDMAP; | ||
| 1192 | unsigned IOCTL_SIOCGATHSTATS = SIOCGATHSTATS; | ||
| 1193 | unsigned IOCTL_SIOCGATHDIAG = SIOCGATHDIAG; | ||
| 1194 | unsigned IOCTL_METEORCAPTUR = METEORCAPTUR; | ||
| 1195 | unsigned IOCTL_METEORCAPFRM = METEORCAPFRM; | ||
| 1196 | unsigned IOCTL_METEORSETGEO = METEORSETGEO; | ||
| 1197 | unsigned IOCTL_METEORGETGEO = METEORGETGEO; | ||
| 1198 | unsigned IOCTL_METEORSTATUS = METEORSTATUS; | ||
| 1199 | unsigned IOCTL_METEORSHUE = METEORSHUE; | ||
| 1200 | unsigned IOCTL_METEORGHUE = METEORGHUE; | ||
| 1201 | unsigned IOCTL_METEORSFMT = METEORSFMT; | ||
| 1202 | unsigned IOCTL_METEORGFMT = METEORGFMT; | ||
| 1203 | unsigned IOCTL_METEORSINPUT = METEORSINPUT; | ||
| 1204 | unsigned IOCTL_METEORGINPUT = METEORGINPUT; | ||
| 1205 | unsigned IOCTL_METEORSCHCV = METEORSCHCV; | ||
| 1206 | unsigned IOCTL_METEORGCHCV = METEORGCHCV; | ||
| 1207 | unsigned IOCTL_METEORSCOUNT = METEORSCOUNT; | ||
| 1208 | unsigned IOCTL_METEORGCOUNT = METEORGCOUNT; | ||
| 1209 | unsigned IOCTL_METEORSFPS = METEORSFPS; | ||
| 1210 | unsigned IOCTL_METEORGFPS = METEORGFPS; | ||
| 1211 | unsigned IOCTL_METEORSSIGNAL = METEORSSIGNAL; | ||
| 1212 | unsigned IOCTL_METEORGSIGNAL = METEORGSIGNAL; | ||
| 1213 | unsigned IOCTL_METEORSVIDEO = METEORSVIDEO; | ||
| 1214 | unsigned IOCTL_METEORGVIDEO = METEORGVIDEO; | ||
| 1215 | unsigned IOCTL_METEORSBRIG = METEORSBRIG; | ||
| 1216 | unsigned IOCTL_METEORGBRIG = METEORGBRIG; | ||
| 1217 | unsigned IOCTL_METEORSCSAT = METEORSCSAT; | ||
| 1218 | unsigned IOCTL_METEORGCSAT = METEORGCSAT; | ||
| 1219 | unsigned IOCTL_METEORSCONT = METEORSCONT; | ||
| 1220 | unsigned IOCTL_METEORGCONT = METEORGCONT; | ||
| 1221 | unsigned IOCTL_METEORSHWS = METEORSHWS; | ||
| 1222 | unsigned IOCTL_METEORGHWS = METEORGHWS; | ||
| 1223 | unsigned IOCTL_METEORSVWS = METEORSVWS; | ||
| 1224 | unsigned IOCTL_METEORGVWS = METEORGVWS; | ||
| 1225 | unsigned IOCTL_METEORSTS = METEORSTS; | ||
| 1226 | unsigned IOCTL_METEORGTS = METEORGTS; | ||
| 1227 | unsigned IOCTL_TVTUNER_SETCHNL = TVTUNER_SETCHNL; | ||
| 1228 | unsigned IOCTL_TVTUNER_GETCHNL = TVTUNER_GETCHNL; | ||
| 1229 | unsigned IOCTL_TVTUNER_SETTYPE = TVTUNER_SETTYPE; | ||
| 1230 | unsigned IOCTL_TVTUNER_GETTYPE = TVTUNER_GETTYPE; | ||
| 1231 | unsigned IOCTL_TVTUNER_GETSTATUS = TVTUNER_GETSTATUS; | ||
| 1232 | unsigned IOCTL_TVTUNER_SETFREQ = TVTUNER_SETFREQ; | ||
| 1233 | unsigned IOCTL_TVTUNER_GETFREQ = TVTUNER_GETFREQ; | ||
| 1234 | unsigned IOCTL_TVTUNER_SETAFC = TVTUNER_SETAFC; | ||
| 1235 | unsigned IOCTL_TVTUNER_GETAFC = TVTUNER_GETAFC; | ||
| 1236 | unsigned IOCTL_RADIO_SETMODE = RADIO_SETMODE; | ||
| 1237 | unsigned IOCTL_RADIO_GETMODE = RADIO_GETMODE; | ||
| 1238 | unsigned IOCTL_RADIO_SETFREQ = RADIO_SETFREQ; | ||
| 1239 | unsigned IOCTL_RADIO_GETFREQ = RADIO_GETFREQ; | ||
| 1240 | unsigned IOCTL_METEORSACTPIXFMT = METEORSACTPIXFMT; | ||
| 1241 | unsigned IOCTL_METEORGACTPIXFMT = METEORGACTPIXFMT; | ||
| 1242 | unsigned IOCTL_METEORGSUPPIXFMT = METEORGSUPPIXFMT; | ||
| 1243 | unsigned IOCTL_TVTUNER_GETCHNLSET = TVTUNER_GETCHNLSET; | ||
| 1244 | unsigned IOCTL_REMOTE_GETKEY = REMOTE_GETKEY; | ||
| 1245 | unsigned IOCTL_GDT_IOCTL_GENERAL = GDT_IOCTL_GENERAL; | ||
| 1246 | unsigned IOCTL_GDT_IOCTL_DRVERS = GDT_IOCTL_DRVERS; | ||
| 1247 | unsigned IOCTL_GDT_IOCTL_CTRTYPE = GDT_IOCTL_CTRTYPE; | ||
| 1248 | unsigned IOCTL_GDT_IOCTL_OSVERS = GDT_IOCTL_OSVERS; | ||
| 1249 | unsigned IOCTL_GDT_IOCTL_CTRCNT = GDT_IOCTL_CTRCNT; | ||
| 1250 | unsigned IOCTL_GDT_IOCTL_EVENT = GDT_IOCTL_EVENT; | ||
| 1251 | unsigned IOCTL_GDT_IOCTL_STATIST = GDT_IOCTL_STATIST; | ||
| 1252 | unsigned IOCTL_GDT_IOCTL_RESCAN = GDT_IOCTL_RESCAN; | ||
| 1253 | unsigned IOCTL_ISP_SDBLEV = ISP_SDBLEV; | ||
| 1254 | unsigned IOCTL_ISP_RESETHBA = ISP_RESETHBA; | ||
| 1255 | unsigned IOCTL_ISP_RESCAN = ISP_RESCAN; | ||
| 1256 | unsigned IOCTL_ISP_SETROLE = ISP_SETROLE; | ||
| 1257 | unsigned IOCTL_ISP_GETROLE = ISP_GETROLE; | ||
| 1258 | unsigned IOCTL_ISP_GET_STATS = ISP_GET_STATS; | ||
| 1259 | unsigned IOCTL_ISP_CLR_STATS = ISP_CLR_STATS; | ||
| 1260 | unsigned IOCTL_ISP_FC_LIP = ISP_FC_LIP; | ||
| 1261 | unsigned IOCTL_ISP_FC_GETDINFO = ISP_FC_GETDINFO; | ||
| 1262 | unsigned IOCTL_ISP_GET_FW_CRASH_DUMP = ISP_GET_FW_CRASH_DUMP; | ||
| 1263 | unsigned IOCTL_ISP_FORCE_CRASH_DUMP = ISP_FORCE_CRASH_DUMP; | ||
| 1264 | unsigned IOCTL_ISP_FC_GETHINFO = ISP_FC_GETHINFO; | ||
| 1265 | unsigned IOCTL_ISP_TSK_MGMT = ISP_TSK_MGMT; | ||
| 1266 | unsigned IOCTL_ISP_FC_GETDLIST = ISP_FC_GETDLIST; | ||
| 1267 | unsigned IOCTL_MLXD_STATUS = MLXD_STATUS; | ||
| 1268 | unsigned IOCTL_MLXD_CHECKASYNC = MLXD_CHECKASYNC; | ||
| 1269 | unsigned IOCTL_MLXD_DETACH = MLXD_DETACH; | ||
| 1270 | unsigned IOCTL_MLX_RESCAN_DRIVES = MLX_RESCAN_DRIVES; | ||
| 1271 | unsigned IOCTL_MLX_PAUSE_CHANNEL = MLX_PAUSE_CHANNEL; | ||
| 1272 | unsigned IOCTL_MLX_COMMAND = MLX_COMMAND; | ||
| 1273 | unsigned IOCTL_MLX_REBUILDASYNC = MLX_REBUILDASYNC; | ||
| 1274 | unsigned IOCTL_MLX_REBUILDSTAT = MLX_REBUILDSTAT; | ||
| 1275 | unsigned IOCTL_MLX_GET_SYSDRIVE = MLX_GET_SYSDRIVE; | ||
| 1276 | unsigned IOCTL_MLX_GET_CINFO = MLX_GET_CINFO; | ||
| 1277 | unsigned IOCTL_NVME_PASSTHROUGH_CMD = NVME_PASSTHROUGH_CMD; | ||
| 1278 | unsigned IOCTL_FWCFGIO_SET_INDEX = FWCFGIO_SET_INDEX; | ||
| 1279 | unsigned IOCTL_IRDA_RESET_PARAMS = IRDA_RESET_PARAMS; | ||
| 1280 | unsigned IOCTL_IRDA_SET_PARAMS = IRDA_SET_PARAMS; | ||
| 1281 | unsigned IOCTL_IRDA_GET_SPEEDMASK = IRDA_GET_SPEEDMASK; | ||
| 1282 | unsigned IOCTL_IRDA_GET_TURNAROUNDMASK = IRDA_GET_TURNAROUNDMASK; | ||
| 1283 | unsigned IOCTL_IRFRAMETTY_GET_DEVICE = IRFRAMETTY_GET_DEVICE; | ||
| 1284 | unsigned IOCTL_IRFRAMETTY_GET_DONGLE = IRFRAMETTY_GET_DONGLE; | ||
| 1285 | unsigned IOCTL_IRFRAMETTY_SET_DONGLE = IRFRAMETTY_SET_DONGLE; | ||
| 1286 | unsigned IOCTL_ISV_CMD = ISV_CMD; | ||
| 1287 | unsigned IOCTL_WTQICMD = WTQICMD; | ||
| 1288 | unsigned IOCTL_ISCSI_GET_VERSION = ISCSI_GET_VERSION; | ||
| 1289 | unsigned IOCTL_ISCSI_LOGIN = ISCSI_LOGIN; | ||
| 1290 | unsigned IOCTL_ISCSI_LOGOUT = ISCSI_LOGOUT; | ||
| 1291 | unsigned IOCTL_ISCSI_ADD_CONNECTION = ISCSI_ADD_CONNECTION; | ||
| 1292 | unsigned IOCTL_ISCSI_RESTORE_CONNECTION = ISCSI_RESTORE_CONNECTION; | ||
| 1293 | unsigned IOCTL_ISCSI_REMOVE_CONNECTION = ISCSI_REMOVE_CONNECTION; | ||
| 1294 | unsigned IOCTL_ISCSI_CONNECTION_STATUS = ISCSI_CONNECTION_STATUS; | ||
| 1295 | unsigned IOCTL_ISCSI_SEND_TARGETS = ISCSI_SEND_TARGETS; | ||
| 1296 | unsigned IOCTL_ISCSI_SET_NODE_NAME = ISCSI_SET_NODE_NAME; | ||
| 1297 | unsigned IOCTL_ISCSI_IO_COMMAND = ISCSI_IO_COMMAND; | ||
| 1298 | unsigned IOCTL_ISCSI_REGISTER_EVENT = ISCSI_REGISTER_EVENT; | ||
| 1299 | unsigned IOCTL_ISCSI_DEREGISTER_EVENT = ISCSI_DEREGISTER_EVENT; | ||
| 1300 | unsigned IOCTL_ISCSI_WAIT_EVENT = ISCSI_WAIT_EVENT; | ||
| 1301 | unsigned IOCTL_ISCSI_POLL_EVENT = ISCSI_POLL_EVENT; | ||
| 1302 | unsigned IOCTL_OFIOCGET = OFIOCGET; | ||
| 1303 | unsigned IOCTL_OFIOCSET = OFIOCSET; | ||
| 1304 | unsigned IOCTL_OFIOCNEXTPROP = OFIOCNEXTPROP; | ||
| 1305 | unsigned IOCTL_OFIOCGETOPTNODE = OFIOCGETOPTNODE; | ||
| 1306 | unsigned IOCTL_OFIOCGETNEXT = OFIOCGETNEXT; | ||
| 1307 | unsigned IOCTL_OFIOCGETCHILD = OFIOCGETCHILD; | ||
| 1308 | unsigned IOCTL_OFIOCFINDDEVICE = OFIOCFINDDEVICE; | ||
| 1309 | unsigned IOCTL_AMR_IO_VERSION = AMR_IO_VERSION; | ||
| 1310 | unsigned IOCTL_AMR_IO_COMMAND = AMR_IO_COMMAND; | ||
| 1311 | unsigned IOCTL_MLYIO_COMMAND = MLYIO_COMMAND; | ||
| 1312 | unsigned IOCTL_MLYIO_HEALTH = MLYIO_HEALTH; | ||
| 1313 | unsigned IOCTL_PCI_IOC_CFGREAD = PCI_IOC_CFGREAD; | ||
| 1314 | unsigned IOCTL_PCI_IOC_CFGWRITE = PCI_IOC_CFGWRITE; | ||
| 1315 | unsigned IOCTL_PCI_IOC_BDF_CFGREAD = PCI_IOC_BDF_CFGREAD; | ||
| 1316 | unsigned IOCTL_PCI_IOC_BDF_CFGWRITE = PCI_IOC_BDF_CFGWRITE; | ||
| 1317 | unsigned IOCTL_PCI_IOC_BUSINFO = PCI_IOC_BUSINFO; | ||
| 1318 | unsigned IOCTL_PCI_IOC_DRVNAME = PCI_IOC_DRVNAME; | ||
| 1319 | unsigned IOCTL_PCI_IOC_DRVNAMEONBUS = PCI_IOC_DRVNAMEONBUS; | ||
| 1320 | unsigned IOCTL_TWEIO_COMMAND = TWEIO_COMMAND; | ||
| 1321 | unsigned IOCTL_TWEIO_STATS = TWEIO_STATS; | ||
| 1322 | unsigned IOCTL_TWEIO_AEN_POLL = TWEIO_AEN_POLL; | ||
| 1323 | unsigned IOCTL_TWEIO_AEN_WAIT = TWEIO_AEN_WAIT; | ||
| 1324 | unsigned IOCTL_TWEIO_SET_PARAM = TWEIO_SET_PARAM; | ||
| 1325 | unsigned IOCTL_TWEIO_GET_PARAM = TWEIO_GET_PARAM; | ||
| 1326 | unsigned IOCTL_TWEIO_RESET = TWEIO_RESET; | ||
| 1327 | unsigned IOCTL_TWEIO_ADD_UNIT = TWEIO_ADD_UNIT; | ||
| 1328 | unsigned IOCTL_TWEIO_DEL_UNIT = TWEIO_DEL_UNIT; | ||
| 1329 | unsigned IOCTL_SIOCSCNWDOMAIN = SIOCSCNWDOMAIN; | ||
| 1330 | unsigned IOCTL_SIOCGCNWDOMAIN = SIOCGCNWDOMAIN; | ||
| 1331 | unsigned IOCTL_SIOCSCNWKEY = SIOCSCNWKEY; | ||
| 1332 | unsigned IOCTL_SIOCGCNWSTATUS = SIOCGCNWSTATUS; | ||
| 1333 | unsigned IOCTL_SIOCGCNWSTATS = SIOCGCNWSTATS; | ||
| 1334 | unsigned IOCTL_SIOCGCNWTRAIL = SIOCGCNWTRAIL; | ||
| 1335 | unsigned IOCTL_SIOCGRAYSIGLEV = SIOCGRAYSIGLEV; | ||
| 1336 | unsigned IOCTL_RAIDFRAME_SHUTDOWN = RAIDFRAME_SHUTDOWN; | ||
| 1337 | unsigned IOCTL_RAIDFRAME_TUR = RAIDFRAME_TUR; | ||
| 1338 | unsigned IOCTL_RAIDFRAME_FAIL_DISK = RAIDFRAME_FAIL_DISK; | ||
| 1339 | unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS = RAIDFRAME_CHECK_RECON_STATUS; | ||
| 1340 | unsigned IOCTL_RAIDFRAME_REWRITEPARITY = RAIDFRAME_REWRITEPARITY; | ||
| 1341 | unsigned IOCTL_RAIDFRAME_COPYBACK = RAIDFRAME_COPYBACK; | ||
| 1342 | unsigned IOCTL_RAIDFRAME_SPARET_WAIT = RAIDFRAME_SPARET_WAIT; | ||
| 1343 | unsigned IOCTL_RAIDFRAME_SEND_SPARET = RAIDFRAME_SEND_SPARET; | ||
| 1344 | unsigned IOCTL_RAIDFRAME_ABORT_SPARET_WAIT = RAIDFRAME_ABORT_SPARET_WAIT; | ||
| 1345 | unsigned IOCTL_RAIDFRAME_START_ATRACE = RAIDFRAME_START_ATRACE; | ||
| 1346 | unsigned IOCTL_RAIDFRAME_STOP_ATRACE = RAIDFRAME_STOP_ATRACE; | ||
| 1347 | unsigned IOCTL_RAIDFRAME_GET_SIZE = RAIDFRAME_GET_SIZE; | ||
| 1348 | unsigned IOCTL_RAIDFRAME_RESET_ACCTOTALS = RAIDFRAME_RESET_ACCTOTALS; | ||
| 1349 | unsigned IOCTL_RAIDFRAME_KEEP_ACCTOTALS = RAIDFRAME_KEEP_ACCTOTALS; | ||
| 1350 | unsigned IOCTL_RAIDFRAME_GET_COMPONENT_LABEL = RAIDFRAME_GET_COMPONENT_LABEL; | ||
| 1351 | unsigned IOCTL_RAIDFRAME_SET_COMPONENT_LABEL = RAIDFRAME_SET_COMPONENT_LABEL; | ||
| 1352 | unsigned IOCTL_RAIDFRAME_INIT_LABELS = RAIDFRAME_INIT_LABELS; | ||
| 1353 | unsigned IOCTL_RAIDFRAME_ADD_HOT_SPARE = RAIDFRAME_ADD_HOT_SPARE; | ||
| 1354 | unsigned IOCTL_RAIDFRAME_REMOVE_HOT_SPARE = RAIDFRAME_REMOVE_HOT_SPARE; | ||
| 1355 | unsigned IOCTL_RAIDFRAME_REBUILD_IN_PLACE = RAIDFRAME_REBUILD_IN_PLACE; | ||
| 1356 | unsigned IOCTL_RAIDFRAME_CHECK_PARITY = RAIDFRAME_CHECK_PARITY; | ||
| 1357 | unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS = | ||
| 1358 | RAIDFRAME_CHECK_PARITYREWRITE_STATUS; | ||
| 1359 | unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS = | ||
| 1360 | RAIDFRAME_CHECK_COPYBACK_STATUS; | ||
| 1361 | unsigned IOCTL_RAIDFRAME_SET_AUTOCONFIG = RAIDFRAME_SET_AUTOCONFIG; | ||
| 1362 | unsigned IOCTL_RAIDFRAME_SET_ROOT = RAIDFRAME_SET_ROOT; | ||
| 1363 | unsigned IOCTL_RAIDFRAME_DELETE_COMPONENT = RAIDFRAME_DELETE_COMPONENT; | ||
| 1364 | unsigned IOCTL_RAIDFRAME_INCORPORATE_HOT_SPARE = | ||
| 1365 | RAIDFRAME_INCORPORATE_HOT_SPARE; | ||
| 1366 | unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS_EXT = | ||
| 1367 | RAIDFRAME_CHECK_RECON_STATUS_EXT; | ||
| 1368 | unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT = | ||
| 1369 | RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT; | ||
| 1370 | unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS_EXT = | ||
| 1371 | RAIDFRAME_CHECK_COPYBACK_STATUS_EXT; | ||
| 1372 | unsigned IOCTL_RAIDFRAME_CONFIGURE = RAIDFRAME_CONFIGURE; | ||
| 1373 | unsigned IOCTL_RAIDFRAME_GET_INFO = RAIDFRAME_GET_INFO; | ||
| 1374 | unsigned IOCTL_RAIDFRAME_PARITYMAP_STATUS = RAIDFRAME_PARITYMAP_STATUS; | ||
| 1375 | unsigned IOCTL_RAIDFRAME_PARITYMAP_GET_DISABLE = | ||
| 1376 | RAIDFRAME_PARITYMAP_GET_DISABLE; | ||
| 1377 | unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_DISABLE = | ||
| 1378 | RAIDFRAME_PARITYMAP_SET_DISABLE; | ||
| 1379 | unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_PARAMS = RAIDFRAME_PARITYMAP_SET_PARAMS; | ||
| 1380 | unsigned IOCTL_RAIDFRAME_SET_LAST_UNIT = RAIDFRAME_SET_LAST_UNIT; | ||
| 1381 | unsigned IOCTL_MBPPIOCSPARAM = MBPPIOCSPARAM; | ||
| 1382 | unsigned IOCTL_MBPPIOCGPARAM = MBPPIOCGPARAM; | ||
| 1383 | unsigned IOCTL_MBPPIOCGSTAT = MBPPIOCGSTAT; | ||
| 1384 | unsigned IOCTL_SESIOC_GETNOBJ = SESIOC_GETNOBJ; | ||
| 1385 | unsigned IOCTL_SESIOC_GETOBJMAP = SESIOC_GETOBJMAP; | ||
| 1386 | unsigned IOCTL_SESIOC_GETENCSTAT = SESIOC_GETENCSTAT; | ||
| 1387 | unsigned IOCTL_SESIOC_SETENCSTAT = SESIOC_SETENCSTAT; | ||
| 1388 | unsigned IOCTL_SESIOC_GETOBJSTAT = SESIOC_GETOBJSTAT; | ||
| 1389 | unsigned IOCTL_SESIOC_SETOBJSTAT = SESIOC_SETOBJSTAT; | ||
| 1390 | unsigned IOCTL_SESIOC_GETTEXT = SESIOC_GETTEXT; | ||
| 1391 | unsigned IOCTL_SESIOC_INIT = SESIOC_INIT; | ||
| 1392 | unsigned IOCTL_SUN_DKIOCGGEOM = SUN_DKIOCGGEOM; | ||
| 1393 | unsigned IOCTL_SUN_DKIOCINFO = SUN_DKIOCINFO; | ||
| 1394 | unsigned IOCTL_SUN_DKIOCGPART = SUN_DKIOCGPART; | ||
| 1395 | unsigned IOCTL_FBIOGTYPE = FBIOGTYPE; | ||
| 1396 | unsigned IOCTL_FBIOPUTCMAP = FBIOPUTCMAP; | ||
| 1397 | unsigned IOCTL_FBIOGETCMAP = FBIOGETCMAP; | ||
| 1398 | unsigned IOCTL_FBIOGATTR = FBIOGATTR; | ||
| 1399 | unsigned IOCTL_FBIOSVIDEO = FBIOSVIDEO; | ||
| 1400 | unsigned IOCTL_FBIOGVIDEO = FBIOGVIDEO; | ||
| 1401 | unsigned IOCTL_FBIOSCURSOR = FBIOSCURSOR; | ||
| 1402 | unsigned IOCTL_FBIOGCURSOR = FBIOGCURSOR; | ||
| 1403 | unsigned IOCTL_FBIOSCURPOS = FBIOSCURPOS; | ||
| 1404 | unsigned IOCTL_FBIOGCURPOS = FBIOGCURPOS; | ||
| 1405 | unsigned IOCTL_FBIOGCURMAX = FBIOGCURMAX; | ||
| 1406 | unsigned IOCTL_KIOCTRANS = KIOCTRANS; | ||
| 1407 | unsigned IOCTL_KIOCSETKEY = KIOCSETKEY; | ||
| 1408 | unsigned IOCTL_KIOCGETKEY = KIOCGETKEY; | ||
| 1409 | unsigned IOCTL_KIOCGTRANS = KIOCGTRANS; | ||
| 1410 | unsigned IOCTL_KIOCCMD = KIOCCMD; | ||
| 1411 | unsigned IOCTL_KIOCTYPE = KIOCTYPE; | ||
| 1412 | unsigned IOCTL_KIOCSDIRECT = KIOCSDIRECT; | ||
| 1413 | unsigned IOCTL_KIOCSKEY = KIOCSKEY; | ||
| 1414 | unsigned IOCTL_KIOCGKEY = KIOCGKEY; | ||
| 1415 | unsigned IOCTL_KIOCSLED = KIOCSLED; | ||
| 1416 | unsigned IOCTL_KIOCGLED = KIOCGLED; | ||
| 1417 | unsigned IOCTL_KIOCLAYOUT = KIOCLAYOUT; | ||
| 1418 | unsigned IOCTL_VUIDSFORMAT = VUIDSFORMAT; | ||
| 1419 | unsigned IOCTL_VUIDGFORMAT = VUIDGFORMAT; | ||
| 1420 | unsigned IOCTL_STICIO_GXINFO = STICIO_GXINFO; | ||
| 1421 | unsigned IOCTL_STICIO_RESET = STICIO_RESET; | ||
| 1422 | unsigned IOCTL_STICIO_STARTQ = STICIO_STARTQ; | ||
| 1423 | unsigned IOCTL_STICIO_STOPQ = STICIO_STOPQ; | ||
| 1424 | unsigned IOCTL_UKYOPON_IDENTIFY = UKYOPON_IDENTIFY; | ||
| 1425 | unsigned IOCTL_URIO_SEND_COMMAND = URIO_SEND_COMMAND; | ||
| 1426 | unsigned IOCTL_URIO_RECV_COMMAND = URIO_RECV_COMMAND; | ||
| 1427 | unsigned IOCTL_USB_REQUEST = USB_REQUEST; | ||
| 1428 | unsigned IOCTL_USB_SETDEBUG = USB_SETDEBUG; | ||
| 1429 | unsigned IOCTL_USB_DISCOVER = USB_DISCOVER; | ||
| 1430 | unsigned IOCTL_USB_DEVICEINFO = USB_DEVICEINFO; | ||
| 1431 | unsigned IOCTL_USB_DEVICEINFO_OLD = USB_DEVICEINFO_OLD; | ||
| 1432 | unsigned IOCTL_USB_DEVICESTATS = USB_DEVICESTATS; | ||
| 1433 | unsigned IOCTL_USB_GET_REPORT_DESC = USB_GET_REPORT_DESC; | ||
| 1434 | unsigned IOCTL_USB_SET_IMMED = USB_SET_IMMED; | ||
| 1435 | unsigned IOCTL_USB_GET_REPORT = USB_GET_REPORT; | ||
| 1436 | unsigned IOCTL_USB_SET_REPORT = USB_SET_REPORT; | ||
| 1437 | unsigned IOCTL_USB_GET_REPORT_ID = USB_GET_REPORT_ID; | ||
| 1438 | unsigned IOCTL_USB_GET_CONFIG = USB_GET_CONFIG; | ||
| 1439 | unsigned IOCTL_USB_SET_CONFIG = USB_SET_CONFIG; | ||
| 1440 | unsigned IOCTL_USB_GET_ALTINTERFACE = USB_GET_ALTINTERFACE; | ||
| 1441 | unsigned IOCTL_USB_SET_ALTINTERFACE = USB_SET_ALTINTERFACE; | ||
| 1442 | unsigned IOCTL_USB_GET_NO_ALT = USB_GET_NO_ALT; | ||
| 1443 | unsigned IOCTL_USB_GET_DEVICE_DESC = USB_GET_DEVICE_DESC; | ||
| 1444 | unsigned IOCTL_USB_GET_CONFIG_DESC = USB_GET_CONFIG_DESC; | ||
| 1445 | unsigned IOCTL_USB_GET_INTERFACE_DESC = USB_GET_INTERFACE_DESC; | ||
| 1446 | unsigned IOCTL_USB_GET_ENDPOINT_DESC = USB_GET_ENDPOINT_DESC; | ||
| 1447 | unsigned IOCTL_USB_GET_FULL_DESC = USB_GET_FULL_DESC; | ||
| 1448 | unsigned IOCTL_USB_GET_STRING_DESC = USB_GET_STRING_DESC; | ||
| 1449 | unsigned IOCTL_USB_DO_REQUEST = USB_DO_REQUEST; | ||
| 1450 | unsigned IOCTL_USB_GET_DEVICEINFO = USB_GET_DEVICEINFO; | ||
| 1451 | unsigned IOCTL_USB_GET_DEVICEINFO_OLD = USB_GET_DEVICEINFO_OLD; | ||
| 1452 | unsigned IOCTL_USB_SET_SHORT_XFER = USB_SET_SHORT_XFER; | ||
| 1453 | unsigned IOCTL_USB_SET_TIMEOUT = USB_SET_TIMEOUT; | ||
| 1454 | unsigned IOCTL_USB_SET_BULK_RA = USB_SET_BULK_RA; | ||
| 1455 | unsigned IOCTL_USB_SET_BULK_WB = USB_SET_BULK_WB; | ||
| 1456 | unsigned IOCTL_USB_SET_BULK_RA_OPT = USB_SET_BULK_RA_OPT; | ||
| 1457 | unsigned IOCTL_USB_SET_BULK_WB_OPT = USB_SET_BULK_WB_OPT; | ||
| 1458 | unsigned IOCTL_USB_GET_CM_OVER_DATA = USB_GET_CM_OVER_DATA; | ||
| 1459 | unsigned IOCTL_USB_SET_CM_OVER_DATA = USB_SET_CM_OVER_DATA; | ||
| 1460 | unsigned IOCTL_UTOPPYIOTURBO = UTOPPYIOTURBO; | ||
| 1461 | unsigned IOCTL_UTOPPYIOCANCEL = UTOPPYIOCANCEL; | ||
| 1462 | unsigned IOCTL_UTOPPYIOREBOOT = UTOPPYIOREBOOT; | ||
| 1463 | unsigned IOCTL_UTOPPYIOSTATS = UTOPPYIOSTATS; | ||
| 1464 | unsigned IOCTL_UTOPPYIORENAME = UTOPPYIORENAME; | ||
| 1465 | unsigned IOCTL_UTOPPYIOMKDIR = UTOPPYIOMKDIR; | ||
| 1466 | unsigned IOCTL_UTOPPYIODELETE = UTOPPYIODELETE; | ||
| 1467 | unsigned IOCTL_UTOPPYIOREADDIR = UTOPPYIOREADDIR; | ||
| 1468 | unsigned IOCTL_UTOPPYIOREADFILE = UTOPPYIOREADFILE; | ||
| 1469 | unsigned IOCTL_UTOPPYIOWRITEFILE = UTOPPYIOWRITEFILE; | ||
| 1470 | unsigned IOCTL_DIOSXDCMD = DIOSXDCMD; | ||
| 1471 | unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; | ||
| 1472 | unsigned IOCTL_VT_SETMODE = VT_SETMODE; | ||
| 1473 | unsigned IOCTL_VT_GETMODE = VT_GETMODE; | ||
| 1474 | unsigned IOCTL_VT_RELDISP = VT_RELDISP; | ||
| 1475 | unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; | ||
| 1476 | unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; | ||
| 1477 | unsigned IOCTL_VT_GETACTIVE = VT_GETACTIVE; | ||
| 1478 | unsigned IOCTL_VT_GETSTATE = VT_GETSTATE; | ||
| 1479 | unsigned IOCTL_KDGETKBENT = KDGETKBENT; | ||
| 1480 | unsigned IOCTL_KDGKBMODE = KDGKBMODE; | ||
| 1481 | unsigned IOCTL_KDSKBMODE = KDSKBMODE; | ||
| 1482 | unsigned IOCTL_KDMKTONE = KDMKTONE; | ||
| 1483 | unsigned IOCTL_KDSETMODE = KDSETMODE; | ||
| 1484 | unsigned IOCTL_KDENABIO = KDENABIO; | ||
| 1485 | unsigned IOCTL_KDDISABIO = KDDISABIO; | ||
| 1486 | unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; | ||
| 1487 | unsigned IOCTL_KDGETLED = KDGETLED; | ||
| 1488 | unsigned IOCTL_KDSETLED = KDSETLED; | ||
| 1489 | unsigned IOCTL_KDSETRAD = KDSETRAD; | ||
| 1490 | unsigned IOCTL_VGAPCVTID = VGAPCVTID; | ||
| 1491 | unsigned IOCTL_CONS_GETVERS = CONS_GETVERS; | ||
| 1492 | unsigned IOCTL_WSKBDIO_GTYPE = WSKBDIO_GTYPE; | ||
| 1493 | unsigned IOCTL_WSKBDIO_BELL = WSKBDIO_BELL; | ||
| 1494 | unsigned IOCTL_WSKBDIO_COMPLEXBELL = WSKBDIO_COMPLEXBELL; | ||
| 1495 | unsigned IOCTL_WSKBDIO_SETBELL = WSKBDIO_SETBELL; | ||
| 1496 | unsigned IOCTL_WSKBDIO_GETBELL = WSKBDIO_GETBELL; | ||
| 1497 | unsigned IOCTL_WSKBDIO_SETDEFAULTBELL = WSKBDIO_SETDEFAULTBELL; | ||
| 1498 | unsigned IOCTL_WSKBDIO_GETDEFAULTBELL = WSKBDIO_GETDEFAULTBELL; | ||
| 1499 | unsigned IOCTL_WSKBDIO_SETKEYREPEAT = WSKBDIO_SETKEYREPEAT; | ||
| 1500 | unsigned IOCTL_WSKBDIO_GETKEYREPEAT = WSKBDIO_GETKEYREPEAT; | ||
| 1501 | unsigned IOCTL_WSKBDIO_SETDEFAULTKEYREPEAT = WSKBDIO_SETDEFAULTKEYREPEAT; | ||
| 1502 | unsigned IOCTL_WSKBDIO_GETDEFAULTKEYREPEAT = WSKBDIO_GETDEFAULTKEYREPEAT; | ||
| 1503 | unsigned IOCTL_WSKBDIO_SETLEDS = WSKBDIO_SETLEDS; | ||
| 1504 | unsigned IOCTL_WSKBDIO_GETLEDS = WSKBDIO_GETLEDS; | ||
| 1505 | unsigned IOCTL_WSKBDIO_GETMAP = WSKBDIO_GETMAP; | ||
| 1506 | unsigned IOCTL_WSKBDIO_SETMAP = WSKBDIO_SETMAP; | ||
| 1507 | unsigned IOCTL_WSKBDIO_GETENCODING = WSKBDIO_GETENCODING; | ||
| 1508 | unsigned IOCTL_WSKBDIO_SETENCODING = WSKBDIO_SETENCODING; | ||
| 1509 | unsigned IOCTL_WSKBDIO_SETMODE = WSKBDIO_SETMODE; | ||
| 1510 | unsigned IOCTL_WSKBDIO_GETMODE = WSKBDIO_GETMODE; | ||
| 1511 | unsigned IOCTL_WSKBDIO_SETKEYCLICK = WSKBDIO_SETKEYCLICK; | ||
| 1512 | unsigned IOCTL_WSKBDIO_GETKEYCLICK = WSKBDIO_GETKEYCLICK; | ||
| 1513 | unsigned IOCTL_WSKBDIO_GETSCROLL = WSKBDIO_GETSCROLL; | ||
| 1514 | unsigned IOCTL_WSKBDIO_SETSCROLL = WSKBDIO_SETSCROLL; | ||
| 1515 | unsigned IOCTL_WSKBDIO_SETVERSION = WSKBDIO_SETVERSION; | ||
| 1516 | unsigned IOCTL_WSMOUSEIO_GTYPE = WSMOUSEIO_GTYPE; | ||
| 1517 | unsigned IOCTL_WSMOUSEIO_SRES = WSMOUSEIO_SRES; | ||
| 1518 | unsigned IOCTL_WSMOUSEIO_SSCALE = WSMOUSEIO_SSCALE; | ||
| 1519 | unsigned IOCTL_WSMOUSEIO_SRATE = WSMOUSEIO_SRATE; | ||
| 1520 | unsigned IOCTL_WSMOUSEIO_SCALIBCOORDS = WSMOUSEIO_SCALIBCOORDS; | ||
| 1521 | unsigned IOCTL_WSMOUSEIO_GCALIBCOORDS = WSMOUSEIO_GCALIBCOORDS; | ||
| 1522 | unsigned IOCTL_WSMOUSEIO_GETID = WSMOUSEIO_GETID; | ||
| 1523 | unsigned IOCTL_WSMOUSEIO_GETREPEAT = WSMOUSEIO_GETREPEAT; | ||
| 1524 | unsigned IOCTL_WSMOUSEIO_SETREPEAT = WSMOUSEIO_SETREPEAT; | ||
| 1525 | unsigned IOCTL_WSMOUSEIO_SETVERSION = WSMOUSEIO_SETVERSION; | ||
| 1526 | unsigned IOCTL_WSDISPLAYIO_GTYPE = WSDISPLAYIO_GTYPE; | ||
| 1527 | unsigned IOCTL_WSDISPLAYIO_GINFO = WSDISPLAYIO_GINFO; | ||
| 1528 | unsigned IOCTL_WSDISPLAYIO_GETCMAP = WSDISPLAYIO_GETCMAP; | ||
| 1529 | unsigned IOCTL_WSDISPLAYIO_PUTCMAP = WSDISPLAYIO_PUTCMAP; | ||
| 1530 | unsigned IOCTL_WSDISPLAYIO_GVIDEO = WSDISPLAYIO_GVIDEO; | ||
| 1531 | unsigned IOCTL_WSDISPLAYIO_SVIDEO = WSDISPLAYIO_SVIDEO; | ||
| 1532 | unsigned IOCTL_WSDISPLAYIO_GCURPOS = WSDISPLAYIO_GCURPOS; | ||
| 1533 | unsigned IOCTL_WSDISPLAYIO_SCURPOS = WSDISPLAYIO_SCURPOS; | ||
| 1534 | unsigned IOCTL_WSDISPLAYIO_GCURMAX = WSDISPLAYIO_GCURMAX; | ||
| 1535 | unsigned IOCTL_WSDISPLAYIO_GCURSOR = WSDISPLAYIO_GCURSOR; | ||
| 1536 | unsigned IOCTL_WSDISPLAYIO_SCURSOR = WSDISPLAYIO_SCURSOR; | ||
| 1537 | unsigned IOCTL_WSDISPLAYIO_GMODE = WSDISPLAYIO_GMODE; | ||
| 1538 | unsigned IOCTL_WSDISPLAYIO_SMODE = WSDISPLAYIO_SMODE; | ||
| 1539 | unsigned IOCTL_WSDISPLAYIO_LDFONT = WSDISPLAYIO_LDFONT; | ||
| 1540 | unsigned IOCTL_WSDISPLAYIO_ADDSCREEN = WSDISPLAYIO_ADDSCREEN; | ||
| 1541 | unsigned IOCTL_WSDISPLAYIO_DELSCREEN = WSDISPLAYIO_DELSCREEN; | ||
| 1542 | unsigned IOCTL_WSDISPLAYIO_SFONT = WSDISPLAYIO_SFONT; | ||
| 1543 | unsigned IOCTL__O_WSDISPLAYIO_SETKEYBOARD = _O_WSDISPLAYIO_SETKEYBOARD; | ||
| 1544 | unsigned IOCTL_WSDISPLAYIO_GETPARAM = WSDISPLAYIO_GETPARAM; | ||
| 1545 | unsigned IOCTL_WSDISPLAYIO_SETPARAM = WSDISPLAYIO_SETPARAM; | ||
| 1546 | unsigned IOCTL_WSDISPLAYIO_GETACTIVESCREEN = WSDISPLAYIO_GETACTIVESCREEN; | ||
| 1547 | unsigned IOCTL_WSDISPLAYIO_GETWSCHAR = WSDISPLAYIO_GETWSCHAR; | ||
| 1548 | unsigned IOCTL_WSDISPLAYIO_PUTWSCHAR = WSDISPLAYIO_PUTWSCHAR; | ||
| 1549 | unsigned IOCTL_WSDISPLAYIO_DGSCROLL = WSDISPLAYIO_DGSCROLL; | ||
| 1550 | unsigned IOCTL_WSDISPLAYIO_DSSCROLL = WSDISPLAYIO_DSSCROLL; | ||
| 1551 | unsigned IOCTL_WSDISPLAYIO_GMSGATTRS = WSDISPLAYIO_GMSGATTRS; | ||
| 1552 | unsigned IOCTL_WSDISPLAYIO_SMSGATTRS = WSDISPLAYIO_SMSGATTRS; | ||
| 1553 | unsigned IOCTL_WSDISPLAYIO_GBORDER = WSDISPLAYIO_GBORDER; | ||
| 1554 | unsigned IOCTL_WSDISPLAYIO_SBORDER = WSDISPLAYIO_SBORDER; | ||
| 1555 | unsigned IOCTL_WSDISPLAYIO_SSPLASH = WSDISPLAYIO_SSPLASH; | ||
| 1556 | unsigned IOCTL_WSDISPLAYIO_SPROGRESS = WSDISPLAYIO_SPROGRESS; | ||
| 1557 | unsigned IOCTL_WSDISPLAYIO_LINEBYTES = WSDISPLAYIO_LINEBYTES; | ||
| 1558 | unsigned IOCTL_WSDISPLAYIO_SETVERSION = WSDISPLAYIO_SETVERSION; | ||
| 1559 | unsigned IOCTL_WSMUXIO_ADD_DEVICE = WSMUXIO_ADD_DEVICE; | ||
| 1560 | unsigned IOCTL_WSMUXIO_REMOVE_DEVICE = WSMUXIO_REMOVE_DEVICE; | ||
| 1561 | unsigned IOCTL_WSMUXIO_LIST_DEVICES = WSMUXIO_LIST_DEVICES; | ||
| 1562 | unsigned IOCTL_WSMUXIO_INJECTEVENT = WSMUXIO_INJECTEVENT; | ||
| 1563 | unsigned IOCTL_WSDISPLAYIO_GET_BUSID = WSDISPLAYIO_GET_BUSID; | ||
| 1564 | unsigned IOCTL_WSDISPLAYIO_GET_EDID = WSDISPLAYIO_GET_EDID; | ||
| 1565 | unsigned IOCTL_WSDISPLAYIO_SET_POLLING = WSDISPLAYIO_SET_POLLING; | ||
| 1566 | unsigned IOCTL_WSDISPLAYIO_GET_FBINFO = WSDISPLAYIO_GET_FBINFO; | ||
| 1567 | unsigned IOCTL_WSDISPLAYIO_DOBLIT = WSDISPLAYIO_DOBLIT; | ||
| 1568 | unsigned IOCTL_WSDISPLAYIO_WAITBLIT = WSDISPLAYIO_WAITBLIT; | ||
| 1569 | unsigned IOCTL_BIOCLOCATE = BIOCLOCATE; | ||
| 1570 | unsigned IOCTL_BIOCINQ = BIOCINQ; | ||
| 1571 | unsigned IOCTL_BIOCDISK_NOVOL = BIOCDISK_NOVOL; | ||
| 1572 | unsigned IOCTL_BIOCDISK = BIOCDISK; | ||
| 1573 | unsigned IOCTL_BIOCVOL = BIOCVOL; | ||
| 1574 | unsigned IOCTL_BIOCALARM = BIOCALARM; | ||
| 1575 | unsigned IOCTL_BIOCBLINK = BIOCBLINK; | ||
| 1576 | unsigned IOCTL_BIOCSETSTATE = BIOCSETSTATE; | ||
| 1577 | unsigned IOCTL_BIOCVOLOPS = BIOCVOLOPS; | ||
| 1578 | unsigned IOCTL_MD_GETCONF = MD_GETCONF; | ||
| 1579 | unsigned IOCTL_MD_SETCONF = MD_SETCONF; | ||
| 1580 | unsigned IOCTL_CCDIOCSET = CCDIOCSET; | ||
| 1581 | unsigned IOCTL_CCDIOCCLR = CCDIOCCLR; | ||
| 1582 | unsigned IOCTL_CGDIOCSET = CGDIOCSET; | ||
| 1583 | unsigned IOCTL_CGDIOCCLR = CGDIOCCLR; | ||
| 1584 | unsigned IOCTL_CGDIOCGET = CGDIOCGET; | ||
| 1585 | unsigned IOCTL_FSSIOCSET = FSSIOCSET; | ||
| 1586 | unsigned IOCTL_FSSIOCGET = FSSIOCGET; | ||
| 1587 | unsigned IOCTL_FSSIOCCLR = FSSIOCCLR; | ||
| 1588 | unsigned IOCTL_FSSIOFSET = FSSIOFSET; | ||
| 1589 | unsigned IOCTL_FSSIOFGET = FSSIOFGET; | ||
| 1590 | unsigned IOCTL_BTDEV_ATTACH = BTDEV_ATTACH; | ||
| 1591 | unsigned IOCTL_BTDEV_DETACH = BTDEV_DETACH; | ||
| 1592 | unsigned IOCTL_BTSCO_GETINFO = BTSCO_GETINFO; | ||
| 1593 | unsigned IOCTL_KTTCP_IO_SEND = KTTCP_IO_SEND; | ||
| 1594 | unsigned IOCTL_KTTCP_IO_RECV = KTTCP_IO_RECV; | ||
| 1595 | unsigned IOCTL_IOC_LOCKSTAT_GVERSION = IOC_LOCKSTAT_GVERSION; | ||
| 1596 | unsigned IOCTL_IOC_LOCKSTAT_ENABLE = IOC_LOCKSTAT_ENABLE; | ||
| 1597 | unsigned IOCTL_IOC_LOCKSTAT_DISABLE = IOC_LOCKSTAT_DISABLE; | ||
| 1598 | unsigned IOCTL_VNDIOCSET = VNDIOCSET; | ||
| 1599 | unsigned IOCTL_VNDIOCCLR = VNDIOCCLR; | ||
| 1600 | unsigned IOCTL_VNDIOCGET = VNDIOCGET; | ||
| 1601 | unsigned IOCTL_SPKRTONE = SPKRTONE; | ||
| 1602 | unsigned IOCTL_SPKRTUNE = SPKRTUNE; | ||
| 1603 | unsigned IOCTL_SPKRGETVOL = SPKRGETVOL; | ||
| 1604 | unsigned IOCTL_SPKRSETVOL = SPKRSETVOL; | ||
| 1605 | #if defined(__x86_64__) | ||
| 1606 | unsigned IOCTL_NVMM_IOC_CAPABILITY = NVMM_IOC_CAPABILITY; | ||
| 1607 | unsigned IOCTL_NVMM_IOC_MACHINE_CREATE = NVMM_IOC_MACHINE_CREATE; | ||
| 1608 | unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY = NVMM_IOC_MACHINE_DESTROY; | ||
| 1609 | unsigned IOCTL_NVMM_IOC_MACHINE_CONFIGURE = NVMM_IOC_MACHINE_CONFIGURE; | ||
| 1610 | unsigned IOCTL_NVMM_IOC_VCPU_CREATE = NVMM_IOC_VCPU_CREATE; | ||
| 1611 | unsigned IOCTL_NVMM_IOC_VCPU_DESTROY = NVMM_IOC_VCPU_DESTROY; | ||
| 1612 | unsigned IOCTL_NVMM_IOC_VCPU_CONFIGURE = NVMM_IOC_VCPU_CONFIGURE; | ||
| 1613 | unsigned IOCTL_NVMM_IOC_VCPU_SETSTATE = NVMM_IOC_VCPU_SETSTATE; | ||
| 1614 | unsigned IOCTL_NVMM_IOC_VCPU_GETSTATE = NVMM_IOC_VCPU_GETSTATE; | ||
| 1615 | unsigned IOCTL_NVMM_IOC_VCPU_INJECT = NVMM_IOC_VCPU_INJECT; | ||
| 1616 | unsigned IOCTL_NVMM_IOC_VCPU_RUN = NVMM_IOC_VCPU_RUN; | ||
| 1617 | unsigned IOCTL_NVMM_IOC_GPA_MAP = NVMM_IOC_GPA_MAP; | ||
| 1618 | unsigned IOCTL_NVMM_IOC_GPA_UNMAP = NVMM_IOC_GPA_UNMAP; | ||
| 1619 | unsigned IOCTL_NVMM_IOC_HVA_MAP = NVMM_IOC_HVA_MAP; | ||
| 1620 | unsigned IOCTL_NVMM_IOC_HVA_UNMAP = NVMM_IOC_HVA_UNMAP; | ||
| 1621 | unsigned IOCTL_NVMM_IOC_CTL = NVMM_IOC_CTL; | ||
| 1622 | #endif | ||
| 1623 | unsigned IOCTL_SPI_IOCTL_CONFIGURE = SPI_IOCTL_CONFIGURE; | ||
| 1624 | unsigned IOCTL_SPI_IOCTL_TRANSFER = SPI_IOCTL_TRANSFER; | ||
| 1625 | unsigned IOCTL_AUTOFSREQUEST = AUTOFSREQUEST; | ||
| 1626 | unsigned IOCTL_AUTOFSDONE = AUTOFSDONE; | ||
| 1627 | unsigned IOCTL_BIOCGBLEN = BIOCGBLEN; | ||
| 1628 | unsigned IOCTL_BIOCSBLEN = BIOCSBLEN; | ||
| 1629 | unsigned IOCTL_BIOCSETF = BIOCSETF; | ||
| 1630 | unsigned IOCTL_BIOCFLUSH = BIOCFLUSH; | ||
| 1631 | unsigned IOCTL_BIOCPROMISC = BIOCPROMISC; | ||
| 1632 | unsigned IOCTL_BIOCGDLT = BIOCGDLT; | ||
| 1633 | unsigned IOCTL_BIOCGETIF = BIOCGETIF; | ||
| 1634 | unsigned IOCTL_BIOCSETIF = BIOCSETIF; | ||
| 1635 | unsigned IOCTL_BIOCGSTATS = BIOCGSTATS; | ||
| 1636 | unsigned IOCTL_BIOCGSTATSOLD = BIOCGSTATSOLD; | ||
| 1637 | unsigned IOCTL_BIOCIMMEDIATE = BIOCIMMEDIATE; | ||
| 1638 | unsigned IOCTL_BIOCVERSION = BIOCVERSION; | ||
| 1639 | unsigned IOCTL_BIOCSTCPF = BIOCSTCPF; | ||
| 1640 | unsigned IOCTL_BIOCSUDPF = BIOCSUDPF; | ||
| 1641 | unsigned IOCTL_BIOCGHDRCMPLT = BIOCGHDRCMPLT; | ||
| 1642 | unsigned IOCTL_BIOCSHDRCMPLT = BIOCSHDRCMPLT; | ||
| 1643 | unsigned IOCTL_BIOCSDLT = BIOCSDLT; | ||
| 1644 | unsigned IOCTL_BIOCGDLTLIST = BIOCGDLTLIST; | ||
| 1645 | unsigned IOCTL_BIOCGDIRECTION = BIOCGDIRECTION; | ||
| 1646 | unsigned IOCTL_BIOCSDIRECTION = BIOCSDIRECTION; | ||
| 1647 | unsigned IOCTL_BIOCSRTIMEOUT = BIOCSRTIMEOUT; | ||
| 1648 | unsigned IOCTL_BIOCGRTIMEOUT = BIOCGRTIMEOUT; | ||
| 1649 | unsigned IOCTL_BIOCGFEEDBACK = BIOCGFEEDBACK; | ||
| 1650 | unsigned IOCTL_BIOCSFEEDBACK = BIOCSFEEDBACK; | ||
| 1651 | unsigned IOCTL_GRESADDRS = GRESADDRS; | ||
| 1652 | unsigned IOCTL_GRESADDRD = GRESADDRD; | ||
| 1653 | unsigned IOCTL_GREGADDRS = GREGADDRS; | ||
| 1654 | unsigned IOCTL_GREGADDRD = GREGADDRD; | ||
| 1655 | unsigned IOCTL_GRESPROTO = GRESPROTO; | ||
| 1656 | unsigned IOCTL_GREGPROTO = GREGPROTO; | ||
| 1657 | unsigned IOCTL_GRESSOCK = GRESSOCK; | ||
| 1658 | unsigned IOCTL_GREDSOCK = GREDSOCK; | ||
| 1659 | unsigned IOCTL_PPPIOCGRAWIN = PPPIOCGRAWIN; | ||
| 1660 | unsigned IOCTL_PPPIOCGFLAGS = PPPIOCGFLAGS; | ||
| 1661 | unsigned IOCTL_PPPIOCSFLAGS = PPPIOCSFLAGS; | ||
| 1662 | unsigned IOCTL_PPPIOCGASYNCMAP = PPPIOCGASYNCMAP; | ||
| 1663 | unsigned IOCTL_PPPIOCSASYNCMAP = PPPIOCSASYNCMAP; | ||
| 1664 | unsigned IOCTL_PPPIOCGUNIT = PPPIOCGUNIT; | ||
| 1665 | unsigned IOCTL_PPPIOCGRASYNCMAP = PPPIOCGRASYNCMAP; | ||
| 1666 | unsigned IOCTL_PPPIOCSRASYNCMAP = PPPIOCSRASYNCMAP; | ||
| 1667 | unsigned IOCTL_PPPIOCGMRU = PPPIOCGMRU; | ||
| 1668 | unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU; | ||
| 1669 | unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID; | ||
| 1670 | unsigned IOCTL_PPPIOCGXASYNCMAP = PPPIOCGXASYNCMAP; | ||
| 1671 | unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP; | ||
| 1672 | unsigned IOCTL_PPPIOCXFERUNIT = PPPIOCXFERUNIT; | ||
| 1673 | unsigned IOCTL_PPPIOCSCOMPRESS = PPPIOCSCOMPRESS; | ||
| 1674 | unsigned IOCTL_PPPIOCGNPMODE = PPPIOCGNPMODE; | ||
| 1675 | unsigned IOCTL_PPPIOCSNPMODE = PPPIOCSNPMODE; | ||
| 1676 | unsigned IOCTL_PPPIOCGIDLE = PPPIOCGIDLE; | ||
| 1677 | unsigned IOCTL_PPPIOCGMTU = PPPIOCGMTU; | ||
| 1678 | unsigned IOCTL_PPPIOCSMTU = PPPIOCSMTU; | ||
| 1679 | unsigned IOCTL_SIOCGPPPSTATS = SIOCGPPPSTATS; | ||
| 1680 | unsigned IOCTL_SIOCGPPPCSTATS = SIOCGPPPCSTATS; | ||
| 1681 | unsigned IOCTL_IOC_NPF_VERSION = IOC_NPF_VERSION; | ||
| 1682 | unsigned IOCTL_IOC_NPF_SWITCH = IOC_NPF_SWITCH; | ||
| 1683 | unsigned IOCTL_IOC_NPF_LOAD = IOC_NPF_LOAD; | ||
| 1684 | unsigned IOCTL_IOC_NPF_TABLE = IOC_NPF_TABLE; | ||
| 1685 | unsigned IOCTL_IOC_NPF_STATS = IOC_NPF_STATS; | ||
| 1686 | unsigned IOCTL_IOC_NPF_SAVE = IOC_NPF_SAVE; | ||
| 1687 | unsigned IOCTL_IOC_NPF_RULE = IOC_NPF_RULE; | ||
| 1688 | unsigned IOCTL_IOC_NPF_CONN_LOOKUP = IOC_NPF_CONN_LOOKUP; | ||
| 1689 | unsigned IOCTL_IOC_NPF_TABLE_REPLACE = IOC_NPF_TABLE_REPLACE; | ||
| 1690 | unsigned IOCTL_PPPOESETPARMS = PPPOESETPARMS; | ||
| 1691 | unsigned IOCTL_PPPOEGETPARMS = PPPOEGETPARMS; | ||
| 1692 | unsigned IOCTL_PPPOEGETSESSION = PPPOEGETSESSION; | ||
| 1693 | unsigned IOCTL_SPPPGETAUTHCFG = SPPPGETAUTHCFG; | ||
| 1694 | unsigned IOCTL_SPPPSETAUTHCFG = SPPPSETAUTHCFG; | ||
| 1695 | unsigned IOCTL_SPPPGETLCPCFG = SPPPGETLCPCFG; | ||
| 1696 | unsigned IOCTL_SPPPSETLCPCFG = SPPPSETLCPCFG; | ||
| 1697 | unsigned IOCTL_SPPPGETSTATUS = SPPPGETSTATUS; | ||
| 1698 | unsigned IOCTL_SPPPGETSTATUSNCP = SPPPGETSTATUSNCP; | ||
| 1699 | unsigned IOCTL_SPPPGETIDLETO = SPPPGETIDLETO; | ||
| 1700 | unsigned IOCTL_SPPPSETIDLETO = SPPPSETIDLETO; | ||
| 1701 | unsigned IOCTL_SPPPGETAUTHFAILURES = SPPPGETAUTHFAILURES; | ||
| 1702 | unsigned IOCTL_SPPPSETAUTHFAILURE = SPPPSETAUTHFAILURE; | ||
| 1703 | unsigned IOCTL_SPPPSETDNSOPTS = SPPPSETDNSOPTS; | ||
| 1704 | unsigned IOCTL_SPPPGETDNSOPTS = SPPPGETDNSOPTS; | ||
| 1705 | unsigned IOCTL_SPPPGETDNSADDRS = SPPPGETDNSADDRS; | ||
| 1706 | unsigned IOCTL_SPPPSETKEEPALIVE = SPPPSETKEEPALIVE; | ||
| 1707 | unsigned IOCTL_SPPPGETKEEPALIVE = SPPPGETKEEPALIVE; | ||
| 1708 | unsigned IOCTL_SRT_GETNRT = SRT_GETNRT; | ||
| 1709 | unsigned IOCTL_SRT_GETRT = SRT_GETRT; | ||
| 1710 | unsigned IOCTL_SRT_SETRT = SRT_SETRT; | ||
| 1711 | unsigned IOCTL_SRT_DELRT = SRT_DELRT; | ||
| 1712 | unsigned IOCTL_SRT_SFLAGS = SRT_SFLAGS; | ||
| 1713 | unsigned IOCTL_SRT_GFLAGS = SRT_GFLAGS; | ||
| 1714 | unsigned IOCTL_SRT_SGFLAGS = SRT_SGFLAGS; | ||
| 1715 | unsigned IOCTL_SRT_DEBUG = SRT_DEBUG; | ||
| 1716 | unsigned IOCTL_TAPGIFNAME = TAPGIFNAME; | ||
| 1717 | unsigned IOCTL_TUNSDEBUG = TUNSDEBUG; | ||
| 1718 | unsigned IOCTL_TUNGDEBUG = TUNGDEBUG; | ||
| 1719 | unsigned IOCTL_TUNSIFMODE = TUNSIFMODE; | ||
| 1720 | unsigned IOCTL_TUNSLMODE = TUNSLMODE; | ||
| 1721 | unsigned IOCTL_TUNSIFHEAD = TUNSIFHEAD; | ||
| 1722 | unsigned IOCTL_TUNGIFHEAD = TUNGIFHEAD; | ||
| 1723 | unsigned IOCTL_DIOCSTART = DIOCSTART; | ||
| 1724 | unsigned IOCTL_DIOCSTOP = DIOCSTOP; | ||
| 1725 | unsigned IOCTL_DIOCADDRULE = DIOCADDRULE; | ||
| 1726 | unsigned IOCTL_DIOCGETRULES = DIOCGETRULES; | ||
| 1727 | unsigned IOCTL_DIOCGETRULE = DIOCGETRULE; | ||
| 1728 | unsigned IOCTL_DIOCSETLCK = DIOCSETLCK; | ||
| 1729 | unsigned IOCTL_DIOCCLRSTATES = DIOCCLRSTATES; | ||
| 1730 | unsigned IOCTL_DIOCGETSTATE = DIOCGETSTATE; | ||
| 1731 | unsigned IOCTL_DIOCSETSTATUSIF = DIOCSETSTATUSIF; | ||
| 1732 | unsigned IOCTL_DIOCGETSTATUS = DIOCGETSTATUS; | ||
| 1733 | unsigned IOCTL_DIOCCLRSTATUS = DIOCCLRSTATUS; | ||
| 1734 | unsigned IOCTL_DIOCNATLOOK = DIOCNATLOOK; | ||
| 1735 | unsigned IOCTL_DIOCSETDEBUG = DIOCSETDEBUG; | ||
| 1736 | unsigned IOCTL_DIOCGETSTATES = DIOCGETSTATES; | ||
| 1737 | unsigned IOCTL_DIOCCHANGERULE = DIOCCHANGERULE; | ||
| 1738 | unsigned IOCTL_DIOCSETTIMEOUT = DIOCSETTIMEOUT; | ||
| 1739 | unsigned IOCTL_DIOCGETTIMEOUT = DIOCGETTIMEOUT; | ||
| 1740 | unsigned IOCTL_DIOCADDSTATE = DIOCADDSTATE; | ||
| 1741 | unsigned IOCTL_DIOCCLRRULECTRS = DIOCCLRRULECTRS; | ||
| 1742 | unsigned IOCTL_DIOCGETLIMIT = DIOCGETLIMIT; | ||
| 1743 | unsigned IOCTL_DIOCSETLIMIT = DIOCSETLIMIT; | ||
| 1744 | unsigned IOCTL_DIOCKILLSTATES = DIOCKILLSTATES; | ||
| 1745 | unsigned IOCTL_DIOCSTARTALTQ = DIOCSTARTALTQ; | ||
| 1746 | unsigned IOCTL_DIOCSTOPALTQ = DIOCSTOPALTQ; | ||
| 1747 | unsigned IOCTL_DIOCADDALTQ = DIOCADDALTQ; | ||
| 1748 | unsigned IOCTL_DIOCGETALTQS = DIOCGETALTQS; | ||
| 1749 | unsigned IOCTL_DIOCGETALTQ = DIOCGETALTQ; | ||
| 1750 | unsigned IOCTL_DIOCCHANGEALTQ = DIOCCHANGEALTQ; | ||
| 1751 | unsigned IOCTL_DIOCGETQSTATS = DIOCGETQSTATS; | ||
| 1752 | unsigned IOCTL_DIOCBEGINADDRS = DIOCBEGINADDRS; | ||
| 1753 | unsigned IOCTL_DIOCADDADDR = DIOCADDADDR; | ||
| 1754 | unsigned IOCTL_DIOCGETADDRS = DIOCGETADDRS; | ||
| 1755 | unsigned IOCTL_DIOCGETADDR = DIOCGETADDR; | ||
| 1756 | unsigned IOCTL_DIOCCHANGEADDR = DIOCCHANGEADDR; | ||
| 1757 | unsigned IOCTL_DIOCADDSTATES = DIOCADDSTATES; | ||
| 1758 | unsigned IOCTL_DIOCGETRULESETS = DIOCGETRULESETS; | ||
| 1759 | unsigned IOCTL_DIOCGETRULESET = DIOCGETRULESET; | ||
| 1760 | unsigned IOCTL_DIOCRCLRTABLES = DIOCRCLRTABLES; | ||
| 1761 | unsigned IOCTL_DIOCRADDTABLES = DIOCRADDTABLES; | ||
| 1762 | unsigned IOCTL_DIOCRDELTABLES = DIOCRDELTABLES; | ||
| 1763 | unsigned IOCTL_DIOCRGETTABLES = DIOCRGETTABLES; | ||
| 1764 | unsigned IOCTL_DIOCRGETTSTATS = DIOCRGETTSTATS; | ||
| 1765 | unsigned IOCTL_DIOCRCLRTSTATS = DIOCRCLRTSTATS; | ||
| 1766 | unsigned IOCTL_DIOCRCLRADDRS = DIOCRCLRADDRS; | ||
| 1767 | unsigned IOCTL_DIOCRADDADDRS = DIOCRADDADDRS; | ||
| 1768 | unsigned IOCTL_DIOCRDELADDRS = DIOCRDELADDRS; | ||
| 1769 | unsigned IOCTL_DIOCRSETADDRS = DIOCRSETADDRS; | ||
| 1770 | unsigned IOCTL_DIOCRGETADDRS = DIOCRGETADDRS; | ||
| 1771 | unsigned IOCTL_DIOCRGETASTATS = DIOCRGETASTATS; | ||
| 1772 | unsigned IOCTL_DIOCRCLRASTATS = DIOCRCLRASTATS; | ||
| 1773 | unsigned IOCTL_DIOCRTSTADDRS = DIOCRTSTADDRS; | ||
| 1774 | unsigned IOCTL_DIOCRSETTFLAGS = DIOCRSETTFLAGS; | ||
| 1775 | unsigned IOCTL_DIOCRINADEFINE = DIOCRINADEFINE; | ||
| 1776 | unsigned IOCTL_DIOCOSFPFLUSH = DIOCOSFPFLUSH; | ||
| 1777 | unsigned IOCTL_DIOCOSFPADD = DIOCOSFPADD; | ||
| 1778 | unsigned IOCTL_DIOCOSFPGET = DIOCOSFPGET; | ||
| 1779 | unsigned IOCTL_DIOCXBEGIN = DIOCXBEGIN; | ||
| 1780 | unsigned IOCTL_DIOCXCOMMIT = DIOCXCOMMIT; | ||
| 1781 | unsigned IOCTL_DIOCXROLLBACK = DIOCXROLLBACK; | ||
| 1782 | unsigned IOCTL_DIOCGETSRCNODES = DIOCGETSRCNODES; | ||
| 1783 | unsigned IOCTL_DIOCCLRSRCNODES = DIOCCLRSRCNODES; | ||
| 1784 | unsigned IOCTL_DIOCSETHOSTID = DIOCSETHOSTID; | ||
| 1785 | unsigned IOCTL_DIOCIGETIFACES = DIOCIGETIFACES; | ||
| 1786 | unsigned IOCTL_DIOCSETIFFLAG = DIOCSETIFFLAG; | ||
| 1787 | unsigned IOCTL_DIOCCLRIFFLAG = DIOCCLRIFFLAG; | ||
| 1788 | unsigned IOCTL_DIOCKILLSRCNODES = DIOCKILLSRCNODES; | ||
| 1789 | unsigned IOCTL_SLIOCGUNIT = SLIOCGUNIT; | ||
| 1790 | unsigned IOCTL_SIOCGBTINFO = SIOCGBTINFO; | ||
| 1791 | unsigned IOCTL_SIOCGBTINFOA = SIOCGBTINFOA; | ||
| 1792 | unsigned IOCTL_SIOCNBTINFO = SIOCNBTINFO; | ||
| 1793 | unsigned IOCTL_SIOCSBTFLAGS = SIOCSBTFLAGS; | ||
| 1794 | unsigned IOCTL_SIOCSBTPOLICY = SIOCSBTPOLICY; | ||
| 1795 | unsigned IOCTL_SIOCSBTPTYPE = SIOCSBTPTYPE; | ||
| 1796 | unsigned IOCTL_SIOCGBTSTATS = SIOCGBTSTATS; | ||
| 1797 | unsigned IOCTL_SIOCZBTSTATS = SIOCZBTSTATS; | ||
| 1798 | unsigned IOCTL_SIOCBTDUMP = SIOCBTDUMP; | ||
| 1799 | unsigned IOCTL_SIOCSBTSCOMTU = SIOCSBTSCOMTU; | ||
| 1800 | unsigned IOCTL_SIOCGBTFEAT = SIOCGBTFEAT; | ||
| 1801 | unsigned IOCTL_SIOCADNAT = SIOCADNAT; | ||
| 1802 | unsigned IOCTL_SIOCRMNAT = SIOCRMNAT; | ||
| 1803 | unsigned IOCTL_SIOCGNATS = SIOCGNATS; | ||
| 1804 | unsigned IOCTL_SIOCGNATL = SIOCGNATL; | ||
| 1805 | unsigned IOCTL_SIOCPURGENAT = SIOCPURGENAT; | ||
| 1806 | unsigned IOCTL_SIOCCONNECTX = SIOCCONNECTX; | ||
| 1807 | unsigned IOCTL_SIOCCONNECTXDEL = SIOCCONNECTXDEL; | ||
| 1808 | unsigned IOCTL_SIOCSIFINFO_FLAGS = SIOCSIFINFO_FLAGS; | ||
| 1809 | unsigned IOCTL_SIOCAADDRCTL_POLICY = SIOCAADDRCTL_POLICY; | ||
| 1810 | unsigned IOCTL_SIOCDADDRCTL_POLICY = SIOCDADDRCTL_POLICY; | ||
| 1811 | unsigned IOCTL_SMBIOC_OPENSESSION = SMBIOC_OPENSESSION; | ||
| 1812 | unsigned IOCTL_SMBIOC_OPENSHARE = SMBIOC_OPENSHARE; | ||
| 1813 | unsigned IOCTL_SMBIOC_REQUEST = SMBIOC_REQUEST; | ||
| 1814 | unsigned IOCTL_SMBIOC_SETFLAGS = SMBIOC_SETFLAGS; | ||
| 1815 | unsigned IOCTL_SMBIOC_LOOKUP = SMBIOC_LOOKUP; | ||
| 1816 | unsigned IOCTL_SMBIOC_READ = SMBIOC_READ; | ||
| 1817 | unsigned IOCTL_SMBIOC_WRITE = SMBIOC_WRITE; | ||
| 1818 | unsigned IOCTL_AGPIOC_INFO = AGPIOC_INFO; | ||
| 1819 | unsigned IOCTL_AGPIOC_ACQUIRE = AGPIOC_ACQUIRE; | ||
| 1820 | unsigned IOCTL_AGPIOC_RELEASE = AGPIOC_RELEASE; | ||
| 1821 | unsigned IOCTL_AGPIOC_SETUP = AGPIOC_SETUP; | ||
| 1822 | unsigned IOCTL_AGPIOC_ALLOCATE = AGPIOC_ALLOCATE; | ||
| 1823 | unsigned IOCTL_AGPIOC_DEALLOCATE = AGPIOC_DEALLOCATE; | ||
| 1824 | unsigned IOCTL_AGPIOC_BIND = AGPIOC_BIND; | ||
| 1825 | unsigned IOCTL_AGPIOC_UNBIND = AGPIOC_UNBIND; | ||
| 1826 | unsigned IOCTL_AUDIO_GETINFO = AUDIO_GETINFO; | ||
| 1827 | unsigned IOCTL_AUDIO_SETINFO = AUDIO_SETINFO; | ||
| 1828 | unsigned IOCTL_AUDIO_DRAIN = AUDIO_DRAIN; | ||
| 1829 | unsigned IOCTL_AUDIO_FLUSH = AUDIO_FLUSH; | ||
| 1830 | unsigned IOCTL_AUDIO_WSEEK = AUDIO_WSEEK; | ||
| 1831 | unsigned IOCTL_AUDIO_RERROR = AUDIO_RERROR; | ||
| 1832 | unsigned IOCTL_AUDIO_GETDEV = AUDIO_GETDEV; | ||
| 1833 | unsigned IOCTL_AUDIO_GETENC = AUDIO_GETENC; | ||
| 1834 | unsigned IOCTL_AUDIO_GETFD = AUDIO_GETFD; | ||
| 1835 | unsigned IOCTL_AUDIO_SETFD = AUDIO_SETFD; | ||
| 1836 | unsigned IOCTL_AUDIO_PERROR = AUDIO_PERROR; | ||
| 1837 | unsigned IOCTL_AUDIO_GETIOFFS = AUDIO_GETIOFFS; | ||
| 1838 | unsigned IOCTL_AUDIO_GETOOFFS = AUDIO_GETOOFFS; | ||
| 1839 | unsigned IOCTL_AUDIO_GETPROPS = AUDIO_GETPROPS; | ||
| 1840 | unsigned IOCTL_AUDIO_GETBUFINFO = AUDIO_GETBUFINFO; | ||
| 1841 | unsigned IOCTL_AUDIO_SETCHAN = AUDIO_SETCHAN; | ||
| 1842 | unsigned IOCTL_AUDIO_GETCHAN = AUDIO_GETCHAN; | ||
| 1843 | unsigned IOCTL_AUDIO_QUERYFORMAT = AUDIO_QUERYFORMAT; | ||
| 1844 | unsigned IOCTL_AUDIO_GETFORMAT = AUDIO_GETFORMAT; | ||
| 1845 | unsigned IOCTL_AUDIO_SETFORMAT = AUDIO_SETFORMAT; | ||
| 1846 | unsigned IOCTL_AUDIO_MIXER_READ = AUDIO_MIXER_READ; | ||
| 1847 | unsigned IOCTL_AUDIO_MIXER_WRITE = AUDIO_MIXER_WRITE; | ||
| 1848 | unsigned IOCTL_AUDIO_MIXER_DEVINFO = AUDIO_MIXER_DEVINFO; | ||
| 1849 | unsigned IOCTL_ATAIOCCOMMAND = ATAIOCCOMMAND; | ||
| 1850 | unsigned IOCTL_ATABUSIOSCAN = ATABUSIOSCAN; | ||
| 1851 | unsigned IOCTL_ATABUSIORESET = ATABUSIORESET; | ||
| 1852 | unsigned IOCTL_ATABUSIODETACH = ATABUSIODETACH; | ||
| 1853 | unsigned IOCTL_CDIOCPLAYTRACKS = CDIOCPLAYTRACKS; | ||
| 1854 | unsigned IOCTL_CDIOCPLAYBLOCKS = CDIOCPLAYBLOCKS; | ||
| 1855 | unsigned IOCTL_CDIOCREADSUBCHANNEL = CDIOCREADSUBCHANNEL; | ||
| 1856 | unsigned IOCTL_CDIOREADTOCHEADER = CDIOREADTOCHEADER; | ||
| 1857 | unsigned IOCTL_CDIOREADTOCENTRIES = CDIOREADTOCENTRIES; | ||
| 1858 | unsigned IOCTL_CDIOREADMSADDR = CDIOREADMSADDR; | ||
| 1859 | unsigned IOCTL_CDIOCSETPATCH = CDIOCSETPATCH; | ||
| 1860 | unsigned IOCTL_CDIOCGETVOL = CDIOCGETVOL; | ||
| 1861 | unsigned IOCTL_CDIOCSETVOL = CDIOCSETVOL; | ||
| 1862 | unsigned IOCTL_CDIOCSETMONO = CDIOCSETMONO; | ||
| 1863 | unsigned IOCTL_CDIOCSETSTEREO = CDIOCSETSTEREO; | ||
| 1864 | unsigned IOCTL_CDIOCSETMUTE = CDIOCSETMUTE; | ||
| 1865 | unsigned IOCTL_CDIOCSETLEFT = CDIOCSETLEFT; | ||
| 1866 | unsigned IOCTL_CDIOCSETRIGHT = CDIOCSETRIGHT; | ||
| 1867 | unsigned IOCTL_CDIOCSETDEBUG = CDIOCSETDEBUG; | ||
| 1868 | unsigned IOCTL_CDIOCCLRDEBUG = CDIOCCLRDEBUG; | ||
| 1869 | unsigned IOCTL_CDIOCPAUSE = CDIOCPAUSE; | ||
| 1870 | unsigned IOCTL_CDIOCRESUME = CDIOCRESUME; | ||
| 1871 | unsigned IOCTL_CDIOCRESET = CDIOCRESET; | ||
| 1872 | unsigned IOCTL_CDIOCSTART = CDIOCSTART; | ||
| 1873 | unsigned IOCTL_CDIOCSTOP = CDIOCSTOP; | ||
| 1874 | unsigned IOCTL_CDIOCEJECT = CDIOCEJECT; | ||
| 1875 | unsigned IOCTL_CDIOCALLOW = CDIOCALLOW; | ||
| 1876 | unsigned IOCTL_CDIOCPREVENT = CDIOCPREVENT; | ||
| 1877 | unsigned IOCTL_CDIOCCLOSE = CDIOCCLOSE; | ||
| 1878 | unsigned IOCTL_CDIOCPLAYMSF = CDIOCPLAYMSF; | ||
| 1879 | unsigned IOCTL_CDIOCLOADUNLOAD = CDIOCLOADUNLOAD; | ||
| 1880 | unsigned IOCTL_CHIOMOVE = CHIOMOVE; | ||
| 1881 | unsigned IOCTL_CHIOEXCHANGE = CHIOEXCHANGE; | ||
| 1882 | unsigned IOCTL_CHIOPOSITION = CHIOPOSITION; | ||
| 1883 | unsigned IOCTL_CHIOGPICKER = CHIOGPICKER; | ||
| 1884 | unsigned IOCTL_CHIOSPICKER = CHIOSPICKER; | ||
| 1885 | unsigned IOCTL_CHIOGPARAMS = CHIOGPARAMS; | ||
| 1886 | unsigned IOCTL_CHIOIELEM = CHIOIELEM; | ||
| 1887 | unsigned IOCTL_OCHIOGSTATUS = OCHIOGSTATUS; | ||
| 1888 | unsigned IOCTL_CHIOGSTATUS = CHIOGSTATUS; | ||
| 1889 | unsigned IOCTL_CHIOSVOLTAG = CHIOSVOLTAG; | ||
| 1890 | unsigned IOCTL_CLOCKCTL_SETTIMEOFDAY = CLOCKCTL_SETTIMEOFDAY; | ||
| 1891 | unsigned IOCTL_CLOCKCTL_ADJTIME = CLOCKCTL_ADJTIME; | ||
| 1892 | unsigned IOCTL_CLOCKCTL_CLOCK_SETTIME = CLOCKCTL_CLOCK_SETTIME; | ||
| 1893 | unsigned IOCTL_CLOCKCTL_NTP_ADJTIME = CLOCKCTL_NTP_ADJTIME; | ||
| 1894 | unsigned IOCTL_IOC_CPU_SETSTATE = IOC_CPU_SETSTATE; | ||
| 1895 | unsigned IOCTL_IOC_CPU_GETSTATE = IOC_CPU_GETSTATE; | ||
| 1896 | unsigned IOCTL_IOC_CPU_GETCOUNT = IOC_CPU_GETCOUNT; | ||
| 1897 | unsigned IOCTL_IOC_CPU_MAPID = IOC_CPU_MAPID; | ||
| 1898 | unsigned IOCTL_IOC_CPU_UCODE_GET_VERSION = IOC_CPU_UCODE_GET_VERSION; | ||
| 1899 | unsigned IOCTL_IOC_CPU_UCODE_APPLY = IOC_CPU_UCODE_APPLY; | ||
| 1900 | unsigned IOCTL_DIOCGDINFO = DIOCGDINFO; | ||
| 1901 | unsigned IOCTL_DIOCSDINFO = DIOCSDINFO; | ||
| 1902 | unsigned IOCTL_DIOCWDINFO = DIOCWDINFO; | ||
| 1903 | unsigned IOCTL_DIOCRFORMAT = DIOCRFORMAT; | ||
| 1904 | unsigned IOCTL_DIOCWFORMAT = DIOCWFORMAT; | ||
| 1905 | unsigned IOCTL_DIOCSSTEP = DIOCSSTEP; | ||
| 1906 | unsigned IOCTL_DIOCSRETRIES = DIOCSRETRIES; | ||
| 1907 | unsigned IOCTL_DIOCKLABEL = DIOCKLABEL; | ||
| 1908 | unsigned IOCTL_DIOCWLABEL = DIOCWLABEL; | ||
| 1909 | unsigned IOCTL_DIOCSBAD = DIOCSBAD; | ||
| 1910 | unsigned IOCTL_DIOCEJECT = DIOCEJECT; | ||
| 1911 | unsigned IOCTL_ODIOCEJECT = ODIOCEJECT; | ||
| 1912 | unsigned IOCTL_DIOCLOCK = DIOCLOCK; | ||
| 1913 | unsigned IOCTL_DIOCGDEFLABEL = DIOCGDEFLABEL; | ||
| 1914 | unsigned IOCTL_DIOCCLRLABEL = DIOCCLRLABEL; | ||
| 1915 | unsigned IOCTL_DIOCGCACHE = DIOCGCACHE; | ||
| 1916 | unsigned IOCTL_DIOCSCACHE = DIOCSCACHE; | ||
| 1917 | unsigned IOCTL_DIOCCACHESYNC = DIOCCACHESYNC; | ||
| 1918 | unsigned IOCTL_DIOCBSLIST = DIOCBSLIST; | ||
| 1919 | unsigned IOCTL_DIOCBSFLUSH = DIOCBSFLUSH; | ||
| 1920 | unsigned IOCTL_DIOCAWEDGE = DIOCAWEDGE; | ||
| 1921 | unsigned IOCTL_DIOCGWEDGEINFO = DIOCGWEDGEINFO; | ||
| 1922 | unsigned IOCTL_DIOCDWEDGE = DIOCDWEDGE; | ||
| 1923 | unsigned IOCTL_DIOCLWEDGES = DIOCLWEDGES; | ||
| 1924 | unsigned IOCTL_DIOCGSTRATEGY = DIOCGSTRATEGY; | ||
| 1925 | unsigned IOCTL_DIOCSSTRATEGY = DIOCSSTRATEGY; | ||
| 1926 | unsigned IOCTL_DIOCGDISKINFO = DIOCGDISKINFO; | ||
| 1927 | unsigned IOCTL_DIOCTUR = DIOCTUR; | ||
| 1928 | unsigned IOCTL_DIOCMWEDGES = DIOCMWEDGES; | ||
| 1929 | unsigned IOCTL_DIOCGSECTORSIZE = DIOCGSECTORSIZE; | ||
| 1930 | unsigned IOCTL_DIOCGMEDIASIZE = DIOCGMEDIASIZE; | ||
| 1931 | unsigned IOCTL_DIOCRMWEDGES = DIOCRMWEDGES; | ||
| 1932 | unsigned IOCTL_DRVDETACHDEV = DRVDETACHDEV; | ||
| 1933 | unsigned IOCTL_DRVRESCANBUS = DRVRESCANBUS; | ||
| 1934 | unsigned IOCTL_DRVCTLCOMMAND = DRVCTLCOMMAND; | ||
| 1935 | unsigned IOCTL_DRVRESUMEDEV = DRVRESUMEDEV; | ||
| 1936 | unsigned IOCTL_DRVLISTDEV = DRVLISTDEV; | ||
| 1937 | unsigned IOCTL_DRVGETEVENT = DRVGETEVENT; | ||
| 1938 | unsigned IOCTL_DRVSUSPENDDEV = DRVSUSPENDDEV; | ||
| 1939 | unsigned IOCTL_DVD_READ_STRUCT = DVD_READ_STRUCT; | ||
| 1940 | unsigned IOCTL_DVD_WRITE_STRUCT = DVD_WRITE_STRUCT; | ||
| 1941 | unsigned IOCTL_DVD_AUTH = DVD_AUTH; | ||
| 1942 | unsigned IOCTL_ENVSYS_GETDICTIONARY = ENVSYS_GETDICTIONARY; | ||
| 1943 | unsigned IOCTL_ENVSYS_SETDICTIONARY = ENVSYS_SETDICTIONARY; | ||
| 1944 | unsigned IOCTL_ENVSYS_REMOVEPROPS = ENVSYS_REMOVEPROPS; | ||
| 1945 | unsigned IOCTL_ENVSYS_GTREDATA = ENVSYS_GTREDATA; | ||
| 1946 | unsigned IOCTL_ENVSYS_GTREINFO = ENVSYS_GTREINFO; | ||
| 1947 | unsigned IOCTL_KFILTER_BYFILTER = KFILTER_BYFILTER; | ||
| 1948 | unsigned IOCTL_KFILTER_BYNAME = KFILTER_BYNAME; | ||
| 1949 | unsigned IOCTL_FDIOCGETOPTS = FDIOCGETOPTS; | ||
| 1950 | unsigned IOCTL_FDIOCSETOPTS = FDIOCSETOPTS; | ||
| 1951 | unsigned IOCTL_FDIOCSETFORMAT = FDIOCSETFORMAT; | ||
| 1952 | unsigned IOCTL_FDIOCGETFORMAT = FDIOCGETFORMAT; | ||
| 1953 | unsigned IOCTL_FDIOCFORMAT_TRACK = FDIOCFORMAT_TRACK; | ||
| 1954 | unsigned IOCTL_FIOCLEX = FIOCLEX; | ||
| 1955 | unsigned IOCTL_FIONCLEX = FIONCLEX; | ||
| 1956 | unsigned IOCTL_FIOSEEKDATA = FIOSEEKDATA; | ||
| 1957 | unsigned IOCTL_FIOSEEKHOLE = FIOSEEKHOLE; | ||
| 1958 | unsigned IOCTL_FIONREAD = FIONREAD; | ||
| 1959 | unsigned IOCTL_FIONBIO = FIONBIO; | ||
| 1960 | unsigned IOCTL_FIOASYNC = FIOASYNC; | ||
| 1961 | unsigned IOCTL_FIOSETOWN = FIOSETOWN; | ||
| 1962 | unsigned IOCTL_FIOGETOWN = FIOGETOWN; | ||
| 1963 | unsigned IOCTL_OFIOGETBMAP = OFIOGETBMAP; | ||
| 1964 | unsigned IOCTL_FIOGETBMAP = FIOGETBMAP; | ||
| 1965 | unsigned IOCTL_FIONWRITE = FIONWRITE; | ||
| 1966 | unsigned IOCTL_FIONSPACE = FIONSPACE; | ||
| 1967 | unsigned IOCTL_GPIOINFO = GPIOINFO; | ||
| 1968 | unsigned IOCTL_GPIOSET = GPIOSET; | ||
| 1969 | unsigned IOCTL_GPIOUNSET = GPIOUNSET; | ||
| 1970 | unsigned IOCTL_GPIOREAD = GPIOREAD; | ||
| 1971 | unsigned IOCTL_GPIOWRITE = GPIOWRITE; | ||
| 1972 | unsigned IOCTL_GPIOTOGGLE = GPIOTOGGLE; | ||
| 1973 | unsigned IOCTL_GPIOATTACH = GPIOATTACH; | ||
| 1974 | unsigned IOCTL_PTIOCNETBSD = PTIOCNETBSD; | ||
| 1975 | unsigned IOCTL_PTIOCSUNOS = PTIOCSUNOS; | ||
| 1976 | unsigned IOCTL_PTIOCLINUX = PTIOCLINUX; | ||
| 1977 | unsigned IOCTL_PTIOCFREEBSD = PTIOCFREEBSD; | ||
| 1978 | unsigned IOCTL_PTIOCULTRIX = PTIOCULTRIX; | ||
| 1979 | unsigned IOCTL_TIOCHPCL = TIOCHPCL; | ||
| 1980 | unsigned IOCTL_TIOCGETP = TIOCGETP; | ||
| 1981 | unsigned IOCTL_TIOCSETP = TIOCSETP; | ||
| 1982 | unsigned IOCTL_TIOCSETN = TIOCSETN; | ||
| 1983 | unsigned IOCTL_TIOCSETC = TIOCSETC; | ||
| 1984 | unsigned IOCTL_TIOCGETC = TIOCGETC; | ||
| 1985 | unsigned IOCTL_TIOCLBIS = TIOCLBIS; | ||
| 1986 | unsigned IOCTL_TIOCLBIC = TIOCLBIC; | ||
| 1987 | unsigned IOCTL_TIOCLSET = TIOCLSET; | ||
| 1988 | unsigned IOCTL_TIOCLGET = TIOCLGET; | ||
| 1989 | unsigned IOCTL_TIOCSLTC = TIOCSLTC; | ||
| 1990 | unsigned IOCTL_TIOCGLTC = TIOCGLTC; | ||
| 1991 | unsigned IOCTL_OTIOCCONS = OTIOCCONS; | ||
| 1992 | unsigned IOCTL_JOY_SETTIMEOUT = JOY_SETTIMEOUT; | ||
| 1993 | unsigned IOCTL_JOY_GETTIMEOUT = JOY_GETTIMEOUT; | ||
| 1994 | unsigned IOCTL_JOY_SET_X_OFFSET = JOY_SET_X_OFFSET; | ||
| 1995 | unsigned IOCTL_JOY_SET_Y_OFFSET = JOY_SET_Y_OFFSET; | ||
| 1996 | unsigned IOCTL_JOY_GET_X_OFFSET = JOY_GET_X_OFFSET; | ||
| 1997 | unsigned IOCTL_JOY_GET_Y_OFFSET = JOY_GET_Y_OFFSET; | ||
| 1998 | unsigned IOCTL_OKIOCGSYMBOL = OKIOCGSYMBOL; | ||
| 1999 | unsigned IOCTL_OKIOCGVALUE = OKIOCGVALUE; | ||
| 2000 | unsigned IOCTL_KIOCGSIZE = KIOCGSIZE; | ||
| 2001 | unsigned IOCTL_KIOCGVALUE = KIOCGVALUE; | ||
| 2002 | unsigned IOCTL_KIOCGSYMBOL = KIOCGSYMBOL; | ||
| 2003 | unsigned IOCTL_LUAINFO = LUAINFO; | ||
| 2004 | unsigned IOCTL_LUACREATE = LUACREATE; | ||
| 2005 | unsigned IOCTL_LUADESTROY = LUADESTROY; | ||
| 2006 | unsigned IOCTL_LUAREQUIRE = LUAREQUIRE; | ||
| 2007 | unsigned IOCTL_LUALOAD = LUALOAD; | ||
| 2008 | unsigned IOCTL_MIDI_PRETIME = MIDI_PRETIME; | ||
| 2009 | unsigned IOCTL_MIDI_MPUMODE = MIDI_MPUMODE; | ||
| 2010 | unsigned IOCTL_MIDI_MPUCMD = MIDI_MPUCMD; | ||
| 2011 | unsigned IOCTL_SEQUENCER_RESET = SEQUENCER_RESET; | ||
| 2012 | unsigned IOCTL_SEQUENCER_SYNC = SEQUENCER_SYNC; | ||
| 2013 | unsigned IOCTL_SEQUENCER_INFO = SEQUENCER_INFO; | ||
| 2014 | unsigned IOCTL_SEQUENCER_CTRLRATE = SEQUENCER_CTRLRATE; | ||
| 2015 | unsigned IOCTL_SEQUENCER_GETOUTCOUNT = SEQUENCER_GETOUTCOUNT; | ||
| 2016 | unsigned IOCTL_SEQUENCER_GETINCOUNT = SEQUENCER_GETINCOUNT; | ||
| 2017 | unsigned IOCTL_SEQUENCER_RESETSAMPLES = SEQUENCER_RESETSAMPLES; | ||
| 2018 | unsigned IOCTL_SEQUENCER_NRSYNTHS = SEQUENCER_NRSYNTHS; | ||
| 2019 | unsigned IOCTL_SEQUENCER_NRMIDIS = SEQUENCER_NRMIDIS; | ||
| 2020 | unsigned IOCTL_SEQUENCER_THRESHOLD = SEQUENCER_THRESHOLD; | ||
| 2021 | unsigned IOCTL_SEQUENCER_MEMAVL = SEQUENCER_MEMAVL; | ||
| 2022 | unsigned IOCTL_SEQUENCER_PANIC = SEQUENCER_PANIC; | ||
| 2023 | unsigned IOCTL_SEQUENCER_OUTOFBAND = SEQUENCER_OUTOFBAND; | ||
| 2024 | unsigned IOCTL_SEQUENCER_GETTIME = SEQUENCER_GETTIME; | ||
| 2025 | unsigned IOCTL_SEQUENCER_TMR_TIMEBASE = SEQUENCER_TMR_TIMEBASE; | ||
| 2026 | unsigned IOCTL_SEQUENCER_TMR_START = SEQUENCER_TMR_START; | ||
| 2027 | unsigned IOCTL_SEQUENCER_TMR_STOP = SEQUENCER_TMR_STOP; | ||
| 2028 | unsigned IOCTL_SEQUENCER_TMR_CONTINUE = SEQUENCER_TMR_CONTINUE; | ||
| 2029 | unsigned IOCTL_SEQUENCER_TMR_TEMPO = SEQUENCER_TMR_TEMPO; | ||
| 2030 | unsigned IOCTL_SEQUENCER_TMR_SOURCE = SEQUENCER_TMR_SOURCE; | ||
| 2031 | unsigned IOCTL_SEQUENCER_TMR_METRONOME = SEQUENCER_TMR_METRONOME; | ||
| 2032 | unsigned IOCTL_SEQUENCER_TMR_SELECT = SEQUENCER_TMR_SELECT; | ||
| 2033 | unsigned IOCTL_MTIOCTOP = MTIOCTOP; | ||
| 2034 | unsigned IOCTL_MTIOCGET = MTIOCGET; | ||
| 2035 | unsigned IOCTL_MTIOCIEOT = MTIOCIEOT; | ||
| 2036 | unsigned IOCTL_MTIOCEEOT = MTIOCEEOT; | ||
| 2037 | unsigned IOCTL_MTIOCRDSPOS = MTIOCRDSPOS; | ||
| 2038 | unsigned IOCTL_MTIOCRDHPOS = MTIOCRDHPOS; | ||
| 2039 | unsigned IOCTL_MTIOCSLOCATE = MTIOCSLOCATE; | ||
| 2040 | unsigned IOCTL_MTIOCHLOCATE = MTIOCHLOCATE; | ||
| 2041 | unsigned IOCTL_POWER_EVENT_RECVDICT = POWER_EVENT_RECVDICT; | ||
| 2042 | unsigned IOCTL_POWER_IOC_GET_TYPE = POWER_IOC_GET_TYPE; | ||
| 2043 | unsigned IOCTL_RIOCGINFO = RIOCGINFO; | ||
| 2044 | unsigned IOCTL_RIOCSINFO = RIOCSINFO; | ||
| 2045 | unsigned IOCTL_RIOCSSRCH = RIOCSSRCH; | ||
| 2046 | unsigned IOCTL_RNDGETENTCNT = RNDGETENTCNT; | ||
| 2047 | unsigned IOCTL_RNDGETSRCNUM = RNDGETSRCNUM; | ||
| 2048 | unsigned IOCTL_RNDGETSRCNAME = RNDGETSRCNAME; | ||
| 2049 | unsigned IOCTL_RNDCTL = RNDCTL; | ||
| 2050 | unsigned IOCTL_RNDADDDATA = RNDADDDATA; | ||
| 2051 | unsigned IOCTL_RNDGETPOOLSTAT = RNDGETPOOLSTAT; | ||
| 2052 | unsigned IOCTL_RNDGETESTNUM = RNDGETESTNUM; | ||
| 2053 | unsigned IOCTL_RNDGETESTNAME = RNDGETESTNAME; | ||
| 2054 | unsigned IOCTL_SCIOCGET = SCIOCGET; | ||
| 2055 | unsigned IOCTL_SCIOCSET = SCIOCSET; | ||
| 2056 | unsigned IOCTL_SCIOCRESTART = SCIOCRESTART; | ||
| 2057 | unsigned IOCTL_SCIOC_USE_ADF = SCIOC_USE_ADF; | ||
| 2058 | unsigned IOCTL_SCIOCCOMMAND = SCIOCCOMMAND; | ||
| 2059 | unsigned IOCTL_SCIOCDEBUG = SCIOCDEBUG; | ||
| 2060 | unsigned IOCTL_SCIOCIDENTIFY = SCIOCIDENTIFY; | ||
| 2061 | unsigned IOCTL_OSCIOCIDENTIFY = OSCIOCIDENTIFY; | ||
| 2062 | unsigned IOCTL_SCIOCDECONFIG = SCIOCDECONFIG; | ||
| 2063 | unsigned IOCTL_SCIOCRECONFIG = SCIOCRECONFIG; | ||
| 2064 | unsigned IOCTL_SCIOCRESET = SCIOCRESET; | ||
| 2065 | unsigned IOCTL_SCBUSIOSCAN = SCBUSIOSCAN; | ||
| 2066 | unsigned IOCTL_SCBUSIORESET = SCBUSIORESET; | ||
| 2067 | unsigned IOCTL_SCBUSIODETACH = SCBUSIODETACH; | ||
| 2068 | unsigned IOCTL_SCBUSACCEL = SCBUSACCEL; | ||
| 2069 | unsigned IOCTL_SCBUSIOLLSCAN = SCBUSIOLLSCAN; | ||
| 2070 | unsigned IOCTL_SIOCSHIWAT = SIOCSHIWAT; | ||
| 2071 | unsigned IOCTL_SIOCGHIWAT = SIOCGHIWAT; | ||
| 2072 | unsigned IOCTL_SIOCSLOWAT = SIOCSLOWAT; | ||
| 2073 | unsigned IOCTL_SIOCGLOWAT = SIOCGLOWAT; | ||
| 2074 | unsigned IOCTL_SIOCATMARK = SIOCATMARK; | ||
| 2075 | unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; | ||
| 2076 | unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; | ||
| 2077 | unsigned IOCTL_SIOCPEELOFF = SIOCPEELOFF; | ||
| 2078 | unsigned IOCTL_SIOCADDRT = SIOCADDRT; | ||
| 2079 | unsigned IOCTL_SIOCDELRT = SIOCDELRT; | ||
| 2080 | unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; | ||
| 2081 | unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; | ||
| 2082 | unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; | ||
| 2083 | unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; | ||
| 2084 | unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; | ||
| 2085 | unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; | ||
| 2086 | unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; | ||
| 2087 | unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; | ||
| 2088 | unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; | ||
| 2089 | unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; | ||
| 2090 | unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; | ||
| 2091 | unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; | ||
| 2092 | unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; | ||
| 2093 | unsigned IOCTL_SIOCDIFADDR = SIOCDIFADDR; | ||
| 2094 | unsigned IOCTL_SIOCAIFADDR = SIOCAIFADDR; | ||
| 2095 | unsigned IOCTL_SIOCGIFALIAS = SIOCGIFALIAS; | ||
| 2096 | unsigned IOCTL_SIOCGIFAFLAG_IN = SIOCGIFAFLAG_IN; | ||
| 2097 | unsigned IOCTL_SIOCALIFADDR = SIOCALIFADDR; | ||
| 2098 | unsigned IOCTL_SIOCGLIFADDR = SIOCGLIFADDR; | ||
| 2099 | unsigned IOCTL_SIOCDLIFADDR = SIOCDLIFADDR; | ||
| 2100 | unsigned IOCTL_SIOCSIFADDRPREF = SIOCSIFADDRPREF; | ||
| 2101 | unsigned IOCTL_SIOCGIFADDRPREF = SIOCGIFADDRPREF; | ||
| 2102 | unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; | ||
| 2103 | unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; | ||
| 2104 | unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; | ||
| 2105 | unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; | ||
| 2106 | unsigned IOCTL_SIOCSIFMEDIA = SIOCSIFMEDIA; | ||
| 2107 | unsigned IOCTL_SIOCGIFMEDIA = SIOCGIFMEDIA; | ||
| 2108 | unsigned IOCTL_SIOCSIFGENERIC = SIOCSIFGENERIC; | ||
| 2109 | unsigned IOCTL_SIOCGIFGENERIC = SIOCGIFGENERIC; | ||
| 2110 | unsigned IOCTL_SIOCSIFPHYADDR = SIOCSIFPHYADDR; | ||
| 2111 | unsigned IOCTL_SIOCGIFPSRCADDR = SIOCGIFPSRCADDR; | ||
| 2112 | unsigned IOCTL_SIOCGIFPDSTADDR = SIOCGIFPDSTADDR; | ||
| 2113 | unsigned IOCTL_SIOCDIFPHYADDR = SIOCDIFPHYADDR; | ||
| 2114 | unsigned IOCTL_SIOCSLIFPHYADDR = SIOCSLIFPHYADDR; | ||
| 2115 | unsigned IOCTL_SIOCGLIFPHYADDR = SIOCGLIFPHYADDR; | ||
| 2116 | unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; | ||
| 2117 | unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; | ||
| 2118 | unsigned IOCTL_SIOCSDRVSPEC = SIOCSDRVSPEC; | ||
| 2119 | unsigned IOCTL_SIOCGDRVSPEC = SIOCGDRVSPEC; | ||
| 2120 | unsigned IOCTL_SIOCIFCREATE = SIOCIFCREATE; | ||
| 2121 | unsigned IOCTL_SIOCIFDESTROY = SIOCIFDESTROY; | ||
| 2122 | unsigned IOCTL_SIOCIFGCLONERS = SIOCIFGCLONERS; | ||
| 2123 | unsigned IOCTL_SIOCGIFDLT = SIOCGIFDLT; | ||
| 2124 | unsigned IOCTL_SIOCGIFCAP = SIOCGIFCAP; | ||
| 2125 | unsigned IOCTL_SIOCSIFCAP = SIOCSIFCAP; | ||
| 2126 | unsigned IOCTL_SIOCSVH = SIOCSVH; | ||
| 2127 | unsigned IOCTL_SIOCGVH = SIOCGVH; | ||
| 2128 | unsigned IOCTL_SIOCINITIFADDR = SIOCINITIFADDR; | ||
| 2129 | unsigned IOCTL_SIOCGIFDATA = SIOCGIFDATA; | ||
| 2130 | unsigned IOCTL_SIOCZIFDATA = SIOCZIFDATA; | ||
| 2131 | unsigned IOCTL_SIOCGLINKSTR = SIOCGLINKSTR; | ||
| 2132 | unsigned IOCTL_SIOCSLINKSTR = SIOCSLINKSTR; | ||
| 2133 | unsigned IOCTL_SIOCGETHERCAP = SIOCGETHERCAP; | ||
| 2134 | unsigned IOCTL_SIOCGIFINDEX = SIOCGIFINDEX; | ||
| 2135 | unsigned IOCTL_SIOCSETHERCAP = SIOCSETHERCAP; | ||
| 2136 | unsigned IOCTL_SIOCSIFDESCR = SIOCSIFDESCR; | ||
| 2137 | unsigned IOCTL_SIOCGIFDESCR = SIOCGIFDESCR; | ||
| 2138 | unsigned IOCTL_SIOCGUMBINFO = SIOCGUMBINFO; | ||
| 2139 | unsigned IOCTL_SIOCSUMBPARAM = SIOCSUMBPARAM; | ||
| 2140 | unsigned IOCTL_SIOCGUMBPARAM = SIOCGUMBPARAM; | ||
| 2141 | unsigned IOCTL_SIOCSETPFSYNC = SIOCSETPFSYNC; | ||
| 2142 | unsigned IOCTL_SIOCGETPFSYNC = SIOCGETPFSYNC; | ||
| 2143 | unsigned IOCTL_PPS_IOC_CREATE = PPS_IOC_CREATE; | ||
| 2144 | unsigned IOCTL_PPS_IOC_DESTROY = PPS_IOC_DESTROY; | ||
| 2145 | unsigned IOCTL_PPS_IOC_SETPARAMS = PPS_IOC_SETPARAMS; | ||
| 2146 | unsigned IOCTL_PPS_IOC_GETPARAMS = PPS_IOC_GETPARAMS; | ||
| 2147 | unsigned IOCTL_PPS_IOC_GETCAP = PPS_IOC_GETCAP; | ||
| 2148 | unsigned IOCTL_PPS_IOC_FETCH = PPS_IOC_FETCH; | ||
| 2149 | unsigned IOCTL_PPS_IOC_KCBIND = PPS_IOC_KCBIND; | ||
| 2150 | unsigned IOCTL_TIOCEXCL = TIOCEXCL; | ||
| 2151 | unsigned IOCTL_TIOCNXCL = TIOCNXCL; | ||
| 2152 | unsigned IOCTL_TIOCFLUSH = TIOCFLUSH; | ||
| 2153 | unsigned IOCTL_TIOCGETA = TIOCGETA; | ||
| 2154 | unsigned IOCTL_TIOCSETA = TIOCSETA; | ||
| 2155 | unsigned IOCTL_TIOCSETAW = TIOCSETAW; | ||
| 2156 | unsigned IOCTL_TIOCSETAF = TIOCSETAF; | ||
| 2157 | unsigned IOCTL_TIOCGETD = TIOCGETD; | ||
| 2158 | unsigned IOCTL_TIOCSETD = TIOCSETD; | ||
| 2159 | unsigned IOCTL_TIOCGLINED = TIOCGLINED; | ||
| 2160 | unsigned IOCTL_TIOCSLINED = TIOCSLINED; | ||
| 2161 | unsigned IOCTL_TIOCSBRK = TIOCSBRK; | ||
| 2162 | unsigned IOCTL_TIOCCBRK = TIOCCBRK; | ||
| 2163 | unsigned IOCTL_TIOCSDTR = TIOCSDTR; | ||
| 2164 | unsigned IOCTL_TIOCCDTR = TIOCCDTR; | ||
| 2165 | unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; | ||
| 2166 | unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; | ||
| 2167 | unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; | ||
| 2168 | unsigned IOCTL_TIOCSTI = TIOCSTI; | ||
| 2169 | unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; | ||
| 2170 | unsigned IOCTL_TIOCPKT = TIOCPKT; | ||
| 2171 | unsigned IOCTL_TIOCSTOP = TIOCSTOP; | ||
| 2172 | unsigned IOCTL_TIOCSTART = TIOCSTART; | ||
| 2173 | unsigned IOCTL_TIOCMSET = TIOCMSET; | ||
| 2174 | unsigned IOCTL_TIOCMBIS = TIOCMBIS; | ||
| 2175 | unsigned IOCTL_TIOCMBIC = TIOCMBIC; | ||
| 2176 | unsigned IOCTL_TIOCMGET = TIOCMGET; | ||
| 2177 | unsigned IOCTL_TIOCREMOTE = TIOCREMOTE; | ||
| 2178 | unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; | ||
| 2179 | unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; | ||
| 2180 | unsigned IOCTL_TIOCUCNTL = TIOCUCNTL; | ||
| 2181 | unsigned IOCTL_TIOCSTAT = TIOCSTAT; | ||
| 2182 | unsigned IOCTL_TIOCGSID = TIOCGSID; | ||
| 2183 | unsigned IOCTL_TIOCCONS = TIOCCONS; | ||
| 2184 | unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; | ||
| 2185 | unsigned IOCTL_TIOCEXT = TIOCEXT; | ||
| 2186 | unsigned IOCTL_TIOCSIG = TIOCSIG; | ||
| 2187 | unsigned IOCTL_TIOCDRAIN = TIOCDRAIN; | ||
| 2188 | unsigned IOCTL_TIOCGFLAGS = TIOCGFLAGS; | ||
| 2189 | unsigned IOCTL_TIOCSFLAGS = TIOCSFLAGS; | ||
| 2190 | unsigned IOCTL_TIOCDCDTIMESTAMP = TIOCDCDTIMESTAMP; | ||
| 2191 | unsigned IOCTL_TIOCRCVFRAME = TIOCRCVFRAME; | ||
| 2192 | unsigned IOCTL_TIOCXMTFRAME = TIOCXMTFRAME; | ||
| 2193 | unsigned IOCTL_TIOCPTMGET = TIOCPTMGET; | ||
| 2194 | unsigned IOCTL_TIOCGRANTPT = TIOCGRANTPT; | ||
| 2195 | unsigned IOCTL_TIOCPTSNAME = TIOCPTSNAME; | ||
| 2196 | unsigned IOCTL_TIOCSQSIZE = TIOCSQSIZE; | ||
| 2197 | unsigned IOCTL_TIOCGQSIZE = TIOCGQSIZE; | ||
| 2198 | unsigned IOCTL_VERIEXEC_LOAD = VERIEXEC_LOAD; | ||
| 2199 | unsigned IOCTL_VERIEXEC_TABLESIZE = VERIEXEC_TABLESIZE; | ||
| 2200 | unsigned IOCTL_VERIEXEC_DELETE = VERIEXEC_DELETE; | ||
| 2201 | unsigned IOCTL_VERIEXEC_QUERY = VERIEXEC_QUERY; | ||
| 2202 | unsigned IOCTL_VERIEXEC_DUMP = VERIEXEC_DUMP; | ||
| 2203 | unsigned IOCTL_VERIEXEC_FLUSH = VERIEXEC_FLUSH; | ||
| 2204 | unsigned IOCTL_VIDIOC_QUERYCAP = VIDIOC_QUERYCAP; | ||
| 2205 | unsigned IOCTL_VIDIOC_RESERVED = VIDIOC_RESERVED; | ||
| 2206 | unsigned IOCTL_VIDIOC_ENUM_FMT = VIDIOC_ENUM_FMT; | ||
| 2207 | unsigned IOCTL_VIDIOC_G_FMT = VIDIOC_G_FMT; | ||
| 2208 | unsigned IOCTL_VIDIOC_S_FMT = VIDIOC_S_FMT; | ||
| 2209 | unsigned IOCTL_VIDIOC_REQBUFS = VIDIOC_REQBUFS; | ||
| 2210 | unsigned IOCTL_VIDIOC_QUERYBUF = VIDIOC_QUERYBUF; | ||
| 2211 | unsigned IOCTL_VIDIOC_G_FBUF = VIDIOC_G_FBUF; | ||
| 2212 | unsigned IOCTL_VIDIOC_S_FBUF = VIDIOC_S_FBUF; | ||
| 2213 | unsigned IOCTL_VIDIOC_OVERLAY = VIDIOC_OVERLAY; | ||
| 2214 | unsigned IOCTL_VIDIOC_QBUF = VIDIOC_QBUF; | ||
| 2215 | unsigned IOCTL_VIDIOC_DQBUF = VIDIOC_DQBUF; | ||
| 2216 | unsigned IOCTL_VIDIOC_STREAMON = VIDIOC_STREAMON; | ||
| 2217 | unsigned IOCTL_VIDIOC_STREAMOFF = VIDIOC_STREAMOFF; | ||
| 2218 | unsigned IOCTL_VIDIOC_G_PARM = VIDIOC_G_PARM; | ||
| 2219 | unsigned IOCTL_VIDIOC_S_PARM = VIDIOC_S_PARM; | ||
| 2220 | unsigned IOCTL_VIDIOC_G_STD = VIDIOC_G_STD; | ||
| 2221 | unsigned IOCTL_VIDIOC_S_STD = VIDIOC_S_STD; | ||
| 2222 | unsigned IOCTL_VIDIOC_ENUMSTD = VIDIOC_ENUMSTD; | ||
| 2223 | unsigned IOCTL_VIDIOC_ENUMINPUT = VIDIOC_ENUMINPUT; | ||
| 2224 | unsigned IOCTL_VIDIOC_G_CTRL = VIDIOC_G_CTRL; | ||
| 2225 | unsigned IOCTL_VIDIOC_S_CTRL = VIDIOC_S_CTRL; | ||
| 2226 | unsigned IOCTL_VIDIOC_G_TUNER = VIDIOC_G_TUNER; | ||
| 2227 | unsigned IOCTL_VIDIOC_S_TUNER = VIDIOC_S_TUNER; | ||
| 2228 | unsigned IOCTL_VIDIOC_G_AUDIO = VIDIOC_G_AUDIO; | ||
| 2229 | unsigned IOCTL_VIDIOC_S_AUDIO = VIDIOC_S_AUDIO; | ||
| 2230 | unsigned IOCTL_VIDIOC_QUERYCTRL = VIDIOC_QUERYCTRL; | ||
| 2231 | unsigned IOCTL_VIDIOC_QUERYMENU = VIDIOC_QUERYMENU; | ||
| 2232 | unsigned IOCTL_VIDIOC_G_INPUT = VIDIOC_G_INPUT; | ||
| 2233 | unsigned IOCTL_VIDIOC_S_INPUT = VIDIOC_S_INPUT; | ||
| 2234 | unsigned IOCTL_VIDIOC_G_OUTPUT = VIDIOC_G_OUTPUT; | ||
| 2235 | unsigned IOCTL_VIDIOC_S_OUTPUT = VIDIOC_S_OUTPUT; | ||
| 2236 | unsigned IOCTL_VIDIOC_ENUMOUTPUT = VIDIOC_ENUMOUTPUT; | ||
| 2237 | unsigned IOCTL_VIDIOC_G_AUDOUT = VIDIOC_G_AUDOUT; | ||
| 2238 | unsigned IOCTL_VIDIOC_S_AUDOUT = VIDIOC_S_AUDOUT; | ||
| 2239 | unsigned IOCTL_VIDIOC_G_MODULATOR = VIDIOC_G_MODULATOR; | ||
| 2240 | unsigned IOCTL_VIDIOC_S_MODULATOR = VIDIOC_S_MODULATOR; | ||
| 2241 | unsigned IOCTL_VIDIOC_G_FREQUENCY = VIDIOC_G_FREQUENCY; | ||
| 2242 | unsigned IOCTL_VIDIOC_S_FREQUENCY = VIDIOC_S_FREQUENCY; | ||
| 2243 | unsigned IOCTL_VIDIOC_CROPCAP = VIDIOC_CROPCAP; | ||
| 2244 | unsigned IOCTL_VIDIOC_G_CROP = VIDIOC_G_CROP; | ||
| 2245 | unsigned IOCTL_VIDIOC_S_CROP = VIDIOC_S_CROP; | ||
| 2246 | unsigned IOCTL_VIDIOC_G_JPEGCOMP = VIDIOC_G_JPEGCOMP; | ||
| 2247 | unsigned IOCTL_VIDIOC_S_JPEGCOMP = VIDIOC_S_JPEGCOMP; | ||
| 2248 | unsigned IOCTL_VIDIOC_QUERYSTD = VIDIOC_QUERYSTD; | ||
| 2249 | unsigned IOCTL_VIDIOC_TRY_FMT = VIDIOC_TRY_FMT; | ||
| 2250 | unsigned IOCTL_VIDIOC_ENUMAUDIO = VIDIOC_ENUMAUDIO; | ||
| 2251 | unsigned IOCTL_VIDIOC_ENUMAUDOUT = VIDIOC_ENUMAUDOUT; | ||
| 2252 | unsigned IOCTL_VIDIOC_G_PRIORITY = VIDIOC_G_PRIORITY; | ||
| 2253 | unsigned IOCTL_VIDIOC_S_PRIORITY = VIDIOC_S_PRIORITY; | ||
| 2254 | unsigned IOCTL_VIDIOC_ENUM_FRAMESIZES = VIDIOC_ENUM_FRAMESIZES; | ||
| 2255 | unsigned IOCTL_VIDIOC_ENUM_FRAMEINTERVALS = VIDIOC_ENUM_FRAMEINTERVALS; | ||
| 2256 | unsigned IOCTL_WDOGIOC_GMODE = WDOGIOC_GMODE; | ||
| 2257 | unsigned IOCTL_WDOGIOC_SMODE = WDOGIOC_SMODE; | ||
| 2258 | unsigned IOCTL_WDOGIOC_WHICH = WDOGIOC_WHICH; | ||
| 2259 | unsigned IOCTL_WDOGIOC_TICKLE = WDOGIOC_TICKLE; | ||
| 2260 | unsigned IOCTL_WDOGIOC_GTICKLER = WDOGIOC_GTICKLER; | ||
| 2261 | unsigned IOCTL_WDOGIOC_GWDOGS = WDOGIOC_GWDOGS; | ||
| 2262 | unsigned IOCTL_KCOV_IOC_SETBUFSIZE = KCOV_IOC_SETBUFSIZE; | ||
| 2263 | unsigned IOCTL_KCOV_IOC_ENABLE = KCOV_IOC_ENABLE; | ||
| 2264 | unsigned IOCTL_KCOV_IOC_DISABLE = KCOV_IOC_DISABLE; | ||
| 2265 | unsigned IOCTL_IPMICTL_RECEIVE_MSG_TRUNC = IPMICTL_RECEIVE_MSG_TRUNC; | ||
| 2266 | unsigned IOCTL_IPMICTL_RECEIVE_MSG = IPMICTL_RECEIVE_MSG; | ||
| 2267 | unsigned IOCTL_IPMICTL_SEND_COMMAND = IPMICTL_SEND_COMMAND; | ||
| 2268 | unsigned IOCTL_IPMICTL_REGISTER_FOR_CMD = IPMICTL_REGISTER_FOR_CMD; | ||
| 2269 | unsigned IOCTL_IPMICTL_UNREGISTER_FOR_CMD = IPMICTL_UNREGISTER_FOR_CMD; | ||
| 2270 | unsigned IOCTL_IPMICTL_SET_GETS_EVENTS_CMD = IPMICTL_SET_GETS_EVENTS_CMD; | ||
| 2271 | unsigned IOCTL_IPMICTL_SET_MY_ADDRESS_CMD = IPMICTL_SET_MY_ADDRESS_CMD; | ||
| 2272 | unsigned IOCTL_IPMICTL_GET_MY_ADDRESS_CMD = IPMICTL_GET_MY_ADDRESS_CMD; | ||
| 2273 | unsigned IOCTL_IPMICTL_SET_MY_LUN_CMD = IPMICTL_SET_MY_LUN_CMD; | ||
| 2274 | unsigned IOCTL_IPMICTL_GET_MY_LUN_CMD = IPMICTL_GET_MY_LUN_CMD; | ||
| 2275 | unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; | ||
| 2276 | unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; | ||
| 2277 | unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; | ||
| 2278 | unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE; | ||
| 2279 | unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; | ||
| 2280 | unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; | ||
| 2281 | unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; | ||
| 2282 | unsigned IOCTL_SOUND_PCM_READ_BITS = SOUND_PCM_READ_BITS; | ||
| 2283 | unsigned IOCTL_SNDCTL_DSP_CHANNELS = SNDCTL_DSP_CHANNELS; | ||
| 2284 | unsigned IOCTL_SOUND_PCM_READ_CHANNELS = SOUND_PCM_READ_CHANNELS; | ||
| 2285 | unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER; | ||
| 2286 | unsigned IOCTL_SOUND_PCM_READ_FILTER = SOUND_PCM_READ_FILTER; | ||
| 2287 | unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; | ||
| 2288 | unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; | ||
| 2289 | unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; | ||
| 2290 | unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; | ||
| 2291 | unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE; | ||
| 2292 | unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; | ||
| 2293 | unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; | ||
| 2294 | unsigned IOCTL_SNDCTL_DSP_GETCAPS = SNDCTL_DSP_GETCAPS; | ||
| 2295 | unsigned IOCTL_SNDCTL_DSP_GETTRIGGER = SNDCTL_DSP_GETTRIGGER; | ||
| 2296 | unsigned IOCTL_SNDCTL_DSP_SETTRIGGER = SNDCTL_DSP_SETTRIGGER; | ||
| 2297 | unsigned IOCTL_SNDCTL_DSP_GETIPTR = SNDCTL_DSP_GETIPTR; | ||
| 2298 | unsigned IOCTL_SNDCTL_DSP_GETOPTR = SNDCTL_DSP_GETOPTR; | ||
| 2299 | unsigned IOCTL_SNDCTL_DSP_MAPINBUF = SNDCTL_DSP_MAPINBUF; | ||
| 2300 | unsigned IOCTL_SNDCTL_DSP_MAPOUTBUF = SNDCTL_DSP_MAPOUTBUF; | ||
| 2301 | unsigned IOCTL_SNDCTL_DSP_SETSYNCRO = SNDCTL_DSP_SETSYNCRO; | ||
| 2302 | unsigned IOCTL_SNDCTL_DSP_SETDUPLEX = SNDCTL_DSP_SETDUPLEX; | ||
| 2303 | unsigned IOCTL_SNDCTL_DSP_PROFILE = SNDCTL_DSP_PROFILE; | ||
| 2304 | unsigned IOCTL_SNDCTL_DSP_GETODELAY = SNDCTL_DSP_GETODELAY; | ||
| 2305 | unsigned IOCTL_SOUND_MIXER_INFO = SOUND_MIXER_INFO; | ||
| 2306 | unsigned IOCTL_SOUND_OLD_MIXER_INFO = SOUND_OLD_MIXER_INFO; | ||
| 2307 | unsigned IOCTL_OSS_GETVERSION = OSS_GETVERSION; | ||
| 2308 | unsigned IOCTL_SNDCTL_SYSINFO = SNDCTL_SYSINFO; | ||
| 2309 | unsigned IOCTL_SNDCTL_AUDIOINFO = SNDCTL_AUDIOINFO; | ||
| 2310 | unsigned IOCTL_SNDCTL_ENGINEINFO = SNDCTL_ENGINEINFO; | ||
| 2311 | unsigned IOCTL_SNDCTL_DSP_GETPLAYVOL = SNDCTL_DSP_GETPLAYVOL; | ||
| 2312 | unsigned IOCTL_SNDCTL_DSP_SETPLAYVOL = SNDCTL_DSP_SETPLAYVOL; | ||
| 2313 | unsigned IOCTL_SNDCTL_DSP_GETRECVOL = SNDCTL_DSP_GETRECVOL; | ||
| 2314 | unsigned IOCTL_SNDCTL_DSP_SETRECVOL = SNDCTL_DSP_SETRECVOL; | ||
| 2315 | unsigned IOCTL_SNDCTL_DSP_SKIP = SNDCTL_DSP_SKIP; | ||
| 2316 | unsigned IOCTL_SNDCTL_DSP_SILENCE = SNDCTL_DSP_SILENCE; | ||
| 2317 | |||
| 2318 | const int si_SEGV_MAPERR = SEGV_MAPERR; | ||
| 2319 | const int si_SEGV_ACCERR = SEGV_ACCERR; | ||
| 2320 | |||
| 2321 | const int modctl_load = MODCTL_LOAD; | ||
| 2322 | const int modctl_unload = MODCTL_UNLOAD; | ||
| 2323 | const int modctl_stat = MODCTL_STAT; | ||
| 2324 | const int modctl_exists = MODCTL_EXISTS; | ||
| 2325 | |||
| 2326 | const unsigned SHA1_CTX_sz = sizeof(SHA1_CTX); | ||
| 2327 | const unsigned SHA1_return_length = SHA1_DIGEST_STRING_LENGTH; | ||
| 2328 | |||
| 2329 | const unsigned MD4_CTX_sz = sizeof(MD4_CTX); | ||
| 2330 | const unsigned MD4_return_length = MD4_DIGEST_STRING_LENGTH; | ||
| 2331 | |||
| 2332 | const unsigned RMD160_CTX_sz = sizeof(RMD160_CTX); | ||
| 2333 | const unsigned RMD160_return_length = RMD160_DIGEST_STRING_LENGTH; | ||
| 2334 | |||
| 2335 | const unsigned MD5_CTX_sz = sizeof(MD5_CTX); | ||
| 2336 | const unsigned MD5_return_length = MD5_DIGEST_STRING_LENGTH; | ||
| 2337 | |||
| 2338 | const unsigned fpos_t_sz = sizeof(fpos_t); | ||
| 2339 | |||
| 2340 | const unsigned MD2_CTX_sz = sizeof(MD2_CTX); | ||
| 2341 | const unsigned MD2_return_length = MD2_DIGEST_STRING_LENGTH; | ||
| 2342 | |||
| 2343 | #define SHA2_CONST(LEN) \ | ||
| 2344 | const unsigned SHA##LEN##_CTX_sz = sizeof(SHA##LEN##_CTX); \ | ||
| 2345 | const unsigned SHA##LEN##_return_length = SHA##LEN##_DIGEST_STRING_LENGTH; \ | ||
| 2346 | const unsigned SHA##LEN##_block_length = SHA##LEN##_BLOCK_LENGTH; \ | ||
| 2347 | const unsigned SHA##LEN##_digest_length = SHA##LEN##_DIGEST_LENGTH | ||
| 2348 | |||
| 2349 | SHA2_CONST(224); | ||
| 2350 | SHA2_CONST(256); | ||
| 2351 | SHA2_CONST(384); | ||
| 2352 | SHA2_CONST(512); | ||
| 2353 | |||
| 2354 | #undef SHA2_CONST | ||
| 2355 | |||
| 2356 | const int unvis_valid = UNVIS_VALID; | ||
| 2357 | const int unvis_validpush = UNVIS_VALIDPUSH; | ||
| 2358 | } // namespace __sanitizer | ||
| 2359 | |||
| 2360 | using namespace __sanitizer; | ||
| 2361 | |||
| 2362 | COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); | ||
| 2363 | |||
| 2364 | COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); | ||
| 2365 | CHECK_TYPE_SIZE(pthread_key_t); | ||
| 2366 | |||
| 2367 | // There are more undocumented fields in dl_phdr_info that we are not interested | ||
| 2368 | // in. | ||
| 2369 | COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); | ||
| 2370 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); | ||
| 2371 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); | ||
| 2372 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); | ||
| 2373 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); | ||
| 2374 | |||
| 2375 | CHECK_TYPE_SIZE(glob_t); | ||
| 2376 | CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); | ||
| 2377 | CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); | ||
| 2378 | CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); | ||
| 2379 | CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); | ||
| 2380 | CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); | ||
| 2381 | CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); | ||
| 2382 | CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); | ||
| 2383 | CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); | ||
| 2384 | CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); | ||
| 2385 | |||
| 2386 | CHECK_TYPE_SIZE(addrinfo); | ||
| 2387 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); | ||
| 2388 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); | ||
| 2389 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); | ||
| 2390 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); | ||
| 2391 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); | ||
| 2392 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); | ||
| 2393 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); | ||
| 2394 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); | ||
| 2395 | |||
| 2396 | CHECK_TYPE_SIZE(hostent); | ||
| 2397 | CHECK_SIZE_AND_OFFSET(hostent, h_name); | ||
| 2398 | CHECK_SIZE_AND_OFFSET(hostent, h_aliases); | ||
| 2399 | CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); | ||
| 2400 | CHECK_SIZE_AND_OFFSET(hostent, h_length); | ||
| 2401 | CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); | ||
| 2402 | |||
| 2403 | CHECK_TYPE_SIZE(iovec); | ||
| 2404 | CHECK_SIZE_AND_OFFSET(iovec, iov_base); | ||
| 2405 | CHECK_SIZE_AND_OFFSET(iovec, iov_len); | ||
| 2406 | |||
| 2407 | CHECK_TYPE_SIZE(msghdr); | ||
| 2408 | CHECK_SIZE_AND_OFFSET(msghdr, msg_name); | ||
| 2409 | CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); | ||
| 2410 | CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); | ||
| 2411 | CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); | ||
| 2412 | CHECK_SIZE_AND_OFFSET(msghdr, msg_control); | ||
| 2413 | CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); | ||
| 2414 | CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); | ||
| 2415 | |||
| 2416 | CHECK_TYPE_SIZE(cmsghdr); | ||
| 2417 | CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); | ||
| 2418 | CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); | ||
| 2419 | CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); | ||
| 2420 | |||
| 2421 | COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); | ||
| 2422 | CHECK_SIZE_AND_OFFSET(dirent, d_fileno); | ||
| 2423 | CHECK_SIZE_AND_OFFSET(dirent, d_reclen); | ||
| 2424 | |||
| 2425 | CHECK_TYPE_SIZE(ifconf); | ||
| 2426 | CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); | ||
| 2427 | CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); | ||
| 2428 | |||
| 2429 | CHECK_TYPE_SIZE(pollfd); | ||
| 2430 | CHECK_SIZE_AND_OFFSET(pollfd, fd); | ||
| 2431 | CHECK_SIZE_AND_OFFSET(pollfd, events); | ||
| 2432 | CHECK_SIZE_AND_OFFSET(pollfd, revents); | ||
| 2433 | |||
| 2434 | CHECK_TYPE_SIZE(nfds_t); | ||
| 2435 | |||
| 2436 | CHECK_TYPE_SIZE(sigset_t); | ||
| 2437 | |||
| 2438 | COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); | ||
| 2439 | // Can't write checks for sa_handler and sa_sigaction due to them being | ||
| 2440 | // preprocessor macros. | ||
| 2441 | CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); | ||
| 2442 | |||
| 2443 | CHECK_TYPE_SIZE(wordexp_t); | ||
| 2444 | CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); | ||
| 2445 | CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); | ||
| 2446 | CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); | ||
| 2447 | |||
| 2448 | COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE)); | ||
| 2449 | CHECK_SIZE_AND_OFFSET(FILE, _p); | ||
| 2450 | CHECK_SIZE_AND_OFFSET(FILE, _r); | ||
| 2451 | CHECK_SIZE_AND_OFFSET(FILE, _w); | ||
| 2452 | CHECK_SIZE_AND_OFFSET(FILE, _flags); | ||
| 2453 | CHECK_SIZE_AND_OFFSET(FILE, _file); | ||
| 2454 | CHECK_SIZE_AND_OFFSET(FILE, _bf); | ||
| 2455 | CHECK_SIZE_AND_OFFSET(FILE, _lbfsize); | ||
| 2456 | CHECK_SIZE_AND_OFFSET(FILE, _cookie); | ||
| 2457 | CHECK_SIZE_AND_OFFSET(FILE, _close); | ||
| 2458 | CHECK_SIZE_AND_OFFSET(FILE, _read); | ||
| 2459 | CHECK_SIZE_AND_OFFSET(FILE, _seek); | ||
| 2460 | CHECK_SIZE_AND_OFFSET(FILE, _write); | ||
| 2461 | CHECK_SIZE_AND_OFFSET(FILE, _ext); | ||
| 2462 | CHECK_SIZE_AND_OFFSET(FILE, _up); | ||
| 2463 | CHECK_SIZE_AND_OFFSET(FILE, _ur); | ||
| 2464 | CHECK_SIZE_AND_OFFSET(FILE, _ubuf); | ||
| 2465 | CHECK_SIZE_AND_OFFSET(FILE, _nbuf); | ||
| 2466 | CHECK_SIZE_AND_OFFSET(FILE, _flush); | ||
| 2467 | CHECK_SIZE_AND_OFFSET(FILE, _lb_unused); | ||
| 2468 | CHECK_SIZE_AND_OFFSET(FILE, _blksize); | ||
| 2469 | CHECK_SIZE_AND_OFFSET(FILE, _offset); | ||
| 2470 | |||
| 2471 | CHECK_TYPE_SIZE(tm); | ||
| 2472 | CHECK_SIZE_AND_OFFSET(tm, tm_sec); | ||
| 2473 | CHECK_SIZE_AND_OFFSET(tm, tm_min); | ||
| 2474 | CHECK_SIZE_AND_OFFSET(tm, tm_hour); | ||
| 2475 | CHECK_SIZE_AND_OFFSET(tm, tm_mday); | ||
| 2476 | CHECK_SIZE_AND_OFFSET(tm, tm_mon); | ||
| 2477 | CHECK_SIZE_AND_OFFSET(tm, tm_year); | ||
| 2478 | CHECK_SIZE_AND_OFFSET(tm, tm_wday); | ||
| 2479 | CHECK_SIZE_AND_OFFSET(tm, tm_yday); | ||
| 2480 | CHECK_SIZE_AND_OFFSET(tm, tm_isdst); | ||
| 2481 | CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); | ||
| 2482 | CHECK_SIZE_AND_OFFSET(tm, tm_zone); | ||
| 2483 | |||
| 2484 | CHECK_TYPE_SIZE(ether_addr); | ||
| 2485 | |||
| 2486 | CHECK_TYPE_SIZE(ipc_perm); | ||
| 2487 | CHECK_SIZE_AND_OFFSET(ipc_perm, _key); | ||
| 2488 | CHECK_SIZE_AND_OFFSET(ipc_perm, _seq); | ||
| 2489 | CHECK_SIZE_AND_OFFSET(ipc_perm, uid); | ||
| 2490 | CHECK_SIZE_AND_OFFSET(ipc_perm, gid); | ||
| 2491 | CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); | ||
| 2492 | CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); | ||
| 2493 | CHECK_SIZE_AND_OFFSET(ipc_perm, mode); | ||
| 2494 | |||
| 2495 | CHECK_TYPE_SIZE(shmid_ds); | ||
| 2496 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); | ||
| 2497 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); | ||
| 2498 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); | ||
| 2499 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); | ||
| 2500 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); | ||
| 2501 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); | ||
| 2502 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); | ||
| 2503 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); | ||
| 2504 | |||
| 2505 | CHECK_TYPE_SIZE(clock_t); | ||
| 2506 | |||
| 2507 | CHECK_TYPE_SIZE(ifaddrs); | ||
| 2508 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); | ||
| 2509 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); | ||
| 2510 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); | ||
| 2511 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); | ||
| 2512 | // Compare against the union, because we can't reach into the union in a | ||
| 2513 | // compliant way. | ||
| 2514 | #ifdef ifa_dstaddr | ||
| 2515 | #undef ifa_dstaddr | ||
| 2516 | #endif | ||
| 2517 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); | ||
| 2518 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); | ||
| 2519 | |||
| 2520 | CHECK_TYPE_SIZE(timeb); | ||
| 2521 | CHECK_SIZE_AND_OFFSET(timeb, time); | ||
| 2522 | CHECK_SIZE_AND_OFFSET(timeb, millitm); | ||
| 2523 | CHECK_SIZE_AND_OFFSET(timeb, timezone); | ||
| 2524 | CHECK_SIZE_AND_OFFSET(timeb, dstflag); | ||
| 2525 | |||
| 2526 | CHECK_TYPE_SIZE(passwd); | ||
| 2527 | CHECK_SIZE_AND_OFFSET(passwd, pw_name); | ||
| 2528 | CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); | ||
| 2529 | CHECK_SIZE_AND_OFFSET(passwd, pw_uid); | ||
| 2530 | CHECK_SIZE_AND_OFFSET(passwd, pw_gid); | ||
| 2531 | CHECK_SIZE_AND_OFFSET(passwd, pw_dir); | ||
| 2532 | CHECK_SIZE_AND_OFFSET(passwd, pw_shell); | ||
| 2533 | |||
| 2534 | CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); | ||
| 2535 | |||
| 2536 | CHECK_TYPE_SIZE(group); | ||
| 2537 | CHECK_SIZE_AND_OFFSET(group, gr_name); | ||
| 2538 | CHECK_SIZE_AND_OFFSET(group, gr_passwd); | ||
| 2539 | CHECK_SIZE_AND_OFFSET(group, gr_gid); | ||
| 2540 | CHECK_SIZE_AND_OFFSET(group, gr_mem); | ||
| 2541 | |||
| 2542 | CHECK_TYPE_SIZE(modctl_load_t); | ||
| 2543 | CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_filename); | ||
| 2544 | CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_flags); | ||
| 2545 | CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_props); | ||
| 2546 | CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_propslen); | ||
| 2547 | |||
| 2548 | // Compat with 9.0 | ||
| 2549 | struct statvfs90 { | ||
| 2550 | unsigned long f_flag; | ||
| 2551 | unsigned long f_bsize; | ||
| 2552 | unsigned long f_frsize; | ||
| 2553 | unsigned long f_iosize; | ||
| 2554 | |||
| 2555 | u64 f_blocks; | ||
| 2556 | u64 f_bfree; | ||
| 2557 | u64 f_bavail; | ||
| 2558 | u64 f_bresvd; | ||
| 2559 | |||
| 2560 | u64 f_files; | ||
| 2561 | u64 f_ffree; | ||
| 2562 | u64 f_favail; | ||
| 2563 | u64 f_fresvd; | ||
| 2564 | |||
| 2565 | u64 f_syncreads; | ||
| 2566 | u64 f_syncwrites; | ||
| 2567 | |||
| 2568 | u64 f_asyncreads; | ||
| 2569 | u64 f_asyncwrites; | ||
| 2570 | |||
| 2571 | struct { | ||
| 2572 | s32 __fsid_val[2]; | ||
| 2573 | } f_fsidx; | ||
| 2574 | unsigned long f_fsid; | ||
| 2575 | unsigned long f_namemax; | ||
| 2576 | u32 f_owner; | ||
| 2577 | |||
| 2578 | u32 f_spare[4]; | ||
| 2579 | |||
| 2580 | char f_fstypename[32]; | ||
| 2581 | char f_mntonname[32]; | ||
| 2582 | char f_mntfromname[32]; | ||
| 2583 | }; | ||
| 2584 | unsigned struct_statvfs90_sz = sizeof(struct statvfs90); | ||
| 2585 | |||
| 2586 | #endif // SANITIZER_NETBSD | ||
lib/tsan/sanitizer_common/sanitizer_platform_limits_netbsd.h created+2422| ... | @@ -0,0 +1,2422 @@ | ||
| 1 | //===-- sanitizer_platform_limits_netbsd.h --------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer common code. | ||
| 10 | // | ||
| 11 | // Sizes and layouts of platform-specific NetBSD data structures. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_PLATFORM_LIMITS_NETBSD_H | ||
| 15 | #define SANITIZER_PLATFORM_LIMITS_NETBSD_H | ||
| 16 | |||
| 17 | #if SANITIZER_NETBSD | ||
| 18 | |||
| 19 | #include "sanitizer_internal_defs.h" | ||
| 20 | #include "sanitizer_platform.h" | ||
| 21 | |||
| 22 | namespace __sanitizer { | ||
| 23 | void *__sanitizer_get_link_map_by_dlopen_handle(void *handle); | ||
| 24 | # define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ | ||
| 25 | (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle) | ||
| 26 | |||
| 27 | extern unsigned struct_utsname_sz; | ||
| 28 | extern unsigned struct_stat_sz; | ||
| 29 | extern unsigned struct_rusage_sz; | ||
| 30 | extern unsigned siginfo_t_sz; | ||
| 31 | extern unsigned struct_itimerval_sz; | ||
| 32 | extern unsigned pthread_t_sz; | ||
| 33 | extern unsigned pthread_mutex_t_sz; | ||
| 34 | extern unsigned pthread_cond_t_sz; | ||
| 35 | extern unsigned pid_t_sz; | ||
| 36 | extern unsigned timeval_sz; | ||
| 37 | extern unsigned uid_t_sz; | ||
| 38 | extern unsigned gid_t_sz; | ||
| 39 | extern unsigned mbstate_t_sz; | ||
| 40 | extern unsigned struct_timezone_sz; | ||
| 41 | extern unsigned struct_tms_sz; | ||
| 42 | extern unsigned struct_itimerspec_sz; | ||
| 43 | extern unsigned struct_sigevent_sz; | ||
| 44 | extern unsigned struct_stack_t_sz; | ||
| 45 | extern unsigned struct_sched_param_sz; | ||
| 46 | extern unsigned struct_statfs_sz; | ||
| 47 | extern unsigned struct_sockaddr_sz; | ||
| 48 | extern unsigned ucontext_t_sz; | ||
| 49 | |||
| 50 | extern unsigned struct_rlimit_sz; | ||
| 51 | extern unsigned struct_utimbuf_sz; | ||
| 52 | extern unsigned struct_timespec_sz; | ||
| 53 | extern unsigned struct_sembuf_sz; | ||
| 54 | |||
| 55 | extern unsigned struct_kevent_sz; | ||
| 56 | extern unsigned struct_FTS_sz; | ||
| 57 | extern unsigned struct_FTSENT_sz; | ||
| 58 | |||
| 59 | extern unsigned struct_regex_sz; | ||
| 60 | extern unsigned struct_regmatch_sz; | ||
| 61 | |||
| 62 | extern unsigned struct_fstab_sz; | ||
| 63 | |||
| 64 | struct __sanitizer_regmatch { | ||
| 65 | OFF_T rm_so; | ||
| 66 | OFF_T rm_eo; | ||
| 67 | }; | ||
| 68 | |||
| 69 | typedef struct __sanitizer_modctl_load { | ||
| 70 | const char *ml_filename; | ||
| 71 | int ml_flags; | ||
| 72 | const char *ml_props; | ||
| 73 | uptr ml_propslen; | ||
| 74 | } __sanitizer_modctl_load_t; | ||
| 75 | extern const int modctl_load; | ||
| 76 | extern const int modctl_unload; | ||
| 77 | extern const int modctl_stat; | ||
| 78 | extern const int modctl_exists; | ||
| 79 | |||
| 80 | union __sanitizer_sigval { | ||
| 81 | int sival_int; | ||
| 82 | uptr sival_ptr; | ||
| 83 | }; | ||
| 84 | |||
| 85 | struct __sanitizer_sigevent { | ||
| 86 | int sigev_notify; | ||
| 87 | int sigev_signo; | ||
| 88 | union __sanitizer_sigval sigev_value; | ||
| 89 | uptr sigev_notify_function; | ||
| 90 | uptr sigev_notify_attributes; | ||
| 91 | }; | ||
| 92 | |||
| 93 | struct __sanitizer_aiocb { | ||
| 94 | u64 aio_offset; | ||
| 95 | uptr aio_buf; | ||
| 96 | uptr aio_nbytes; | ||
| 97 | int aio_fildes; | ||
| 98 | int aio_lio_opcode; | ||
| 99 | int aio_reqprio; | ||
| 100 | struct __sanitizer_sigevent aio_sigevent; | ||
| 101 | int _state; | ||
| 102 | int _errno; | ||
| 103 | long _retval; | ||
| 104 | }; | ||
| 105 | |||
| 106 | struct __sanitizer_sem_t { | ||
| 107 | uptr data[5]; | ||
| 108 | }; | ||
| 109 | |||
| 110 | struct __sanitizer_ipc_perm { | ||
| 111 | u32 uid; | ||
| 112 | u32 gid; | ||
| 113 | u32 cuid; | ||
| 114 | u32 cgid; | ||
| 115 | u32 mode; | ||
| 116 | unsigned short _seq; | ||
| 117 | long _key; | ||
| 118 | }; | ||
| 119 | |||
| 120 | struct __sanitizer_shmid_ds { | ||
| 121 | __sanitizer_ipc_perm shm_perm; | ||
| 122 | unsigned long shm_segsz; | ||
| 123 | u32 shm_lpid; | ||
| 124 | u32 shm_cpid; | ||
| 125 | unsigned int shm_nattch; | ||
| 126 | u64 shm_atime; | ||
| 127 | u64 shm_dtime; | ||
| 128 | u64 shm_ctime; | ||
| 129 | void *_shm_internal; | ||
| 130 | }; | ||
| 131 | |||
| 132 | struct __sanitizer_protoent { | ||
| 133 | char *p_name; | ||
| 134 | char **p_aliases; | ||
| 135 | int p_proto; | ||
| 136 | }; | ||
| 137 | |||
| 138 | struct __sanitizer_netent { | ||
| 139 | char *n_name; | ||
| 140 | char **n_aliases; | ||
| 141 | int n_addrtype; | ||
| 142 | u32 n_net; | ||
| 143 | }; | ||
| 144 | |||
| 145 | extern unsigned struct_msqid_ds_sz; | ||
| 146 | extern unsigned struct_mq_attr_sz; | ||
| 147 | extern unsigned struct_timex_sz; | ||
| 148 | extern unsigned struct_statvfs_sz; | ||
| 149 | |||
| 150 | struct __sanitizer_iovec { | ||
| 151 | void *iov_base; | ||
| 152 | uptr iov_len; | ||
| 153 | }; | ||
| 154 | |||
| 155 | struct __sanitizer_ifaddrs { | ||
| 156 | struct __sanitizer_ifaddrs *ifa_next; | ||
| 157 | char *ifa_name; | ||
| 158 | unsigned int ifa_flags; | ||
| 159 | void *ifa_addr; // (struct sockaddr *) | ||
| 160 | void *ifa_netmask; // (struct sockaddr *) | ||
| 161 | void *ifa_dstaddr; // (struct sockaddr *) | ||
| 162 | void *ifa_data; | ||
| 163 | unsigned int ifa_addrflags; | ||
| 164 | }; | ||
| 165 | |||
| 166 | typedef unsigned int __sanitizer_socklen_t; | ||
| 167 | |||
| 168 | typedef unsigned __sanitizer_pthread_key_t; | ||
| 169 | |||
| 170 | typedef long long __sanitizer_time_t; | ||
| 171 | typedef int __sanitizer_suseconds_t; | ||
| 172 | |||
| 173 | struct __sanitizer_timeval { | ||
| 174 | __sanitizer_time_t tv_sec; | ||
| 175 | __sanitizer_suseconds_t tv_usec; | ||
| 176 | }; | ||
| 177 | |||
| 178 | struct __sanitizer_itimerval { | ||
| 179 | struct __sanitizer_timeval it_interval; | ||
| 180 | struct __sanitizer_timeval it_value; | ||
| 181 | }; | ||
| 182 | |||
| 183 | struct __sanitizer_timespec { | ||
| 184 | __sanitizer_time_t tv_sec; | ||
| 185 | long tv_nsec; | ||
| 186 | }; | ||
| 187 | |||
| 188 | struct __sanitizer_passwd { | ||
| 189 | char *pw_name; | ||
| 190 | char *pw_passwd; | ||
| 191 | int pw_uid; | ||
| 192 | int pw_gid; | ||
| 193 | __sanitizer_time_t pw_change; | ||
| 194 | char *pw_class; | ||
| 195 | char *pw_gecos; | ||
| 196 | char *pw_dir; | ||
| 197 | char *pw_shell; | ||
| 198 | __sanitizer_time_t pw_expire; | ||
| 199 | }; | ||
| 200 | |||
| 201 | struct __sanitizer_group { | ||
| 202 | char *gr_name; | ||
| 203 | char *gr_passwd; | ||
| 204 | int gr_gid; | ||
| 205 | char **gr_mem; | ||
| 206 | }; | ||
| 207 | |||
| 208 | struct __sanitizer_timeb { | ||
| 209 | __sanitizer_time_t time; | ||
| 210 | unsigned short millitm; | ||
| 211 | short timezone; | ||
| 212 | short dstflag; | ||
| 213 | }; | ||
| 214 | |||
| 215 | struct __sanitizer_ether_addr { | ||
| 216 | u8 octet[6]; | ||
| 217 | }; | ||
| 218 | |||
| 219 | struct __sanitizer_tm { | ||
| 220 | int tm_sec; | ||
| 221 | int tm_min; | ||
| 222 | int tm_hour; | ||
| 223 | int tm_mday; | ||
| 224 | int tm_mon; | ||
| 225 | int tm_year; | ||
| 226 | int tm_wday; | ||
| 227 | int tm_yday; | ||
| 228 | int tm_isdst; | ||
| 229 | long int tm_gmtoff; | ||
| 230 | const char *tm_zone; | ||
| 231 | }; | ||
| 232 | |||
| 233 | struct __sanitizer_msghdr { | ||
| 234 | void *msg_name; | ||
| 235 | unsigned msg_namelen; | ||
| 236 | struct __sanitizer_iovec *msg_iov; | ||
| 237 | unsigned msg_iovlen; | ||
| 238 | void *msg_control; | ||
| 239 | unsigned msg_controllen; | ||
| 240 | int msg_flags; | ||
| 241 | }; | ||
| 242 | |||
| 243 | struct __sanitizer_mmsghdr { | ||
| 244 | struct __sanitizer_msghdr msg_hdr; | ||
| 245 | unsigned int msg_len; | ||
| 246 | }; | ||
| 247 | |||
| 248 | struct __sanitizer_cmsghdr { | ||
| 249 | unsigned cmsg_len; | ||
| 250 | int cmsg_level; | ||
| 251 | int cmsg_type; | ||
| 252 | }; | ||
| 253 | |||
| 254 | struct __sanitizer_dirent { | ||
| 255 | u64 d_fileno; | ||
| 256 | u16 d_reclen; | ||
| 257 | // more fields that we don't care about | ||
| 258 | }; | ||
| 259 | |||
| 260 | typedef int __sanitizer_clock_t; | ||
| 261 | typedef int __sanitizer_clockid_t; | ||
| 262 | |||
| 263 | typedef u32 __sanitizer___kernel_uid_t; | ||
| 264 | typedef u32 __sanitizer___kernel_gid_t; | ||
| 265 | typedef u64 __sanitizer___kernel_off_t; | ||
| 266 | typedef struct { | ||
| 267 | u32 fds_bits[8]; | ||
| 268 | } __sanitizer___kernel_fd_set; | ||
| 269 | |||
| 270 | typedef struct { | ||
| 271 | unsigned int pta_magic; | ||
| 272 | int pta_flags; | ||
| 273 | void *pta_private; | ||
| 274 | } __sanitizer_pthread_attr_t; | ||
| 275 | |||
| 276 | struct __sanitizer_sigset_t { | ||
| 277 | // uint32_t * 4 | ||
| 278 | unsigned int __bits[4]; | ||
| 279 | }; | ||
| 280 | |||
| 281 | struct __sanitizer_siginfo { | ||
| 282 | // The size is determined by looking at sizeof of real siginfo_t on linux. | ||
| 283 | u64 opaque[128 / sizeof(u64)]; | ||
| 284 | }; | ||
| 285 | |||
| 286 | using __sanitizer_sighandler_ptr = void (*)(int sig); | ||
| 287 | using __sanitizer_sigactionhandler_ptr = void (*)(int sig, | ||
| 288 | __sanitizer_siginfo *siginfo, | ||
| 289 | void *uctx); | ||
| 290 | |||
| 291 | struct __sanitizer_sigaction { | ||
| 292 | union { | ||
| 293 | __sanitizer_sighandler_ptr handler; | ||
| 294 | __sanitizer_sigactionhandler_ptr sigaction; | ||
| 295 | }; | ||
| 296 | __sanitizer_sigset_t sa_mask; | ||
| 297 | int sa_flags; | ||
| 298 | }; | ||
| 299 | |||
| 300 | extern unsigned struct_sigaltstack_sz; | ||
| 301 | |||
| 302 | typedef unsigned int __sanitizer_sigset13_t; | ||
| 303 | |||
| 304 | struct __sanitizer_sigaction13 { | ||
| 305 | __sanitizer_sighandler_ptr osa_handler; | ||
| 306 | __sanitizer_sigset13_t osa_mask; | ||
| 307 | int osa_flags; | ||
| 308 | }; | ||
| 309 | |||
| 310 | struct __sanitizer_sigaltstack { | ||
| 311 | void *ss_sp; | ||
| 312 | uptr ss_size; | ||
| 313 | int ss_flags; | ||
| 314 | }; | ||
| 315 | |||
| 316 | typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t; | ||
| 317 | |||
| 318 | struct __sanitizer_kernel_sigaction_t { | ||
| 319 | union { | ||
| 320 | void (*handler)(int signo); | ||
| 321 | void (*sigaction)(int signo, void *info, void *ctx); | ||
| 322 | }; | ||
| 323 | unsigned long sa_flags; | ||
| 324 | void (*sa_restorer)(void); | ||
| 325 | __sanitizer_kernel_sigset_t sa_mask; | ||
| 326 | }; | ||
| 327 | |||
| 328 | extern const uptr sig_ign; | ||
| 329 | extern const uptr sig_dfl; | ||
| 330 | extern const uptr sig_err; | ||
| 331 | extern const uptr sa_siginfo; | ||
| 332 | |||
| 333 | extern int af_inet; | ||
| 334 | extern int af_inet6; | ||
| 335 | uptr __sanitizer_in_addr_sz(int af); | ||
| 336 | |||
| 337 | struct __sanitizer_dl_phdr_info { | ||
| 338 | uptr dlpi_addr; | ||
| 339 | const char *dlpi_name; | ||
| 340 | const void *dlpi_phdr; | ||
| 341 | short dlpi_phnum; | ||
| 342 | }; | ||
| 343 | |||
| 344 | extern unsigned struct_ElfW_Phdr_sz; | ||
| 345 | |||
| 346 | struct __sanitizer_addrinfo { | ||
| 347 | int ai_flags; | ||
| 348 | int ai_family; | ||
| 349 | int ai_socktype; | ||
| 350 | int ai_protocol; | ||
| 351 | #if defined(__sparc__) && defined(_LP64) | ||
| 352 | int __ai_pad0; | ||
| 353 | #endif | ||
| 354 | unsigned ai_addrlen; | ||
| 355 | #if defined(__alpha__) || (defined(__i386__) && defined(_LP64)) | ||
| 356 | int __ai_pad0; | ||
| 357 | #endif | ||
| 358 | char *ai_canonname; | ||
| 359 | void *ai_addr; | ||
| 360 | struct __sanitizer_addrinfo *ai_next; | ||
| 361 | }; | ||
| 362 | |||
| 363 | struct __sanitizer_hostent { | ||
| 364 | char *h_name; | ||
| 365 | char **h_aliases; | ||
| 366 | int h_addrtype; | ||
| 367 | int h_length; | ||
| 368 | char **h_addr_list; | ||
| 369 | }; | ||
| 370 | |||
| 371 | struct __sanitizer_pollfd { | ||
| 372 | int fd; | ||
| 373 | short events; | ||
| 374 | short revents; | ||
| 375 | }; | ||
| 376 | |||
| 377 | typedef unsigned __sanitizer_nfds_t; | ||
| 378 | |||
| 379 | typedef int __sanitizer_lwpid_t; | ||
| 380 | |||
| 381 | struct __sanitizer_glob_t { | ||
| 382 | uptr gl_pathc; | ||
| 383 | uptr gl_matchc; | ||
| 384 | uptr gl_offs; | ||
| 385 | int gl_flags; | ||
| 386 | char **gl_pathv; | ||
| 387 | int (*gl_errfunc)(const char *, int); | ||
| 388 | void (*gl_closedir)(void *dirp); | ||
| 389 | struct dirent *(*gl_readdir)(void *dirp); | ||
| 390 | void *(*gl_opendir)(const char *); | ||
| 391 | int (*gl_lstat)(const char *, void * /* struct stat* */); | ||
| 392 | int (*gl_stat)(const char *, void * /* struct stat* */); | ||
| 393 | }; | ||
| 394 | |||
| 395 | extern int glob_nomatch; | ||
| 396 | extern int glob_altdirfunc; | ||
| 397 | |||
| 398 | extern unsigned path_max; | ||
| 399 | |||
| 400 | extern int struct_ttyent_sz; | ||
| 401 | |||
| 402 | extern int ptrace_pt_io; | ||
| 403 | extern int ptrace_pt_lwpinfo; | ||
| 404 | extern int ptrace_pt_set_event_mask; | ||
| 405 | extern int ptrace_pt_get_event_mask; | ||
| 406 | extern int ptrace_pt_get_process_state; | ||
| 407 | extern int ptrace_pt_set_siginfo; | ||
| 408 | extern int ptrace_pt_get_siginfo; | ||
| 409 | extern int ptrace_pt_lwpstatus; | ||
| 410 | extern int ptrace_pt_lwpnext; | ||
| 411 | extern int ptrace_piod_read_d; | ||
| 412 | extern int ptrace_piod_write_d; | ||
| 413 | extern int ptrace_piod_read_i; | ||
| 414 | extern int ptrace_piod_write_i; | ||
| 415 | extern int ptrace_piod_read_auxv; | ||
| 416 | extern int ptrace_pt_setregs; | ||
| 417 | extern int ptrace_pt_getregs; | ||
| 418 | extern int ptrace_pt_setfpregs; | ||
| 419 | extern int ptrace_pt_getfpregs; | ||
| 420 | extern int ptrace_pt_setdbregs; | ||
| 421 | extern int ptrace_pt_getdbregs; | ||
| 422 | |||
| 423 | struct __sanitizer_ptrace_io_desc { | ||
| 424 | int piod_op; | ||
| 425 | void *piod_offs; | ||
| 426 | void *piod_addr; | ||
| 427 | uptr piod_len; | ||
| 428 | }; | ||
| 429 | |||
| 430 | struct __sanitizer_ptrace_lwpinfo { | ||
| 431 | __sanitizer_lwpid_t pl_lwpid; | ||
| 432 | int pl_event; | ||
| 433 | }; | ||
| 434 | |||
| 435 | struct __sanitizer_ptrace_lwpstatus { | ||
| 436 | __sanitizer_lwpid_t pl_lwpid; | ||
| 437 | __sanitizer_sigset_t pl_sigpend; | ||
| 438 | __sanitizer_sigset_t pl_sigmask; | ||
| 439 | char pl_name[20]; | ||
| 440 | void *pl_private; | ||
| 441 | }; | ||
| 442 | |||
| 443 | extern unsigned struct_ptrace_ptrace_io_desc_struct_sz; | ||
| 444 | extern unsigned struct_ptrace_ptrace_lwpinfo_struct_sz; | ||
| 445 | extern unsigned struct_ptrace_ptrace_lwpstatus_struct_sz; | ||
| 446 | extern unsigned struct_ptrace_ptrace_event_struct_sz; | ||
| 447 | extern unsigned struct_ptrace_ptrace_siginfo_struct_sz; | ||
| 448 | |||
| 449 | extern unsigned struct_ptrace_reg_struct_sz; | ||
| 450 | extern unsigned struct_ptrace_fpreg_struct_sz; | ||
| 451 | extern unsigned struct_ptrace_dbreg_struct_sz; | ||
| 452 | |||
| 453 | struct __sanitizer_wordexp_t { | ||
| 454 | uptr we_wordc; | ||
| 455 | char **we_wordv; | ||
| 456 | uptr we_offs; | ||
| 457 | char *we_strings; | ||
| 458 | uptr we_nbytes; | ||
| 459 | }; | ||
| 460 | |||
| 461 | struct __sanitizer_FILE { | ||
| 462 | unsigned char *_p; | ||
| 463 | int _r; | ||
| 464 | int _w; | ||
| 465 | unsigned short _flags; | ||
| 466 | short _file; | ||
| 467 | struct { | ||
| 468 | unsigned char *_base; | ||
| 469 | int _size; | ||
| 470 | } _bf; | ||
| 471 | int _lbfsize; | ||
| 472 | void *_cookie; | ||
| 473 | int (*_close)(void *ptr); | ||
| 474 | u64 (*_read)(void *, void *, uptr); | ||
| 475 | u64 (*_seek)(void *, u64, int); | ||
| 476 | uptr (*_write)(void *, const void *, uptr); | ||
| 477 | struct { | ||
| 478 | unsigned char *_base; | ||
| 479 | int _size; | ||
| 480 | } _ext; | ||
| 481 | unsigned char *_up; | ||
| 482 | int _ur; | ||
| 483 | unsigned char _ubuf[3]; | ||
| 484 | unsigned char _nbuf[1]; | ||
| 485 | int (*_flush)(void *ptr); | ||
| 486 | char _lb_unused[sizeof(uptr)]; | ||
| 487 | int _blksize; | ||
| 488 | u64 _offset; | ||
| 489 | }; | ||
| 490 | #define SANITIZER_HAS_STRUCT_FILE 1 | ||
| 491 | |||
| 492 | extern int shmctl_ipc_stat; | ||
| 493 | |||
| 494 | // This simplifies generic code | ||
| 495 | #define struct_shminfo_sz -1 | ||
| 496 | #define struct_shm_info_sz -1 | ||
| 497 | #define shmctl_shm_stat -1 | ||
| 498 | #define shmctl_ipc_info -1 | ||
| 499 | #define shmctl_shm_info -1 | ||
| 500 | |||
| 501 | extern unsigned struct_utmp_sz; | ||
| 502 | extern unsigned struct_utmpx_sz; | ||
| 503 | |||
| 504 | extern int map_fixed; | ||
| 505 | |||
| 506 | // ioctl arguments | ||
| 507 | struct __sanitizer_ifconf { | ||
| 508 | int ifc_len; | ||
| 509 | union { | ||
| 510 | void *ifcu_req; | ||
| 511 | } ifc_ifcu; | ||
| 512 | }; | ||
| 513 | |||
| 514 | struct __sanitizer_ttyent { | ||
| 515 | char *ty_name; | ||
| 516 | char *ty_getty; | ||
| 517 | char *ty_type; | ||
| 518 | int ty_status; | ||
| 519 | char *ty_window; | ||
| 520 | char *ty_comment; | ||
| 521 | char *ty_class; | ||
| 522 | }; | ||
| 523 | |||
| 524 | extern const unsigned long __sanitizer_bufsiz; | ||
| 525 | |||
| 526 | #define IOC_NRBITS 8 | ||
| 527 | #define IOC_TYPEBITS 8 | ||
| 528 | #define IOC_SIZEBITS 14 | ||
| 529 | #define IOC_DIRBITS 2 | ||
| 530 | #define IOC_NONE 0U | ||
| 531 | #define IOC_WRITE 1U | ||
| 532 | #define IOC_READ 2U | ||
| 533 | #define IOC_NRMASK ((1 << IOC_NRBITS) - 1) | ||
| 534 | #define IOC_TYPEMASK ((1 << IOC_TYPEBITS) - 1) | ||
| 535 | #define IOC_SIZEMASK ((1 << IOC_SIZEBITS) - 1) | ||
| 536 | #undef IOC_DIRMASK | ||
| 537 | #define IOC_DIRMASK ((1 << IOC_DIRBITS) - 1) | ||
| 538 | #define IOC_NRSHIFT 0 | ||
| 539 | #define IOC_TYPESHIFT (IOC_NRSHIFT + IOC_NRBITS) | ||
| 540 | #define IOC_SIZESHIFT (IOC_TYPESHIFT + IOC_TYPEBITS) | ||
| 541 | #define IOC_DIRSHIFT (IOC_SIZESHIFT + IOC_SIZEBITS) | ||
| 542 | #define EVIOC_EV_MAX 0x1f | ||
| 543 | #define EVIOC_ABS_MAX 0x3f | ||
| 544 | |||
| 545 | #define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK) | ||
| 546 | #define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK) | ||
| 547 | #define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK) | ||
| 548 | #define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) | ||
| 549 | |||
| 550 | // ioctl request identifiers | ||
| 551 | |||
| 552 | extern unsigned struct_altqreq_sz; | ||
| 553 | extern unsigned struct_amr_user_ioctl_sz; | ||
| 554 | extern unsigned struct_ap_control_sz; | ||
| 555 | extern unsigned struct_apm_ctl_sz; | ||
| 556 | extern unsigned struct_apm_event_info_sz; | ||
| 557 | extern unsigned struct_apm_power_info_sz; | ||
| 558 | extern unsigned struct_atabusiodetach_args_sz; | ||
| 559 | extern unsigned struct_atabusioscan_args_sz; | ||
| 560 | extern unsigned struct_ath_diag_sz; | ||
| 561 | extern unsigned struct_atm_flowmap_sz; | ||
| 562 | extern unsigned struct_audio_buf_info_sz; | ||
| 563 | extern unsigned struct_audio_device_sz; | ||
| 564 | extern unsigned struct_audio_encoding_sz; | ||
| 565 | extern unsigned struct_audio_info_sz; | ||
| 566 | extern unsigned struct_audio_offset_sz; | ||
| 567 | extern unsigned struct_bio_locate_sz; | ||
| 568 | extern unsigned struct_bioc_alarm_sz; | ||
| 569 | extern unsigned struct_bioc_blink_sz; | ||
| 570 | extern unsigned struct_bioc_disk_sz; | ||
| 571 | extern unsigned struct_bioc_inq_sz; | ||
| 572 | extern unsigned struct_bioc_setstate_sz; | ||
| 573 | extern unsigned struct_bioc_vol_sz; | ||
| 574 | extern unsigned struct_bioc_volops_sz; | ||
| 575 | extern unsigned struct_bktr_chnlset_sz; | ||
| 576 | extern unsigned struct_bktr_remote_sz; | ||
| 577 | extern unsigned struct_blue_conf_sz; | ||
| 578 | extern unsigned struct_blue_interface_sz; | ||
| 579 | extern unsigned struct_blue_stats_sz; | ||
| 580 | extern unsigned struct_bpf_dltlist_sz; | ||
| 581 | extern unsigned struct_bpf_program_sz; | ||
| 582 | extern unsigned struct_bpf_stat_old_sz; | ||
| 583 | extern unsigned struct_bpf_stat_sz; | ||
| 584 | extern unsigned struct_bpf_version_sz; | ||
| 585 | extern unsigned struct_btreq_sz; | ||
| 586 | extern unsigned struct_btsco_info_sz; | ||
| 587 | extern unsigned struct_buffmem_desc_sz; | ||
| 588 | extern unsigned struct_cbq_add_class_sz; | ||
| 589 | extern unsigned struct_cbq_add_filter_sz; | ||
| 590 | extern unsigned struct_cbq_delete_class_sz; | ||
| 591 | extern unsigned struct_cbq_delete_filter_sz; | ||
| 592 | extern unsigned struct_cbq_getstats_sz; | ||
| 593 | extern unsigned struct_cbq_interface_sz; | ||
| 594 | extern unsigned struct_cbq_modify_class_sz; | ||
| 595 | extern unsigned struct_ccd_ioctl_sz; | ||
| 596 | extern unsigned struct_cdnr_add_element_sz; | ||
| 597 | extern unsigned struct_cdnr_add_filter_sz; | ||
| 598 | extern unsigned struct_cdnr_add_tbmeter_sz; | ||
| 599 | extern unsigned struct_cdnr_add_trtcm_sz; | ||
| 600 | extern unsigned struct_cdnr_add_tswtcm_sz; | ||
| 601 | extern unsigned struct_cdnr_delete_element_sz; | ||
| 602 | extern unsigned struct_cdnr_delete_filter_sz; | ||
| 603 | extern unsigned struct_cdnr_get_stats_sz; | ||
| 604 | extern unsigned struct_cdnr_interface_sz; | ||
| 605 | extern unsigned struct_cdnr_modify_tbmeter_sz; | ||
| 606 | extern unsigned struct_cdnr_modify_trtcm_sz; | ||
| 607 | extern unsigned struct_cdnr_modify_tswtcm_sz; | ||
| 608 | extern unsigned struct_cdnr_tbmeter_stats_sz; | ||
| 609 | extern unsigned struct_cdnr_tcm_stats_sz; | ||
| 610 | extern unsigned struct_cgd_ioctl_sz; | ||
| 611 | extern unsigned struct_cgd_user_sz; | ||
| 612 | extern unsigned struct_changer_element_status_request_sz; | ||
| 613 | extern unsigned struct_changer_exchange_request_sz; | ||
| 614 | extern unsigned struct_changer_move_request_sz; | ||
| 615 | extern unsigned struct_changer_params_sz; | ||
| 616 | extern unsigned struct_changer_position_request_sz; | ||
| 617 | extern unsigned struct_changer_set_voltag_request_sz; | ||
| 618 | extern unsigned struct_clockctl_adjtime_sz; | ||
| 619 | extern unsigned struct_clockctl_clock_settime_sz; | ||
| 620 | extern unsigned struct_clockctl_ntp_adjtime_sz; | ||
| 621 | extern unsigned struct_clockctl_settimeofday_sz; | ||
| 622 | extern unsigned struct_cnwistats_sz; | ||
| 623 | extern unsigned struct_cnwitrail_sz; | ||
| 624 | extern unsigned struct_cnwstatus_sz; | ||
| 625 | extern unsigned struct_count_info_sz; | ||
| 626 | extern unsigned struct_cpu_ucode_sz; | ||
| 627 | extern unsigned struct_cpu_ucode_version_sz; | ||
| 628 | extern unsigned struct_crypt_kop_sz; | ||
| 629 | extern unsigned struct_crypt_mkop_sz; | ||
| 630 | extern unsigned struct_crypt_mop_sz; | ||
| 631 | extern unsigned struct_crypt_op_sz; | ||
| 632 | extern unsigned struct_crypt_result_sz; | ||
| 633 | extern unsigned struct_crypt_sfop_sz; | ||
| 634 | extern unsigned struct_crypt_sgop_sz; | ||
| 635 | extern unsigned struct_cryptret_sz; | ||
| 636 | extern unsigned struct_devdetachargs_sz; | ||
| 637 | extern unsigned struct_devlistargs_sz; | ||
| 638 | extern unsigned struct_devpmargs_sz; | ||
| 639 | extern unsigned struct_devrescanargs_sz; | ||
| 640 | extern unsigned struct_disk_badsecinfo_sz; | ||
| 641 | extern unsigned struct_disk_strategy_sz; | ||
| 642 | extern unsigned struct_disklabel_sz; | ||
| 643 | extern unsigned struct_dkbad_sz; | ||
| 644 | extern unsigned struct_dkwedge_info_sz; | ||
| 645 | extern unsigned struct_dkwedge_list_sz; | ||
| 646 | extern unsigned struct_dmio_setfunc_sz; | ||
| 647 | extern unsigned struct_dmx_pes_filter_params_sz; | ||
| 648 | extern unsigned struct_dmx_sct_filter_params_sz; | ||
| 649 | extern unsigned struct_dmx_stc_sz; | ||
| 650 | extern unsigned struct_dvb_diseqc_master_cmd_sz; | ||
| 651 | extern unsigned struct_dvb_diseqc_slave_reply_sz; | ||
| 652 | extern unsigned struct_dvb_frontend_event_sz; | ||
| 653 | extern unsigned struct_dvb_frontend_info_sz; | ||
| 654 | extern unsigned struct_dvb_frontend_parameters_sz; | ||
| 655 | extern unsigned struct_eccapreq_sz; | ||
| 656 | extern unsigned struct_fbcmap_sz; | ||
| 657 | extern unsigned struct_fbcurpos_sz; | ||
| 658 | extern unsigned struct_fbcursor_sz; | ||
| 659 | extern unsigned struct_fbgattr_sz; | ||
| 660 | extern unsigned struct_fbsattr_sz; | ||
| 661 | extern unsigned struct_fbtype_sz; | ||
| 662 | extern unsigned struct_fdformat_cmd_sz; | ||
| 663 | extern unsigned struct_fdformat_parms_sz; | ||
| 664 | extern unsigned struct_fifoq_conf_sz; | ||
| 665 | extern unsigned struct_fifoq_getstats_sz; | ||
| 666 | extern unsigned struct_fifoq_interface_sz; | ||
| 667 | extern unsigned struct_format_op_sz; | ||
| 668 | extern unsigned struct_fss_get_sz; | ||
| 669 | extern unsigned struct_fss_set_sz; | ||
| 670 | extern unsigned struct_gpio_attach_sz; | ||
| 671 | extern unsigned struct_gpio_info_sz; | ||
| 672 | extern unsigned struct_gpio_req_sz; | ||
| 673 | extern unsigned struct_gpio_set_sz; | ||
| 674 | extern unsigned struct_hfsc_add_class_sz; | ||
| 675 | extern unsigned struct_hfsc_add_filter_sz; | ||
| 676 | extern unsigned struct_hfsc_attach_sz; | ||
| 677 | extern unsigned struct_hfsc_class_stats_sz; | ||
| 678 | extern unsigned struct_hfsc_delete_class_sz; | ||
| 679 | extern unsigned struct_hfsc_delete_filter_sz; | ||
| 680 | extern unsigned struct_hfsc_interface_sz; | ||
| 681 | extern unsigned struct_hfsc_modify_class_sz; | ||
| 682 | extern unsigned struct_hpcfb_dsp_op_sz; | ||
| 683 | extern unsigned struct_hpcfb_dspconf_sz; | ||
| 684 | extern unsigned struct_hpcfb_fbconf_sz; | ||
| 685 | extern unsigned struct_if_addrprefreq_sz; | ||
| 686 | extern unsigned struct_if_clonereq_sz; | ||
| 687 | extern unsigned struct_if_laddrreq_sz; | ||
| 688 | extern unsigned struct_ifaddr_sz; | ||
| 689 | extern unsigned struct_ifaliasreq_sz; | ||
| 690 | extern unsigned struct_ifcapreq_sz; | ||
| 691 | extern unsigned struct_ifconf_sz; | ||
| 692 | extern unsigned struct_ifdatareq_sz; | ||
| 693 | extern unsigned struct_ifdrv_sz; | ||
| 694 | extern unsigned struct_ifmediareq_sz; | ||
| 695 | extern unsigned struct_ifpppcstatsreq_sz; | ||
| 696 | extern unsigned struct_ifpppstatsreq_sz; | ||
| 697 | extern unsigned struct_ifreq_sz; | ||
| 698 | extern unsigned struct_in6_addrpolicy_sz; | ||
| 699 | extern unsigned struct_in6_ndireq_sz; | ||
| 700 | extern unsigned struct_ioc_load_unload_sz; | ||
| 701 | extern unsigned struct_ioc_patch_sz; | ||
| 702 | extern unsigned struct_ioc_play_blocks_sz; | ||
| 703 | extern unsigned struct_ioc_play_msf_sz; | ||
| 704 | extern unsigned struct_ioc_play_track_sz; | ||
| 705 | extern unsigned struct_ioc_read_subchannel_sz; | ||
| 706 | extern unsigned struct_ioc_read_toc_entry_sz; | ||
| 707 | extern unsigned struct_ioc_toc_header_sz; | ||
| 708 | extern unsigned struct_ioc_vol_sz; | ||
| 709 | extern unsigned struct_ioctl_pt_sz; | ||
| 710 | extern unsigned struct_ioppt_sz; | ||
| 711 | extern unsigned struct_iovec_sz; | ||
| 712 | extern unsigned struct_ipfobj_sz; | ||
| 713 | extern unsigned struct_irda_params_sz; | ||
| 714 | extern unsigned struct_isp_fc_device_sz; | ||
| 715 | extern unsigned struct_isp_fc_tsk_mgmt_sz; | ||
| 716 | extern unsigned struct_isp_hba_device_sz; | ||
| 717 | extern unsigned struct_isv_cmd_sz; | ||
| 718 | extern unsigned struct_jobs_add_class_sz; | ||
| 719 | extern unsigned struct_jobs_add_filter_sz; | ||
| 720 | extern unsigned struct_jobs_attach_sz; | ||
| 721 | extern unsigned struct_jobs_class_stats_sz; | ||
| 722 | extern unsigned struct_jobs_delete_class_sz; | ||
| 723 | extern unsigned struct_jobs_delete_filter_sz; | ||
| 724 | extern unsigned struct_jobs_interface_sz; | ||
| 725 | extern unsigned struct_jobs_modify_class_sz; | ||
| 726 | extern unsigned struct_kbentry_sz; | ||
| 727 | extern unsigned struct_kfilter_mapping_sz; | ||
| 728 | extern unsigned struct_kiockeymap_sz; | ||
| 729 | extern unsigned struct_ksyms_gsymbol_sz; | ||
| 730 | extern unsigned struct_ksyms_gvalue_sz; | ||
| 731 | extern unsigned struct_ksyms_ogsymbol_sz; | ||
| 732 | extern unsigned struct_kttcp_io_args_sz; | ||
| 733 | extern unsigned struct_ltchars_sz; | ||
| 734 | extern unsigned struct_lua_create_sz; | ||
| 735 | extern unsigned struct_lua_info_sz; | ||
| 736 | extern unsigned struct_lua_load_sz; | ||
| 737 | extern unsigned struct_lua_require_sz; | ||
| 738 | extern unsigned struct_mbpp_param_sz; | ||
| 739 | extern unsigned struct_md_conf_sz; | ||
| 740 | extern unsigned struct_meteor_capframe_sz; | ||
| 741 | extern unsigned struct_meteor_counts_sz; | ||
| 742 | extern unsigned struct_meteor_geomet_sz; | ||
| 743 | extern unsigned struct_meteor_pixfmt_sz; | ||
| 744 | extern unsigned struct_meteor_video_sz; | ||
| 745 | extern unsigned struct_mlx_cinfo_sz; | ||
| 746 | extern unsigned struct_mlx_pause_sz; | ||
| 747 | extern unsigned struct_mlx_rebuild_request_sz; | ||
| 748 | extern unsigned struct_mlx_rebuild_status_sz; | ||
| 749 | extern unsigned struct_mlx_usercommand_sz; | ||
| 750 | extern unsigned struct_mly_user_command_sz; | ||
| 751 | extern unsigned struct_mly_user_health_sz; | ||
| 752 | extern unsigned struct_mtget_sz; | ||
| 753 | extern unsigned struct_mtop_sz; | ||
| 754 | extern unsigned struct_npf_ioctl_table_sz; | ||
| 755 | extern unsigned struct_npioctl_sz; | ||
| 756 | extern unsigned struct_nvme_pt_command_sz; | ||
| 757 | extern unsigned struct_ochanger_element_status_request_sz; | ||
| 758 | extern unsigned struct_ofiocdesc_sz; | ||
| 759 | extern unsigned struct_okiockey_sz; | ||
| 760 | extern unsigned struct_ortentry_sz; | ||
| 761 | extern unsigned struct_oscsi_addr_sz; | ||
| 762 | extern unsigned struct_oss_audioinfo_sz; | ||
| 763 | extern unsigned struct_oss_sysinfo_sz; | ||
| 764 | extern unsigned struct_pciio_bdf_cfgreg_sz; | ||
| 765 | extern unsigned struct_pciio_businfo_sz; | ||
| 766 | extern unsigned struct_pciio_cfgreg_sz; | ||
| 767 | extern unsigned struct_pciio_drvname_sz; | ||
| 768 | extern unsigned struct_pciio_drvnameonbus_sz; | ||
| 769 | extern unsigned struct_pcvtid_sz; | ||
| 770 | extern unsigned struct_pf_osfp_ioctl_sz; | ||
| 771 | extern unsigned struct_pf_status_sz; | ||
| 772 | extern unsigned struct_pfioc_altq_sz; | ||
| 773 | extern unsigned struct_pfioc_if_sz; | ||
| 774 | extern unsigned struct_pfioc_iface_sz; | ||
| 775 | extern unsigned struct_pfioc_limit_sz; | ||
| 776 | extern unsigned struct_pfioc_natlook_sz; | ||
| 777 | extern unsigned struct_pfioc_pooladdr_sz; | ||
| 778 | extern unsigned struct_pfioc_qstats_sz; | ||
| 779 | extern unsigned struct_pfioc_rule_sz; | ||
| 780 | extern unsigned struct_pfioc_ruleset_sz; | ||
| 781 | extern unsigned struct_pfioc_src_node_kill_sz; | ||
| 782 | extern unsigned struct_pfioc_src_nodes_sz; | ||
| 783 | extern unsigned struct_pfioc_state_kill_sz; | ||
| 784 | extern unsigned struct_pfioc_state_sz; | ||
| 785 | extern unsigned struct_pfioc_states_sz; | ||
| 786 | extern unsigned struct_pfioc_table_sz; | ||
| 787 | extern unsigned struct_pfioc_tm_sz; | ||
| 788 | extern unsigned struct_pfioc_trans_sz; | ||
| 789 | extern unsigned struct_plistref_sz; | ||
| 790 | extern unsigned struct_power_type_sz; | ||
| 791 | extern unsigned struct_ppp_idle_sz; | ||
| 792 | extern unsigned struct_ppp_option_data_sz; | ||
| 793 | extern unsigned struct_ppp_rawin_sz; | ||
| 794 | extern unsigned struct_pppoeconnectionstate_sz; | ||
| 795 | extern unsigned struct_pppoediscparms_sz; | ||
| 796 | extern unsigned struct_priq_add_class_sz; | ||
| 797 | extern unsigned struct_priq_add_filter_sz; | ||
| 798 | extern unsigned struct_priq_class_stats_sz; | ||
| 799 | extern unsigned struct_priq_delete_class_sz; | ||
| 800 | extern unsigned struct_priq_delete_filter_sz; | ||
| 801 | extern unsigned struct_priq_interface_sz; | ||
| 802 | extern unsigned struct_priq_modify_class_sz; | ||
| 803 | extern unsigned struct_ptmget_sz; | ||
| 804 | extern unsigned struct_pvctxreq_sz; | ||
| 805 | extern unsigned struct_radio_info_sz; | ||
| 806 | extern unsigned struct_red_conf_sz; | ||
| 807 | extern unsigned struct_red_interface_sz; | ||
| 808 | extern unsigned struct_red_stats_sz; | ||
| 809 | extern unsigned struct_redparams_sz; | ||
| 810 | extern unsigned struct_rf_pmparams_sz; | ||
| 811 | extern unsigned struct_rf_pmstat_sz; | ||
| 812 | extern unsigned struct_rf_recon_req_sz; | ||
| 813 | extern unsigned struct_rio_conf_sz; | ||
| 814 | extern unsigned struct_rio_interface_sz; | ||
| 815 | extern unsigned struct_rio_stats_sz; | ||
| 816 | extern unsigned struct_scan_io_sz; | ||
| 817 | extern unsigned struct_scbusaccel_args_sz; | ||
| 818 | extern unsigned struct_scbusiodetach_args_sz; | ||
| 819 | extern unsigned struct_scbusioscan_args_sz; | ||
| 820 | extern unsigned struct_scsi_addr_sz; | ||
| 821 | extern unsigned struct_seq_event_rec_sz; | ||
| 822 | extern unsigned struct_session_op_sz; | ||
| 823 | extern unsigned struct_sgttyb_sz; | ||
| 824 | extern unsigned struct_sioc_sg_req_sz; | ||
| 825 | extern unsigned struct_sioc_vif_req_sz; | ||
| 826 | extern unsigned struct_smbioc_flags_sz; | ||
| 827 | extern unsigned struct_smbioc_lookup_sz; | ||
| 828 | extern unsigned struct_smbioc_oshare_sz; | ||
| 829 | extern unsigned struct_smbioc_ossn_sz; | ||
| 830 | extern unsigned struct_smbioc_rq_sz; | ||
| 831 | extern unsigned struct_smbioc_rw_sz; | ||
| 832 | extern unsigned struct_spppauthcfg_sz; | ||
| 833 | extern unsigned struct_spppauthfailuresettings_sz; | ||
| 834 | extern unsigned struct_spppauthfailurestats_sz; | ||
| 835 | extern unsigned struct_spppdnsaddrs_sz; | ||
| 836 | extern unsigned struct_spppdnssettings_sz; | ||
| 837 | extern unsigned struct_spppidletimeout_sz; | ||
| 838 | extern unsigned struct_spppkeepalivesettings_sz; | ||
| 839 | extern unsigned struct_sppplcpcfg_sz; | ||
| 840 | extern unsigned struct_spppstatus_sz; | ||
| 841 | extern unsigned struct_spppstatusncp_sz; | ||
| 842 | extern unsigned struct_srt_rt_sz; | ||
| 843 | extern unsigned struct_stic_xinfo_sz; | ||
| 844 | extern unsigned struct_sun_dkctlr_sz; | ||
| 845 | extern unsigned struct_sun_dkgeom_sz; | ||
| 846 | extern unsigned struct_sun_dkpart_sz; | ||
| 847 | extern unsigned struct_synth_info_sz; | ||
| 848 | extern unsigned struct_tbrreq_sz; | ||
| 849 | extern unsigned struct_tchars_sz; | ||
| 850 | extern unsigned struct_termios_sz; | ||
| 851 | extern unsigned struct_timeval_sz; | ||
| 852 | extern unsigned struct_twe_drivecommand_sz; | ||
| 853 | extern unsigned struct_twe_paramcommand_sz; | ||
| 854 | extern unsigned struct_twe_usercommand_sz; | ||
| 855 | extern unsigned struct_ukyopon_identify_sz; | ||
| 856 | extern unsigned struct_urio_command_sz; | ||
| 857 | extern unsigned struct_usb_alt_interface_sz; | ||
| 858 | extern unsigned struct_usb_bulk_ra_wb_opt_sz; | ||
| 859 | extern unsigned struct_usb_config_desc_sz; | ||
| 860 | extern unsigned struct_usb_ctl_report_desc_sz; | ||
| 861 | extern unsigned struct_usb_ctl_report_sz; | ||
| 862 | extern unsigned struct_usb_ctl_request_sz; | ||
| 863 | #if defined(__x86_64__) | ||
| 864 | extern unsigned struct_nvmm_ioc_capability_sz; | ||
| 865 | extern unsigned struct_nvmm_ioc_machine_create_sz; | ||
| 866 | extern unsigned struct_nvmm_ioc_machine_destroy_sz; | ||
| 867 | extern unsigned struct_nvmm_ioc_machine_configure_sz; | ||
| 868 | extern unsigned struct_nvmm_ioc_vcpu_create_sz; | ||
| 869 | extern unsigned struct_nvmm_ioc_vcpu_destroy_sz; | ||
| 870 | extern unsigned struct_nvmm_ioc_vcpu_configure_sz; | ||
| 871 | extern unsigned struct_nvmm_ioc_vcpu_setstate_sz; | ||
| 872 | extern unsigned struct_nvmm_ioc_vcpu_getstate_sz; | ||
| 873 | extern unsigned struct_nvmm_ioc_vcpu_inject_sz; | ||
| 874 | extern unsigned struct_nvmm_ioc_vcpu_run_sz; | ||
| 875 | extern unsigned struct_nvmm_ioc_gpa_map_sz; | ||
| 876 | extern unsigned struct_nvmm_ioc_gpa_unmap_sz; | ||
| 877 | extern unsigned struct_nvmm_ioc_hva_map_sz; | ||
| 878 | extern unsigned struct_nvmm_ioc_hva_unmap_sz; | ||
| 879 | extern unsigned struct_nvmm_ioc_ctl_sz; | ||
| 880 | #endif | ||
| 881 | extern unsigned struct_spi_ioctl_configure_sz; | ||
| 882 | extern unsigned struct_spi_ioctl_transfer_sz; | ||
| 883 | extern unsigned struct_autofs_daemon_request_sz; | ||
| 884 | extern unsigned struct_autofs_daemon_done_sz; | ||
| 885 | extern unsigned struct_sctp_connectx_addrs_sz; | ||
| 886 | extern unsigned struct_usb_device_info_old_sz; | ||
| 887 | extern unsigned struct_usb_device_info_sz; | ||
| 888 | extern unsigned struct_usb_device_stats_sz; | ||
| 889 | extern unsigned struct_usb_endpoint_desc_sz; | ||
| 890 | extern unsigned struct_usb_full_desc_sz; | ||
| 891 | extern unsigned struct_usb_interface_desc_sz; | ||
| 892 | extern unsigned struct_usb_string_desc_sz; | ||
| 893 | extern unsigned struct_utoppy_readfile_sz; | ||
| 894 | extern unsigned struct_utoppy_rename_sz; | ||
| 895 | extern unsigned struct_utoppy_stats_sz; | ||
| 896 | extern unsigned struct_utoppy_writefile_sz; | ||
| 897 | extern unsigned struct_v4l2_audio_sz; | ||
| 898 | extern unsigned struct_v4l2_audioout_sz; | ||
| 899 | extern unsigned struct_v4l2_buffer_sz; | ||
| 900 | extern unsigned struct_v4l2_capability_sz; | ||
| 901 | extern unsigned struct_v4l2_control_sz; | ||
| 902 | extern unsigned struct_v4l2_crop_sz; | ||
| 903 | extern unsigned struct_v4l2_cropcap_sz; | ||
| 904 | extern unsigned struct_v4l2_fmtdesc_sz; | ||
| 905 | extern unsigned struct_v4l2_format_sz; | ||
| 906 | extern unsigned struct_v4l2_framebuffer_sz; | ||
| 907 | extern unsigned struct_v4l2_frequency_sz; | ||
| 908 | extern unsigned struct_v4l2_frmivalenum_sz; | ||
| 909 | extern unsigned struct_v4l2_frmsizeenum_sz; | ||
| 910 | extern unsigned struct_v4l2_input_sz; | ||
| 911 | extern unsigned struct_v4l2_jpegcompression_sz; | ||
| 912 | extern unsigned struct_v4l2_modulator_sz; | ||
| 913 | extern unsigned struct_v4l2_output_sz; | ||
| 914 | extern unsigned struct_v4l2_queryctrl_sz; | ||
| 915 | extern unsigned struct_v4l2_querymenu_sz; | ||
| 916 | extern unsigned struct_v4l2_requestbuffers_sz; | ||
| 917 | extern unsigned struct_v4l2_standard_sz; | ||
| 918 | extern unsigned struct_v4l2_streamparm_sz; | ||
| 919 | extern unsigned struct_v4l2_tuner_sz; | ||
| 920 | extern unsigned struct_vnd_ioctl_sz; | ||
| 921 | extern unsigned struct_vnd_user_sz; | ||
| 922 | extern unsigned struct_vt_stat_sz; | ||
| 923 | extern unsigned struct_wdog_conf_sz; | ||
| 924 | extern unsigned struct_wdog_mode_sz; | ||
| 925 | extern unsigned struct_ipmi_recv_sz; | ||
| 926 | extern unsigned struct_ipmi_req_sz; | ||
| 927 | extern unsigned struct_ipmi_cmdspec_sz; | ||
| 928 | extern unsigned struct_wfq_conf_sz; | ||
| 929 | extern unsigned struct_wfq_getqid_sz; | ||
| 930 | extern unsigned struct_wfq_getstats_sz; | ||
| 931 | extern unsigned struct_wfq_interface_sz; | ||
| 932 | extern unsigned struct_wfq_setweight_sz; | ||
| 933 | extern unsigned struct_winsize_sz; | ||
| 934 | extern unsigned struct_wscons_event_sz; | ||
| 935 | extern unsigned struct_wsdisplay_addscreendata_sz; | ||
| 936 | extern unsigned struct_wsdisplay_char_sz; | ||
| 937 | extern unsigned struct_wsdisplay_cmap_sz; | ||
| 938 | extern unsigned struct_wsdisplay_curpos_sz; | ||
| 939 | extern unsigned struct_wsdisplay_cursor_sz; | ||
| 940 | extern unsigned struct_wsdisplay_delscreendata_sz; | ||
| 941 | extern unsigned struct_wsdisplay_fbinfo_sz; | ||
| 942 | extern unsigned struct_wsdisplay_font_sz; | ||
| 943 | extern unsigned struct_wsdisplay_kbddata_sz; | ||
| 944 | extern unsigned struct_wsdisplay_msgattrs_sz; | ||
| 945 | extern unsigned struct_wsdisplay_param_sz; | ||
| 946 | extern unsigned struct_wsdisplay_scroll_data_sz; | ||
| 947 | extern unsigned struct_wsdisplay_usefontdata_sz; | ||
| 948 | extern unsigned struct_wsdisplayio_blit_sz; | ||
| 949 | extern unsigned struct_wsdisplayio_bus_id_sz; | ||
| 950 | extern unsigned struct_wsdisplayio_edid_info_sz; | ||
| 951 | extern unsigned struct_wsdisplayio_fbinfo_sz; | ||
| 952 | extern unsigned struct_wskbd_bell_data_sz; | ||
| 953 | extern unsigned struct_wskbd_keyrepeat_data_sz; | ||
| 954 | extern unsigned struct_wskbd_map_data_sz; | ||
| 955 | extern unsigned struct_wskbd_scroll_data_sz; | ||
| 956 | extern unsigned struct_wsmouse_calibcoords_sz; | ||
| 957 | extern unsigned struct_wsmouse_id_sz; | ||
| 958 | extern unsigned struct_wsmouse_repeat_sz; | ||
| 959 | extern unsigned struct_wsmux_device_list_sz; | ||
| 960 | extern unsigned struct_wsmux_device_sz; | ||
| 961 | extern unsigned struct_xd_iocmd_sz; | ||
| 962 | |||
| 963 | extern unsigned struct_scsireq_sz; | ||
| 964 | extern unsigned struct_tone_sz; | ||
| 965 | extern unsigned union_twe_statrequest_sz; | ||
| 966 | extern unsigned struct_usb_device_descriptor_sz; | ||
| 967 | extern unsigned struct_vt_mode_sz; | ||
| 968 | extern unsigned struct__old_mixer_info_sz; | ||
| 969 | extern unsigned struct__agp_allocate_sz; | ||
| 970 | extern unsigned struct__agp_bind_sz; | ||
| 971 | extern unsigned struct__agp_info_sz; | ||
| 972 | extern unsigned struct__agp_setup_sz; | ||
| 973 | extern unsigned struct__agp_unbind_sz; | ||
| 974 | extern unsigned struct_atareq_sz; | ||
| 975 | extern unsigned struct_cpustate_sz; | ||
| 976 | extern unsigned struct_dmx_caps_sz; | ||
| 977 | extern unsigned enum_dmx_source_sz; | ||
| 978 | extern unsigned union_dvd_authinfo_sz; | ||
| 979 | extern unsigned union_dvd_struct_sz; | ||
| 980 | extern unsigned enum_v4l2_priority_sz; | ||
| 981 | extern unsigned struct_envsys_basic_info_sz; | ||
| 982 | extern unsigned struct_envsys_tre_data_sz; | ||
| 983 | extern unsigned enum_fe_sec_mini_cmd_sz; | ||
| 984 | extern unsigned enum_fe_sec_tone_mode_sz; | ||
| 985 | extern unsigned enum_fe_sec_voltage_sz; | ||
| 986 | extern unsigned enum_fe_status_sz; | ||
| 987 | extern unsigned struct_gdt_ctrt_sz; | ||
| 988 | extern unsigned struct_gdt_event_sz; | ||
| 989 | extern unsigned struct_gdt_osv_sz; | ||
| 990 | extern unsigned struct_gdt_rescan_sz; | ||
| 991 | extern unsigned struct_gdt_statist_sz; | ||
| 992 | extern unsigned struct_gdt_ucmd_sz; | ||
| 993 | extern unsigned struct_iscsi_conn_status_parameters_sz; | ||
| 994 | extern unsigned struct_iscsi_get_version_parameters_sz; | ||
| 995 | extern unsigned struct_iscsi_iocommand_parameters_sz; | ||
| 996 | extern unsigned struct_iscsi_login_parameters_sz; | ||
| 997 | extern unsigned struct_iscsi_logout_parameters_sz; | ||
| 998 | extern unsigned struct_iscsi_register_event_parameters_sz; | ||
| 999 | extern unsigned struct_iscsi_remove_parameters_sz; | ||
| 1000 | extern unsigned struct_iscsi_send_targets_parameters_sz; | ||
| 1001 | extern unsigned struct_iscsi_set_node_name_parameters_sz; | ||
| 1002 | extern unsigned struct_iscsi_wait_event_parameters_sz; | ||
| 1003 | extern unsigned struct_isp_stats_sz; | ||
| 1004 | extern unsigned struct_lsenable_sz; | ||
| 1005 | extern unsigned struct_lsdisable_sz; | ||
| 1006 | extern unsigned struct_audio_format_query_sz; | ||
| 1007 | extern unsigned struct_mixer_ctrl_sz; | ||
| 1008 | extern unsigned struct_mixer_devinfo_sz; | ||
| 1009 | extern unsigned struct_mpu_command_rec_sz; | ||
| 1010 | extern unsigned struct_rndstat_sz; | ||
| 1011 | extern unsigned struct_rndstat_name_sz; | ||
| 1012 | extern unsigned struct_rndctl_sz; | ||
| 1013 | extern unsigned struct_rnddata_sz; | ||
| 1014 | extern unsigned struct_rndpoolstat_sz; | ||
| 1015 | extern unsigned struct_rndstat_est_sz; | ||
| 1016 | extern unsigned struct_rndstat_est_name_sz; | ||
| 1017 | extern unsigned struct_pps_params_sz; | ||
| 1018 | extern unsigned struct_pps_info_sz; | ||
| 1019 | extern unsigned struct_mixer_info_sz; | ||
| 1020 | extern unsigned struct_RF_SparetWait_sz; | ||
| 1021 | extern unsigned struct_RF_ComponentLabel_sz; | ||
| 1022 | extern unsigned struct_RF_SingleComponent_sz; | ||
| 1023 | extern unsigned struct_RF_ProgressInfo_sz; | ||
| 1024 | extern unsigned struct_nvlist_ref_sz; | ||
| 1025 | extern unsigned struct_StringList_sz; | ||
| 1026 | |||
| 1027 | |||
| 1028 | // A special value to mark ioctls that are not present on the target platform, | ||
| 1029 | // when it can not be determined without including any system headers. | ||
| 1030 | extern const unsigned IOCTL_NOT_PRESENT; | ||
| 1031 | |||
| 1032 | |||
| 1033 | extern unsigned IOCTL_AFM_ADDFMAP; | ||
| 1034 | extern unsigned IOCTL_AFM_DELFMAP; | ||
| 1035 | extern unsigned IOCTL_AFM_CLEANFMAP; | ||
| 1036 | extern unsigned IOCTL_AFM_GETFMAP; | ||
| 1037 | extern unsigned IOCTL_ALTQGTYPE; | ||
| 1038 | extern unsigned IOCTL_ALTQTBRSET; | ||
| 1039 | extern unsigned IOCTL_ALTQTBRGET; | ||
| 1040 | extern unsigned IOCTL_BLUE_IF_ATTACH; | ||
| 1041 | extern unsigned IOCTL_BLUE_IF_DETACH; | ||
| 1042 | extern unsigned IOCTL_BLUE_ENABLE; | ||
| 1043 | extern unsigned IOCTL_BLUE_DISABLE; | ||
| 1044 | extern unsigned IOCTL_BLUE_CONFIG; | ||
| 1045 | extern unsigned IOCTL_BLUE_GETSTATS; | ||
| 1046 | extern unsigned IOCTL_CBQ_IF_ATTACH; | ||
| 1047 | extern unsigned IOCTL_CBQ_IF_DETACH; | ||
| 1048 | extern unsigned IOCTL_CBQ_ENABLE; | ||
| 1049 | extern unsigned IOCTL_CBQ_DISABLE; | ||
| 1050 | extern unsigned IOCTL_CBQ_CLEAR_HIERARCHY; | ||
| 1051 | extern unsigned IOCTL_CBQ_ADD_CLASS; | ||
| 1052 | extern unsigned IOCTL_CBQ_DEL_CLASS; | ||
| 1053 | extern unsigned IOCTL_CBQ_MODIFY_CLASS; | ||
| 1054 | extern unsigned IOCTL_CBQ_ADD_FILTER; | ||
| 1055 | extern unsigned IOCTL_CBQ_DEL_FILTER; | ||
| 1056 | extern unsigned IOCTL_CBQ_GETSTATS; | ||
| 1057 | extern unsigned IOCTL_CDNR_IF_ATTACH; | ||
| 1058 | extern unsigned IOCTL_CDNR_IF_DETACH; | ||
| 1059 | extern unsigned IOCTL_CDNR_ENABLE; | ||
| 1060 | extern unsigned IOCTL_CDNR_DISABLE; | ||
| 1061 | extern unsigned IOCTL_CDNR_ADD_FILTER; | ||
| 1062 | extern unsigned IOCTL_CDNR_DEL_FILTER; | ||
| 1063 | extern unsigned IOCTL_CDNR_GETSTATS; | ||
| 1064 | extern unsigned IOCTL_CDNR_ADD_ELEM; | ||
| 1065 | extern unsigned IOCTL_CDNR_DEL_ELEM; | ||
| 1066 | extern unsigned IOCTL_CDNR_ADD_TBM; | ||
| 1067 | extern unsigned IOCTL_CDNR_MOD_TBM; | ||
| 1068 | extern unsigned IOCTL_CDNR_TBM_STATS; | ||
| 1069 | extern unsigned IOCTL_CDNR_ADD_TCM; | ||
| 1070 | extern unsigned IOCTL_CDNR_MOD_TCM; | ||
| 1071 | extern unsigned IOCTL_CDNR_TCM_STATS; | ||
| 1072 | extern unsigned IOCTL_CDNR_ADD_TSW; | ||
| 1073 | extern unsigned IOCTL_CDNR_MOD_TSW; | ||
| 1074 | extern unsigned IOCTL_FIFOQ_IF_ATTACH; | ||
| 1075 | extern unsigned IOCTL_FIFOQ_IF_DETACH; | ||
| 1076 | extern unsigned IOCTL_FIFOQ_ENABLE; | ||
| 1077 | extern unsigned IOCTL_FIFOQ_DISABLE; | ||
| 1078 | extern unsigned IOCTL_FIFOQ_CONFIG; | ||
| 1079 | extern unsigned IOCTL_FIFOQ_GETSTATS; | ||
| 1080 | extern unsigned IOCTL_HFSC_IF_ATTACH; | ||
| 1081 | extern unsigned IOCTL_HFSC_IF_DETACH; | ||
| 1082 | extern unsigned IOCTL_HFSC_ENABLE; | ||
| 1083 | extern unsigned IOCTL_HFSC_DISABLE; | ||
| 1084 | extern unsigned IOCTL_HFSC_CLEAR_HIERARCHY; | ||
| 1085 | extern unsigned IOCTL_HFSC_ADD_CLASS; | ||
| 1086 | extern unsigned IOCTL_HFSC_DEL_CLASS; | ||
| 1087 | extern unsigned IOCTL_HFSC_MOD_CLASS; | ||
| 1088 | extern unsigned IOCTL_HFSC_ADD_FILTER; | ||
| 1089 | extern unsigned IOCTL_HFSC_DEL_FILTER; | ||
| 1090 | extern unsigned IOCTL_HFSC_GETSTATS; | ||
| 1091 | extern unsigned IOCTL_JOBS_IF_ATTACH; | ||
| 1092 | extern unsigned IOCTL_JOBS_IF_DETACH; | ||
| 1093 | extern unsigned IOCTL_JOBS_ENABLE; | ||
| 1094 | extern unsigned IOCTL_JOBS_DISABLE; | ||
| 1095 | extern unsigned IOCTL_JOBS_CLEAR; | ||
| 1096 | extern unsigned IOCTL_JOBS_ADD_CLASS; | ||
| 1097 | extern unsigned IOCTL_JOBS_DEL_CLASS; | ||
| 1098 | extern unsigned IOCTL_JOBS_MOD_CLASS; | ||
| 1099 | extern unsigned IOCTL_JOBS_ADD_FILTER; | ||
| 1100 | extern unsigned IOCTL_JOBS_DEL_FILTER; | ||
| 1101 | extern unsigned IOCTL_JOBS_GETSTATS; | ||
| 1102 | extern unsigned IOCTL_PRIQ_IF_ATTACH; | ||
| 1103 | extern unsigned IOCTL_PRIQ_IF_DETACH; | ||
| 1104 | extern unsigned IOCTL_PRIQ_ENABLE; | ||
| 1105 | extern unsigned IOCTL_PRIQ_DISABLE; | ||
| 1106 | extern unsigned IOCTL_PRIQ_CLEAR; | ||
| 1107 | extern unsigned IOCTL_PRIQ_ADD_CLASS; | ||
| 1108 | extern unsigned IOCTL_PRIQ_DEL_CLASS; | ||
| 1109 | extern unsigned IOCTL_PRIQ_MOD_CLASS; | ||
| 1110 | extern unsigned IOCTL_PRIQ_ADD_FILTER; | ||
| 1111 | extern unsigned IOCTL_PRIQ_DEL_FILTER; | ||
| 1112 | extern unsigned IOCTL_PRIQ_GETSTATS; | ||
| 1113 | extern unsigned IOCTL_RED_IF_ATTACH; | ||
| 1114 | extern unsigned IOCTL_RED_IF_DETACH; | ||
| 1115 | extern unsigned IOCTL_RED_ENABLE; | ||
| 1116 | extern unsigned IOCTL_RED_DISABLE; | ||
| 1117 | extern unsigned IOCTL_RED_CONFIG; | ||
| 1118 | extern unsigned IOCTL_RED_GETSTATS; | ||
| 1119 | extern unsigned IOCTL_RED_SETDEFAULTS; | ||
| 1120 | extern unsigned IOCTL_RIO_IF_ATTACH; | ||
| 1121 | extern unsigned IOCTL_RIO_IF_DETACH; | ||
| 1122 | extern unsigned IOCTL_RIO_ENABLE; | ||
| 1123 | extern unsigned IOCTL_RIO_DISABLE; | ||
| 1124 | extern unsigned IOCTL_RIO_CONFIG; | ||
| 1125 | extern unsigned IOCTL_RIO_GETSTATS; | ||
| 1126 | extern unsigned IOCTL_RIO_SETDEFAULTS; | ||
| 1127 | extern unsigned IOCTL_WFQ_IF_ATTACH; | ||
| 1128 | extern unsigned IOCTL_WFQ_IF_DETACH; | ||
| 1129 | extern unsigned IOCTL_WFQ_ENABLE; | ||
| 1130 | extern unsigned IOCTL_WFQ_DISABLE; | ||
| 1131 | extern unsigned IOCTL_WFQ_CONFIG; | ||
| 1132 | extern unsigned IOCTL_WFQ_GET_STATS; | ||
| 1133 | extern unsigned IOCTL_WFQ_GET_QID; | ||
| 1134 | extern unsigned IOCTL_WFQ_SET_WEIGHT; | ||
| 1135 | extern unsigned IOCTL_CRIOGET; | ||
| 1136 | extern unsigned IOCTL_CIOCFSESSION; | ||
| 1137 | extern unsigned IOCTL_CIOCKEY; | ||
| 1138 | extern unsigned IOCTL_CIOCNFKEYM; | ||
| 1139 | extern unsigned IOCTL_CIOCNFSESSION; | ||
| 1140 | extern unsigned IOCTL_CIOCNCRYPTRETM; | ||
| 1141 | extern unsigned IOCTL_CIOCNCRYPTRET; | ||
| 1142 | extern unsigned IOCTL_CIOCGSESSION; | ||
| 1143 | extern unsigned IOCTL_CIOCNGSESSION; | ||
| 1144 | extern unsigned IOCTL_CIOCCRYPT; | ||
| 1145 | extern unsigned IOCTL_CIOCNCRYPTM; | ||
| 1146 | extern unsigned IOCTL_CIOCASYMFEAT; | ||
| 1147 | extern unsigned IOCTL_APM_IOC_REJECT; | ||
| 1148 | extern unsigned IOCTL_APM_IOC_STANDBY; | ||
| 1149 | extern unsigned IOCTL_APM_IOC_SUSPEND; | ||
| 1150 | extern unsigned IOCTL_OAPM_IOC_GETPOWER; | ||
| 1151 | extern unsigned IOCTL_APM_IOC_GETPOWER; | ||
| 1152 | extern unsigned IOCTL_APM_IOC_NEXTEVENT; | ||
| 1153 | extern unsigned IOCTL_APM_IOC_DEV_CTL; | ||
| 1154 | extern unsigned IOCTL_NETBSD_DM_IOCTL; | ||
| 1155 | extern unsigned IOCTL_DMIO_SETFUNC; | ||
| 1156 | extern unsigned IOCTL_DMX_START; | ||
| 1157 | extern unsigned IOCTL_DMX_STOP; | ||
| 1158 | extern unsigned IOCTL_DMX_SET_FILTER; | ||
| 1159 | extern unsigned IOCTL_DMX_SET_PES_FILTER; | ||
| 1160 | extern unsigned IOCTL_DMX_SET_BUFFER_SIZE; | ||
| 1161 | extern unsigned IOCTL_DMX_GET_STC; | ||
| 1162 | extern unsigned IOCTL_DMX_ADD_PID; | ||
| 1163 | extern unsigned IOCTL_DMX_REMOVE_PID; | ||
| 1164 | extern unsigned IOCTL_DMX_GET_CAPS; | ||
| 1165 | extern unsigned IOCTL_DMX_SET_SOURCE; | ||
| 1166 | extern unsigned IOCTL_FE_READ_STATUS; | ||
| 1167 | extern unsigned IOCTL_FE_READ_BER; | ||
| 1168 | extern unsigned IOCTL_FE_READ_SNR; | ||
| 1169 | extern unsigned IOCTL_FE_READ_SIGNAL_STRENGTH; | ||
| 1170 | extern unsigned IOCTL_FE_READ_UNCORRECTED_BLOCKS; | ||
| 1171 | extern unsigned IOCTL_FE_SET_FRONTEND; | ||
| 1172 | extern unsigned IOCTL_FE_GET_FRONTEND; | ||
| 1173 | extern unsigned IOCTL_FE_GET_EVENT; | ||
| 1174 | extern unsigned IOCTL_FE_GET_INFO; | ||
| 1175 | extern unsigned IOCTL_FE_DISEQC_RESET_OVERLOAD; | ||
| 1176 | extern unsigned IOCTL_FE_DISEQC_SEND_MASTER_CMD; | ||
| 1177 | extern unsigned IOCTL_FE_DISEQC_RECV_SLAVE_REPLY; | ||
| 1178 | extern unsigned IOCTL_FE_DISEQC_SEND_BURST; | ||
| 1179 | extern unsigned IOCTL_FE_SET_TONE; | ||
| 1180 | extern unsigned IOCTL_FE_SET_VOLTAGE; | ||
| 1181 | extern unsigned IOCTL_FE_ENABLE_HIGH_LNB_VOLTAGE; | ||
| 1182 | extern unsigned IOCTL_FE_SET_FRONTEND_TUNE_MODE; | ||
| 1183 | extern unsigned IOCTL_FE_DISHNETWORK_SEND_LEGACY_CMD; | ||
| 1184 | extern unsigned IOCTL_FILEMON_SET_FD; | ||
| 1185 | extern unsigned IOCTL_FILEMON_SET_PID; | ||
| 1186 | extern unsigned IOCTL_HDAUDIO_FGRP_INFO; | ||
| 1187 | extern unsigned IOCTL_HDAUDIO_FGRP_GETCONFIG; | ||
| 1188 | extern unsigned IOCTL_HDAUDIO_FGRP_SETCONFIG; | ||
| 1189 | extern unsigned IOCTL_HDAUDIO_FGRP_WIDGET_INFO; | ||
| 1190 | extern unsigned IOCTL_HDAUDIO_FGRP_CODEC_INFO; | ||
| 1191 | extern unsigned IOCTL_HDAUDIO_AFG_WIDGET_INFO; | ||
| 1192 | extern unsigned IOCTL_HDAUDIO_AFG_CODEC_INFO; | ||
| 1193 | extern unsigned IOCTL_CEC_GET_PHYS_ADDR; | ||
| 1194 | extern unsigned IOCTL_CEC_GET_LOG_ADDRS; | ||
| 1195 | extern unsigned IOCTL_CEC_SET_LOG_ADDRS; | ||
| 1196 | extern unsigned IOCTL_CEC_GET_VENDOR_ID; | ||
| 1197 | extern unsigned IOCTL_HPCFBIO_GCONF; | ||
| 1198 | extern unsigned IOCTL_HPCFBIO_SCONF; | ||
| 1199 | extern unsigned IOCTL_HPCFBIO_GDSPCONF; | ||
| 1200 | extern unsigned IOCTL_HPCFBIO_SDSPCONF; | ||
| 1201 | extern unsigned IOCTL_HPCFBIO_GOP; | ||
| 1202 | extern unsigned IOCTL_HPCFBIO_SOP; | ||
| 1203 | extern unsigned IOCTL_IOPIOCPT; | ||
| 1204 | extern unsigned IOCTL_IOPIOCGLCT; | ||
| 1205 | extern unsigned IOCTL_IOPIOCGSTATUS; | ||
| 1206 | extern unsigned IOCTL_IOPIOCRECONFIG; | ||
| 1207 | extern unsigned IOCTL_IOPIOCGTIDMAP; | ||
| 1208 | extern unsigned IOCTL_SIOCGATHSTATS; | ||
| 1209 | extern unsigned IOCTL_SIOCGATHDIAG; | ||
| 1210 | extern unsigned IOCTL_METEORCAPTUR; | ||
| 1211 | extern unsigned IOCTL_METEORCAPFRM; | ||
| 1212 | extern unsigned IOCTL_METEORSETGEO; | ||
| 1213 | extern unsigned IOCTL_METEORGETGEO; | ||
| 1214 | extern unsigned IOCTL_METEORSTATUS; | ||
| 1215 | extern unsigned IOCTL_METEORSHUE; | ||
| 1216 | extern unsigned IOCTL_METEORGHUE; | ||
| 1217 | extern unsigned IOCTL_METEORSFMT; | ||
| 1218 | extern unsigned IOCTL_METEORGFMT; | ||
| 1219 | extern unsigned IOCTL_METEORSINPUT; | ||
| 1220 | extern unsigned IOCTL_METEORGINPUT; | ||
| 1221 | extern unsigned IOCTL_METEORSCHCV; | ||
| 1222 | extern unsigned IOCTL_METEORGCHCV; | ||
| 1223 | extern unsigned IOCTL_METEORSCOUNT; | ||
| 1224 | extern unsigned IOCTL_METEORGCOUNT; | ||
| 1225 | extern unsigned IOCTL_METEORSFPS; | ||
| 1226 | extern unsigned IOCTL_METEORGFPS; | ||
| 1227 | extern unsigned IOCTL_METEORSSIGNAL; | ||
| 1228 | extern unsigned IOCTL_METEORGSIGNAL; | ||
| 1229 | extern unsigned IOCTL_METEORSVIDEO; | ||
| 1230 | extern unsigned IOCTL_METEORGVIDEO; | ||
| 1231 | extern unsigned IOCTL_METEORSBRIG; | ||
| 1232 | extern unsigned IOCTL_METEORGBRIG; | ||
| 1233 | extern unsigned IOCTL_METEORSCSAT; | ||
| 1234 | extern unsigned IOCTL_METEORGCSAT; | ||
| 1235 | extern unsigned IOCTL_METEORSCONT; | ||
| 1236 | extern unsigned IOCTL_METEORGCONT; | ||
| 1237 | extern unsigned IOCTL_METEORSHWS; | ||
| 1238 | extern unsigned IOCTL_METEORGHWS; | ||
| 1239 | extern unsigned IOCTL_METEORSVWS; | ||
| 1240 | extern unsigned IOCTL_METEORGVWS; | ||
| 1241 | extern unsigned IOCTL_METEORSTS; | ||
| 1242 | extern unsigned IOCTL_METEORGTS; | ||
| 1243 | extern unsigned IOCTL_TVTUNER_SETCHNL; | ||
| 1244 | extern unsigned IOCTL_TVTUNER_GETCHNL; | ||
| 1245 | extern unsigned IOCTL_TVTUNER_SETTYPE; | ||
| 1246 | extern unsigned IOCTL_TVTUNER_GETTYPE; | ||
| 1247 | extern unsigned IOCTL_TVTUNER_GETSTATUS; | ||
| 1248 | extern unsigned IOCTL_TVTUNER_SETFREQ; | ||
| 1249 | extern unsigned IOCTL_TVTUNER_GETFREQ; | ||
| 1250 | extern unsigned IOCTL_TVTUNER_SETAFC; | ||
| 1251 | extern unsigned IOCTL_TVTUNER_GETAFC; | ||
| 1252 | extern unsigned IOCTL_RADIO_SETMODE; | ||
| 1253 | extern unsigned IOCTL_RADIO_GETMODE; | ||
| 1254 | extern unsigned IOCTL_RADIO_SETFREQ; | ||
| 1255 | extern unsigned IOCTL_RADIO_GETFREQ; | ||
| 1256 | extern unsigned IOCTL_METEORSACTPIXFMT; | ||
| 1257 | extern unsigned IOCTL_METEORGACTPIXFMT; | ||
| 1258 | extern unsigned IOCTL_METEORGSUPPIXFMT; | ||
| 1259 | extern unsigned IOCTL_TVTUNER_GETCHNLSET; | ||
| 1260 | extern unsigned IOCTL_REMOTE_GETKEY; | ||
| 1261 | extern unsigned IOCTL_GDT_IOCTL_GENERAL; | ||
| 1262 | extern unsigned IOCTL_GDT_IOCTL_DRVERS; | ||
| 1263 | extern unsigned IOCTL_GDT_IOCTL_CTRTYPE; | ||
| 1264 | extern unsigned IOCTL_GDT_IOCTL_OSVERS; | ||
| 1265 | extern unsigned IOCTL_GDT_IOCTL_CTRCNT; | ||
| 1266 | extern unsigned IOCTL_GDT_IOCTL_EVENT; | ||
| 1267 | extern unsigned IOCTL_GDT_IOCTL_STATIST; | ||
| 1268 | extern unsigned IOCTL_GDT_IOCTL_RESCAN; | ||
| 1269 | extern unsigned IOCTL_ISP_SDBLEV; | ||
| 1270 | extern unsigned IOCTL_ISP_RESETHBA; | ||
| 1271 | extern unsigned IOCTL_ISP_RESCAN; | ||
| 1272 | extern unsigned IOCTL_ISP_SETROLE; | ||
| 1273 | extern unsigned IOCTL_ISP_GETROLE; | ||
| 1274 | extern unsigned IOCTL_ISP_GET_STATS; | ||
| 1275 | extern unsigned IOCTL_ISP_CLR_STATS; | ||
| 1276 | extern unsigned IOCTL_ISP_FC_LIP; | ||
| 1277 | extern unsigned IOCTL_ISP_FC_GETDINFO; | ||
| 1278 | extern unsigned IOCTL_ISP_GET_FW_CRASH_DUMP; | ||
| 1279 | extern unsigned IOCTL_ISP_FORCE_CRASH_DUMP; | ||
| 1280 | extern unsigned IOCTL_ISP_FC_GETHINFO; | ||
| 1281 | extern unsigned IOCTL_ISP_TSK_MGMT; | ||
| 1282 | extern unsigned IOCTL_ISP_FC_GETDLIST; | ||
| 1283 | extern unsigned IOCTL_MLXD_STATUS; | ||
| 1284 | extern unsigned IOCTL_MLXD_CHECKASYNC; | ||
| 1285 | extern unsigned IOCTL_MLXD_DETACH; | ||
| 1286 | extern unsigned IOCTL_MLX_RESCAN_DRIVES; | ||
| 1287 | extern unsigned IOCTL_MLX_PAUSE_CHANNEL; | ||
| 1288 | extern unsigned IOCTL_MLX_COMMAND; | ||
| 1289 | extern unsigned IOCTL_MLX_REBUILDASYNC; | ||
| 1290 | extern unsigned IOCTL_MLX_REBUILDSTAT; | ||
| 1291 | extern unsigned IOCTL_MLX_GET_SYSDRIVE; | ||
| 1292 | extern unsigned IOCTL_MLX_GET_CINFO; | ||
| 1293 | extern unsigned IOCTL_NVME_PASSTHROUGH_CMD; | ||
| 1294 | extern unsigned IOCTL_FWCFGIO_SET_INDEX; | ||
| 1295 | extern unsigned IOCTL_IRDA_RESET_PARAMS; | ||
| 1296 | extern unsigned IOCTL_IRDA_SET_PARAMS; | ||
| 1297 | extern unsigned IOCTL_IRDA_GET_SPEEDMASK; | ||
| 1298 | extern unsigned IOCTL_IRDA_GET_TURNAROUNDMASK; | ||
| 1299 | extern unsigned IOCTL_IRFRAMETTY_GET_DEVICE; | ||
| 1300 | extern unsigned IOCTL_IRFRAMETTY_GET_DONGLE; | ||
| 1301 | extern unsigned IOCTL_IRFRAMETTY_SET_DONGLE; | ||
| 1302 | extern unsigned IOCTL_ISV_CMD; | ||
| 1303 | extern unsigned IOCTL_WTQICMD; | ||
| 1304 | extern unsigned IOCTL_ISCSI_GET_VERSION; | ||
| 1305 | extern unsigned IOCTL_ISCSI_LOGIN; | ||
| 1306 | extern unsigned IOCTL_ISCSI_LOGOUT; | ||
| 1307 | extern unsigned IOCTL_ISCSI_ADD_CONNECTION; | ||
| 1308 | extern unsigned IOCTL_ISCSI_RESTORE_CONNECTION; | ||
| 1309 | extern unsigned IOCTL_ISCSI_REMOVE_CONNECTION; | ||
| 1310 | extern unsigned IOCTL_ISCSI_CONNECTION_STATUS; | ||
| 1311 | extern unsigned IOCTL_ISCSI_SEND_TARGETS; | ||
| 1312 | extern unsigned IOCTL_ISCSI_SET_NODE_NAME; | ||
| 1313 | extern unsigned IOCTL_ISCSI_IO_COMMAND; | ||
| 1314 | extern unsigned IOCTL_ISCSI_REGISTER_EVENT; | ||
| 1315 | extern unsigned IOCTL_ISCSI_DEREGISTER_EVENT; | ||
| 1316 | extern unsigned IOCTL_ISCSI_WAIT_EVENT; | ||
| 1317 | extern unsigned IOCTL_ISCSI_POLL_EVENT; | ||
| 1318 | extern unsigned IOCTL_OFIOCGET; | ||
| 1319 | extern unsigned IOCTL_OFIOCSET; | ||
| 1320 | extern unsigned IOCTL_OFIOCNEXTPROP; | ||
| 1321 | extern unsigned IOCTL_OFIOCGETOPTNODE; | ||
| 1322 | extern unsigned IOCTL_OFIOCGETNEXT; | ||
| 1323 | extern unsigned IOCTL_OFIOCGETCHILD; | ||
| 1324 | extern unsigned IOCTL_OFIOCFINDDEVICE; | ||
| 1325 | extern unsigned IOCTL_AMR_IO_VERSION; | ||
| 1326 | extern unsigned IOCTL_AMR_IO_COMMAND; | ||
| 1327 | extern unsigned IOCTL_MLYIO_COMMAND; | ||
| 1328 | extern unsigned IOCTL_MLYIO_HEALTH; | ||
| 1329 | extern unsigned IOCTL_PCI_IOC_CFGREAD; | ||
| 1330 | extern unsigned IOCTL_PCI_IOC_CFGWRITE; | ||
| 1331 | extern unsigned IOCTL_PCI_IOC_BDF_CFGREAD; | ||
| 1332 | extern unsigned IOCTL_PCI_IOC_BDF_CFGWRITE; | ||
| 1333 | extern unsigned IOCTL_PCI_IOC_BUSINFO; | ||
| 1334 | extern unsigned IOCTL_PCI_IOC_DRVNAME; | ||
| 1335 | extern unsigned IOCTL_PCI_IOC_DRVNAMEONBUS; | ||
| 1336 | extern unsigned IOCTL_TWEIO_COMMAND; | ||
| 1337 | extern unsigned IOCTL_TWEIO_STATS; | ||
| 1338 | extern unsigned IOCTL_TWEIO_AEN_POLL; | ||
| 1339 | extern unsigned IOCTL_TWEIO_AEN_WAIT; | ||
| 1340 | extern unsigned IOCTL_TWEIO_SET_PARAM; | ||
| 1341 | extern unsigned IOCTL_TWEIO_GET_PARAM; | ||
| 1342 | extern unsigned IOCTL_TWEIO_RESET; | ||
| 1343 | extern unsigned IOCTL_TWEIO_ADD_UNIT; | ||
| 1344 | extern unsigned IOCTL_TWEIO_DEL_UNIT; | ||
| 1345 | extern unsigned IOCTL_SIOCSCNWDOMAIN; | ||
| 1346 | extern unsigned IOCTL_SIOCGCNWDOMAIN; | ||
| 1347 | extern unsigned IOCTL_SIOCSCNWKEY; | ||
| 1348 | extern unsigned IOCTL_SIOCGCNWSTATUS; | ||
| 1349 | extern unsigned IOCTL_SIOCGCNWSTATS; | ||
| 1350 | extern unsigned IOCTL_SIOCGCNWTRAIL; | ||
| 1351 | extern unsigned IOCTL_SIOCGRAYSIGLEV; | ||
| 1352 | extern unsigned IOCTL_RAIDFRAME_SHUTDOWN; | ||
| 1353 | extern unsigned IOCTL_RAIDFRAME_TUR; | ||
| 1354 | extern unsigned IOCTL_RAIDFRAME_FAIL_DISK; | ||
| 1355 | extern unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS; | ||
| 1356 | extern unsigned IOCTL_RAIDFRAME_REWRITEPARITY; | ||
| 1357 | extern unsigned IOCTL_RAIDFRAME_COPYBACK; | ||
| 1358 | extern unsigned IOCTL_RAIDFRAME_SPARET_WAIT; | ||
| 1359 | extern unsigned IOCTL_RAIDFRAME_SEND_SPARET; | ||
| 1360 | extern unsigned IOCTL_RAIDFRAME_ABORT_SPARET_WAIT; | ||
| 1361 | extern unsigned IOCTL_RAIDFRAME_START_ATRACE; | ||
| 1362 | extern unsigned IOCTL_RAIDFRAME_STOP_ATRACE; | ||
| 1363 | extern unsigned IOCTL_RAIDFRAME_GET_SIZE; | ||
| 1364 | extern unsigned IOCTL_RAIDFRAME_RESET_ACCTOTALS; | ||
| 1365 | extern unsigned IOCTL_RAIDFRAME_KEEP_ACCTOTALS; | ||
| 1366 | extern unsigned IOCTL_RAIDFRAME_GET_COMPONENT_LABEL; | ||
| 1367 | extern unsigned IOCTL_RAIDFRAME_SET_COMPONENT_LABEL; | ||
| 1368 | extern unsigned IOCTL_RAIDFRAME_INIT_LABELS; | ||
| 1369 | extern unsigned IOCTL_RAIDFRAME_ADD_HOT_SPARE; | ||
| 1370 | extern unsigned IOCTL_RAIDFRAME_REMOVE_HOT_SPARE; | ||
| 1371 | extern unsigned IOCTL_RAIDFRAME_REBUILD_IN_PLACE; | ||
| 1372 | extern unsigned IOCTL_RAIDFRAME_CHECK_PARITY; | ||
| 1373 | extern unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS; | ||
| 1374 | extern unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS; | ||
| 1375 | extern unsigned IOCTL_RAIDFRAME_SET_AUTOCONFIG; | ||
| 1376 | extern unsigned IOCTL_RAIDFRAME_SET_ROOT; | ||
| 1377 | extern unsigned IOCTL_RAIDFRAME_DELETE_COMPONENT; | ||
| 1378 | extern unsigned IOCTL_RAIDFRAME_INCORPORATE_HOT_SPARE; | ||
| 1379 | extern unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS_EXT; | ||
| 1380 | extern unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT; | ||
| 1381 | extern unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS_EXT; | ||
| 1382 | extern unsigned IOCTL_RAIDFRAME_CONFIGURE; | ||
| 1383 | extern unsigned IOCTL_RAIDFRAME_GET_INFO; | ||
| 1384 | extern unsigned IOCTL_RAIDFRAME_PARITYMAP_STATUS; | ||
| 1385 | extern unsigned IOCTL_RAIDFRAME_PARITYMAP_GET_DISABLE; | ||
| 1386 | extern unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_DISABLE; | ||
| 1387 | extern unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_PARAMS; | ||
| 1388 | extern unsigned IOCTL_RAIDFRAME_SET_LAST_UNIT; | ||
| 1389 | extern unsigned IOCTL_MBPPIOCSPARAM; | ||
| 1390 | extern unsigned IOCTL_MBPPIOCGPARAM; | ||
| 1391 | extern unsigned IOCTL_MBPPIOCGSTAT; | ||
| 1392 | extern unsigned IOCTL_SESIOC_GETNOBJ; | ||
| 1393 | extern unsigned IOCTL_SESIOC_GETOBJMAP; | ||
| 1394 | extern unsigned IOCTL_SESIOC_GETENCSTAT; | ||
| 1395 | extern unsigned IOCTL_SESIOC_SETENCSTAT; | ||
| 1396 | extern unsigned IOCTL_SESIOC_GETOBJSTAT; | ||
| 1397 | extern unsigned IOCTL_SESIOC_SETOBJSTAT; | ||
| 1398 | extern unsigned IOCTL_SESIOC_GETTEXT; | ||
| 1399 | extern unsigned IOCTL_SESIOC_INIT; | ||
| 1400 | extern unsigned IOCTL_SUN_DKIOCGGEOM; | ||
| 1401 | extern unsigned IOCTL_SUN_DKIOCINFO; | ||
| 1402 | extern unsigned IOCTL_SUN_DKIOCGPART; | ||
| 1403 | extern unsigned IOCTL_FBIOGTYPE; | ||
| 1404 | extern unsigned IOCTL_FBIOPUTCMAP; | ||
| 1405 | extern unsigned IOCTL_FBIOGETCMAP; | ||
| 1406 | extern unsigned IOCTL_FBIOGATTR; | ||
| 1407 | extern unsigned IOCTL_FBIOSVIDEO; | ||
| 1408 | extern unsigned IOCTL_FBIOGVIDEO; | ||
| 1409 | extern unsigned IOCTL_FBIOSCURSOR; | ||
| 1410 | extern unsigned IOCTL_FBIOGCURSOR; | ||
| 1411 | extern unsigned IOCTL_FBIOSCURPOS; | ||
| 1412 | extern unsigned IOCTL_FBIOGCURPOS; | ||
| 1413 | extern unsigned IOCTL_FBIOGCURMAX; | ||
| 1414 | extern unsigned IOCTL_KIOCTRANS; | ||
| 1415 | extern unsigned IOCTL_KIOCSETKEY; | ||
| 1416 | extern unsigned IOCTL_KIOCGETKEY; | ||
| 1417 | extern unsigned IOCTL_KIOCGTRANS; | ||
| 1418 | extern unsigned IOCTL_KIOCCMD; | ||
| 1419 | extern unsigned IOCTL_KIOCTYPE; | ||
| 1420 | extern unsigned IOCTL_KIOCSDIRECT; | ||
| 1421 | extern unsigned IOCTL_KIOCSKEY; | ||
| 1422 | extern unsigned IOCTL_KIOCGKEY; | ||
| 1423 | extern unsigned IOCTL_KIOCSLED; | ||
| 1424 | extern unsigned IOCTL_KIOCGLED; | ||
| 1425 | extern unsigned IOCTL_KIOCLAYOUT; | ||
| 1426 | extern unsigned IOCTL_VUIDSFORMAT; | ||
| 1427 | extern unsigned IOCTL_VUIDGFORMAT; | ||
| 1428 | extern unsigned IOCTL_STICIO_GXINFO; | ||
| 1429 | extern unsigned IOCTL_STICIO_RESET; | ||
| 1430 | extern unsigned IOCTL_STICIO_STARTQ; | ||
| 1431 | extern unsigned IOCTL_STICIO_STOPQ; | ||
| 1432 | extern unsigned IOCTL_UKYOPON_IDENTIFY; | ||
| 1433 | extern unsigned IOCTL_URIO_SEND_COMMAND; | ||
| 1434 | extern unsigned IOCTL_URIO_RECV_COMMAND; | ||
| 1435 | extern unsigned IOCTL_USB_REQUEST; | ||
| 1436 | extern unsigned IOCTL_USB_SETDEBUG; | ||
| 1437 | extern unsigned IOCTL_USB_DISCOVER; | ||
| 1438 | extern unsigned IOCTL_USB_DEVICEINFO; | ||
| 1439 | extern unsigned IOCTL_USB_DEVICEINFO_OLD; | ||
| 1440 | extern unsigned IOCTL_USB_DEVICESTATS; | ||
| 1441 | extern unsigned IOCTL_USB_GET_REPORT_DESC; | ||
| 1442 | extern unsigned IOCTL_USB_SET_IMMED; | ||
| 1443 | extern unsigned IOCTL_USB_GET_REPORT; | ||
| 1444 | extern unsigned IOCTL_USB_SET_REPORT; | ||
| 1445 | extern unsigned IOCTL_USB_GET_REPORT_ID; | ||
| 1446 | extern unsigned IOCTL_USB_GET_CONFIG; | ||
| 1447 | extern unsigned IOCTL_USB_SET_CONFIG; | ||
| 1448 | extern unsigned IOCTL_USB_GET_ALTINTERFACE; | ||
| 1449 | extern unsigned IOCTL_USB_SET_ALTINTERFACE; | ||
| 1450 | extern unsigned IOCTL_USB_GET_NO_ALT; | ||
| 1451 | extern unsigned IOCTL_USB_GET_DEVICE_DESC; | ||
| 1452 | extern unsigned IOCTL_USB_GET_CONFIG_DESC; | ||
| 1453 | extern unsigned IOCTL_USB_GET_INTERFACE_DESC; | ||
| 1454 | extern unsigned IOCTL_USB_GET_ENDPOINT_DESC; | ||
| 1455 | extern unsigned IOCTL_USB_GET_FULL_DESC; | ||
| 1456 | extern unsigned IOCTL_USB_GET_STRING_DESC; | ||
| 1457 | extern unsigned IOCTL_USB_DO_REQUEST; | ||
| 1458 | extern unsigned IOCTL_USB_GET_DEVICEINFO; | ||
| 1459 | extern unsigned IOCTL_USB_GET_DEVICEINFO_OLD; | ||
| 1460 | extern unsigned IOCTL_USB_SET_SHORT_XFER; | ||
| 1461 | extern unsigned IOCTL_USB_SET_TIMEOUT; | ||
| 1462 | extern unsigned IOCTL_USB_SET_BULK_RA; | ||
| 1463 | extern unsigned IOCTL_USB_SET_BULK_WB; | ||
| 1464 | extern unsigned IOCTL_USB_SET_BULK_RA_OPT; | ||
| 1465 | extern unsigned IOCTL_USB_SET_BULK_WB_OPT; | ||
| 1466 | extern unsigned IOCTL_USB_GET_CM_OVER_DATA; | ||
| 1467 | extern unsigned IOCTL_USB_SET_CM_OVER_DATA; | ||
| 1468 | extern unsigned IOCTL_UTOPPYIOTURBO; | ||
| 1469 | extern unsigned IOCTL_UTOPPYIOCANCEL; | ||
| 1470 | extern unsigned IOCTL_UTOPPYIOREBOOT; | ||
| 1471 | extern unsigned IOCTL_UTOPPYIOSTATS; | ||
| 1472 | extern unsigned IOCTL_UTOPPYIORENAME; | ||
| 1473 | extern unsigned IOCTL_UTOPPYIOMKDIR; | ||
| 1474 | extern unsigned IOCTL_UTOPPYIODELETE; | ||
| 1475 | extern unsigned IOCTL_UTOPPYIOREADDIR; | ||
| 1476 | extern unsigned IOCTL_UTOPPYIOREADFILE; | ||
| 1477 | extern unsigned IOCTL_UTOPPYIOWRITEFILE; | ||
| 1478 | extern unsigned IOCTL_DIOSXDCMD; | ||
| 1479 | extern unsigned IOCTL_VT_OPENQRY; | ||
| 1480 | extern unsigned IOCTL_VT_SETMODE; | ||
| 1481 | extern unsigned IOCTL_VT_GETMODE; | ||
| 1482 | extern unsigned IOCTL_VT_RELDISP; | ||
| 1483 | extern unsigned IOCTL_VT_ACTIVATE; | ||
| 1484 | extern unsigned IOCTL_VT_WAITACTIVE; | ||
| 1485 | extern unsigned IOCTL_VT_GETACTIVE; | ||
| 1486 | extern unsigned IOCTL_VT_GETSTATE; | ||
| 1487 | extern unsigned IOCTL_KDGETKBENT; | ||
| 1488 | extern unsigned IOCTL_KDGKBMODE; | ||
| 1489 | extern unsigned IOCTL_KDSKBMODE; | ||
| 1490 | extern unsigned IOCTL_KDMKTONE; | ||
| 1491 | extern unsigned IOCTL_KDSETMODE; | ||
| 1492 | extern unsigned IOCTL_KDENABIO; | ||
| 1493 | extern unsigned IOCTL_KDDISABIO; | ||
| 1494 | extern unsigned IOCTL_KDGKBTYPE; | ||
| 1495 | extern unsigned IOCTL_KDGETLED; | ||
| 1496 | extern unsigned IOCTL_KDSETLED; | ||
| 1497 | extern unsigned IOCTL_KDSETRAD; | ||
| 1498 | extern unsigned IOCTL_VGAPCVTID; | ||
| 1499 | extern unsigned IOCTL_CONS_GETVERS; | ||
| 1500 | extern unsigned IOCTL_WSKBDIO_GTYPE; | ||
| 1501 | extern unsigned IOCTL_WSKBDIO_BELL; | ||
| 1502 | extern unsigned IOCTL_WSKBDIO_COMPLEXBELL; | ||
| 1503 | extern unsigned IOCTL_WSKBDIO_SETBELL; | ||
| 1504 | extern unsigned IOCTL_WSKBDIO_GETBELL; | ||
| 1505 | extern unsigned IOCTL_WSKBDIO_SETDEFAULTBELL; | ||
| 1506 | extern unsigned IOCTL_WSKBDIO_GETDEFAULTBELL; | ||
| 1507 | extern unsigned IOCTL_WSKBDIO_SETKEYREPEAT; | ||
| 1508 | extern unsigned IOCTL_WSKBDIO_GETKEYREPEAT; | ||
| 1509 | extern unsigned IOCTL_WSKBDIO_SETDEFAULTKEYREPEAT; | ||
| 1510 | extern unsigned IOCTL_WSKBDIO_GETDEFAULTKEYREPEAT; | ||
| 1511 | extern unsigned IOCTL_WSKBDIO_SETLEDS; | ||
| 1512 | extern unsigned IOCTL_WSKBDIO_GETLEDS; | ||
| 1513 | extern unsigned IOCTL_WSKBDIO_GETMAP; | ||
| 1514 | extern unsigned IOCTL_WSKBDIO_SETMAP; | ||
| 1515 | extern unsigned IOCTL_WSKBDIO_GETENCODING; | ||
| 1516 | extern unsigned IOCTL_WSKBDIO_SETENCODING; | ||
| 1517 | extern unsigned IOCTL_WSKBDIO_SETMODE; | ||
| 1518 | extern unsigned IOCTL_WSKBDIO_GETMODE; | ||
| 1519 | extern unsigned IOCTL_WSKBDIO_SETKEYCLICK; | ||
| 1520 | extern unsigned IOCTL_WSKBDIO_GETKEYCLICK; | ||
| 1521 | extern unsigned IOCTL_WSKBDIO_GETSCROLL; | ||
| 1522 | extern unsigned IOCTL_WSKBDIO_SETSCROLL; | ||
| 1523 | extern unsigned IOCTL_WSKBDIO_SETVERSION; | ||
| 1524 | extern unsigned IOCTL_WSMOUSEIO_GTYPE; | ||
| 1525 | extern unsigned IOCTL_WSMOUSEIO_SRES; | ||
| 1526 | extern unsigned IOCTL_WSMOUSEIO_SSCALE; | ||
| 1527 | extern unsigned IOCTL_WSMOUSEIO_SRATE; | ||
| 1528 | extern unsigned IOCTL_WSMOUSEIO_SCALIBCOORDS; | ||
| 1529 | extern unsigned IOCTL_WSMOUSEIO_GCALIBCOORDS; | ||
| 1530 | extern unsigned IOCTL_WSMOUSEIO_GETID; | ||
| 1531 | extern unsigned IOCTL_WSMOUSEIO_GETREPEAT; | ||
| 1532 | extern unsigned IOCTL_WSMOUSEIO_SETREPEAT; | ||
| 1533 | extern unsigned IOCTL_WSMOUSEIO_SETVERSION; | ||
| 1534 | extern unsigned IOCTL_WSDISPLAYIO_GTYPE; | ||
| 1535 | extern unsigned IOCTL_WSDISPLAYIO_GINFO; | ||
| 1536 | extern unsigned IOCTL_WSDISPLAYIO_GETCMAP; | ||
| 1537 | extern unsigned IOCTL_WSDISPLAYIO_PUTCMAP; | ||
| 1538 | extern unsigned IOCTL_WSDISPLAYIO_GVIDEO; | ||
| 1539 | extern unsigned IOCTL_WSDISPLAYIO_SVIDEO; | ||
| 1540 | extern unsigned IOCTL_WSDISPLAYIO_GCURPOS; | ||
| 1541 | extern unsigned IOCTL_WSDISPLAYIO_SCURPOS; | ||
| 1542 | extern unsigned IOCTL_WSDISPLAYIO_GCURMAX; | ||
| 1543 | extern unsigned IOCTL_WSDISPLAYIO_GCURSOR; | ||
| 1544 | extern unsigned IOCTL_WSDISPLAYIO_SCURSOR; | ||
| 1545 | extern unsigned IOCTL_WSDISPLAYIO_GMODE; | ||
| 1546 | extern unsigned IOCTL_WSDISPLAYIO_SMODE; | ||
| 1547 | extern unsigned IOCTL_WSDISPLAYIO_LDFONT; | ||
| 1548 | extern unsigned IOCTL_WSDISPLAYIO_ADDSCREEN; | ||
| 1549 | extern unsigned IOCTL_WSDISPLAYIO_DELSCREEN; | ||
| 1550 | extern unsigned IOCTL_WSDISPLAYIO_SFONT; | ||
| 1551 | extern unsigned IOCTL__O_WSDISPLAYIO_SETKEYBOARD; | ||
| 1552 | extern unsigned IOCTL_WSDISPLAYIO_GETPARAM; | ||
| 1553 | extern unsigned IOCTL_WSDISPLAYIO_SETPARAM; | ||
| 1554 | extern unsigned IOCTL_WSDISPLAYIO_GETACTIVESCREEN; | ||
| 1555 | extern unsigned IOCTL_WSDISPLAYIO_GETWSCHAR; | ||
| 1556 | extern unsigned IOCTL_WSDISPLAYIO_PUTWSCHAR; | ||
| 1557 | extern unsigned IOCTL_WSDISPLAYIO_DGSCROLL; | ||
| 1558 | extern unsigned IOCTL_WSDISPLAYIO_DSSCROLL; | ||
| 1559 | extern unsigned IOCTL_WSDISPLAYIO_GMSGATTRS; | ||
| 1560 | extern unsigned IOCTL_WSDISPLAYIO_SMSGATTRS; | ||
| 1561 | extern unsigned IOCTL_WSDISPLAYIO_GBORDER; | ||
| 1562 | extern unsigned IOCTL_WSDISPLAYIO_SBORDER; | ||
| 1563 | extern unsigned IOCTL_WSDISPLAYIO_SSPLASH; | ||
| 1564 | extern unsigned IOCTL_WSDISPLAYIO_SPROGRESS; | ||
| 1565 | extern unsigned IOCTL_WSDISPLAYIO_LINEBYTES; | ||
| 1566 | extern unsigned IOCTL_WSDISPLAYIO_SETVERSION; | ||
| 1567 | extern unsigned IOCTL_WSMUXIO_ADD_DEVICE; | ||
| 1568 | extern unsigned IOCTL_WSMUXIO_REMOVE_DEVICE; | ||
| 1569 | extern unsigned IOCTL_WSMUXIO_LIST_DEVICES; | ||
| 1570 | extern unsigned IOCTL_WSMUXIO_INJECTEVENT; | ||
| 1571 | extern unsigned IOCTL_WSDISPLAYIO_GET_BUSID; | ||
| 1572 | extern unsigned IOCTL_WSDISPLAYIO_GET_EDID; | ||
| 1573 | extern unsigned IOCTL_WSDISPLAYIO_SET_POLLING; | ||
| 1574 | extern unsigned IOCTL_WSDISPLAYIO_GET_FBINFO; | ||
| 1575 | extern unsigned IOCTL_WSDISPLAYIO_DOBLIT; | ||
| 1576 | extern unsigned IOCTL_WSDISPLAYIO_WAITBLIT; | ||
| 1577 | extern unsigned IOCTL_BIOCLOCATE; | ||
| 1578 | extern unsigned IOCTL_BIOCINQ; | ||
| 1579 | extern unsigned IOCTL_BIOCDISK_NOVOL; | ||
| 1580 | extern unsigned IOCTL_BIOCDISK; | ||
| 1581 | extern unsigned IOCTL_BIOCVOL; | ||
| 1582 | extern unsigned IOCTL_BIOCALARM; | ||
| 1583 | extern unsigned IOCTL_BIOCBLINK; | ||
| 1584 | extern unsigned IOCTL_BIOCSETSTATE; | ||
| 1585 | extern unsigned IOCTL_BIOCVOLOPS; | ||
| 1586 | extern unsigned IOCTL_MD_GETCONF; | ||
| 1587 | extern unsigned IOCTL_MD_SETCONF; | ||
| 1588 | extern unsigned IOCTL_CCDIOCSET; | ||
| 1589 | extern unsigned IOCTL_CCDIOCCLR; | ||
| 1590 | extern unsigned IOCTL_CGDIOCSET; | ||
| 1591 | extern unsigned IOCTL_CGDIOCCLR; | ||
| 1592 | extern unsigned IOCTL_CGDIOCGET; | ||
| 1593 | extern unsigned IOCTL_FSSIOCSET; | ||
| 1594 | extern unsigned IOCTL_FSSIOCGET; | ||
| 1595 | extern unsigned IOCTL_FSSIOCCLR; | ||
| 1596 | extern unsigned IOCTL_FSSIOFSET; | ||
| 1597 | extern unsigned IOCTL_FSSIOFGET; | ||
| 1598 | extern unsigned IOCTL_BTDEV_ATTACH; | ||
| 1599 | extern unsigned IOCTL_BTDEV_DETACH; | ||
| 1600 | extern unsigned IOCTL_BTSCO_GETINFO; | ||
| 1601 | extern unsigned IOCTL_KTTCP_IO_SEND; | ||
| 1602 | extern unsigned IOCTL_KTTCP_IO_RECV; | ||
| 1603 | extern unsigned IOCTL_IOC_LOCKSTAT_GVERSION; | ||
| 1604 | extern unsigned IOCTL_IOC_LOCKSTAT_ENABLE; | ||
| 1605 | extern unsigned IOCTL_IOC_LOCKSTAT_DISABLE; | ||
| 1606 | extern unsigned IOCTL_VNDIOCSET; | ||
| 1607 | extern unsigned IOCTL_VNDIOCCLR; | ||
| 1608 | extern unsigned IOCTL_VNDIOCGET; | ||
| 1609 | extern unsigned IOCTL_SPKRTONE; | ||
| 1610 | extern unsigned IOCTL_SPKRTUNE; | ||
| 1611 | extern unsigned IOCTL_SPKRGETVOL; | ||
| 1612 | extern unsigned IOCTL_SPKRSETVOL; | ||
| 1613 | #if defined(__x86_64__) | ||
| 1614 | extern unsigned IOCTL_NVMM_IOC_CAPABILITY; | ||
| 1615 | extern unsigned IOCTL_NVMM_IOC_MACHINE_CREATE; | ||
| 1616 | extern unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY; | ||
| 1617 | extern unsigned IOCTL_NVMM_IOC_MACHINE_CONFIGURE; | ||
| 1618 | extern unsigned IOCTL_NVMM_IOC_VCPU_CREATE; | ||
| 1619 | extern unsigned IOCTL_NVMM_IOC_VCPU_DESTROY; | ||
| 1620 | extern unsigned IOCTL_NVMM_IOC_VCPU_CONFIGURE; | ||
| 1621 | extern unsigned IOCTL_NVMM_IOC_VCPU_SETSTATE; | ||
| 1622 | extern unsigned IOCTL_NVMM_IOC_VCPU_GETSTATE; | ||
| 1623 | extern unsigned IOCTL_NVMM_IOC_VCPU_INJECT; | ||
| 1624 | extern unsigned IOCTL_NVMM_IOC_VCPU_RUN; | ||
| 1625 | extern unsigned IOCTL_NVMM_IOC_GPA_MAP; | ||
| 1626 | extern unsigned IOCTL_NVMM_IOC_GPA_UNMAP; | ||
| 1627 | extern unsigned IOCTL_NVMM_IOC_HVA_MAP; | ||
| 1628 | extern unsigned IOCTL_NVMM_IOC_HVA_UNMAP; | ||
| 1629 | extern unsigned IOCTL_NVMM_IOC_CTL; | ||
| 1630 | #endif | ||
| 1631 | extern unsigned IOCTL_AUTOFSREQUEST; | ||
| 1632 | extern unsigned IOCTL_AUTOFSDONE; | ||
| 1633 | extern unsigned IOCTL_BIOCGBLEN; | ||
| 1634 | extern unsigned IOCTL_BIOCSBLEN; | ||
| 1635 | extern unsigned IOCTL_BIOCSETF; | ||
| 1636 | extern unsigned IOCTL_BIOCFLUSH; | ||
| 1637 | extern unsigned IOCTL_BIOCPROMISC; | ||
| 1638 | extern unsigned IOCTL_BIOCGDLT; | ||
| 1639 | extern unsigned IOCTL_BIOCGETIF; | ||
| 1640 | extern unsigned IOCTL_BIOCSETIF; | ||
| 1641 | extern unsigned IOCTL_BIOCGSTATS; | ||
| 1642 | extern unsigned IOCTL_BIOCGSTATSOLD; | ||
| 1643 | extern unsigned IOCTL_BIOCIMMEDIATE; | ||
| 1644 | extern unsigned IOCTL_BIOCVERSION; | ||
| 1645 | extern unsigned IOCTL_BIOCSTCPF; | ||
| 1646 | extern unsigned IOCTL_BIOCSUDPF; | ||
| 1647 | extern unsigned IOCTL_BIOCGHDRCMPLT; | ||
| 1648 | extern unsigned IOCTL_BIOCSHDRCMPLT; | ||
| 1649 | extern unsigned IOCTL_BIOCSDLT; | ||
| 1650 | extern unsigned IOCTL_BIOCGDLTLIST; | ||
| 1651 | extern unsigned IOCTL_BIOCGDIRECTION; | ||
| 1652 | extern unsigned IOCTL_BIOCSDIRECTION; | ||
| 1653 | extern unsigned IOCTL_BIOCSRTIMEOUT; | ||
| 1654 | extern unsigned IOCTL_BIOCGRTIMEOUT; | ||
| 1655 | extern unsigned IOCTL_BIOCGFEEDBACK; | ||
| 1656 | extern unsigned IOCTL_BIOCSFEEDBACK; | ||
| 1657 | extern unsigned IOCTL_GRESADDRS; | ||
| 1658 | extern unsigned IOCTL_GRESADDRD; | ||
| 1659 | extern unsigned IOCTL_GREGADDRS; | ||
| 1660 | extern unsigned IOCTL_GREGADDRD; | ||
| 1661 | extern unsigned IOCTL_GRESPROTO; | ||
| 1662 | extern unsigned IOCTL_GREGPROTO; | ||
| 1663 | extern unsigned IOCTL_GRESSOCK; | ||
| 1664 | extern unsigned IOCTL_GREDSOCK; | ||
| 1665 | extern unsigned IOCTL_PPPIOCGRAWIN; | ||
| 1666 | extern unsigned IOCTL_PPPIOCGFLAGS; | ||
| 1667 | extern unsigned IOCTL_PPPIOCSFLAGS; | ||
| 1668 | extern unsigned IOCTL_PPPIOCGASYNCMAP; | ||
| 1669 | extern unsigned IOCTL_PPPIOCSASYNCMAP; | ||
| 1670 | extern unsigned IOCTL_PPPIOCGUNIT; | ||
| 1671 | extern unsigned IOCTL_PPPIOCGRASYNCMAP; | ||
| 1672 | extern unsigned IOCTL_PPPIOCSRASYNCMAP; | ||
| 1673 | extern unsigned IOCTL_PPPIOCGMRU; | ||
| 1674 | extern unsigned IOCTL_PPPIOCSMRU; | ||
| 1675 | extern unsigned IOCTL_PPPIOCSMAXCID; | ||
| 1676 | extern unsigned IOCTL_PPPIOCGXASYNCMAP; | ||
| 1677 | extern unsigned IOCTL_PPPIOCSXASYNCMAP; | ||
| 1678 | extern unsigned IOCTL_PPPIOCXFERUNIT; | ||
| 1679 | extern unsigned IOCTL_PPPIOCSCOMPRESS; | ||
| 1680 | extern unsigned IOCTL_PPPIOCGNPMODE; | ||
| 1681 | extern unsigned IOCTL_PPPIOCSNPMODE; | ||
| 1682 | extern unsigned IOCTL_PPPIOCGIDLE; | ||
| 1683 | extern unsigned IOCTL_PPPIOCGMTU; | ||
| 1684 | extern unsigned IOCTL_PPPIOCSMTU; | ||
| 1685 | extern unsigned IOCTL_SIOCGPPPSTATS; | ||
| 1686 | extern unsigned IOCTL_SIOCGPPPCSTATS; | ||
| 1687 | extern unsigned IOCTL_IOC_NPF_VERSION; | ||
| 1688 | extern unsigned IOCTL_IOC_NPF_SWITCH; | ||
| 1689 | extern unsigned IOCTL_IOC_NPF_LOAD; | ||
| 1690 | extern unsigned IOCTL_IOC_NPF_TABLE; | ||
| 1691 | extern unsigned IOCTL_IOC_NPF_STATS; | ||
| 1692 | extern unsigned IOCTL_IOC_NPF_SAVE; | ||
| 1693 | extern unsigned IOCTL_IOC_NPF_RULE; | ||
| 1694 | extern unsigned IOCTL_IOC_NPF_CONN_LOOKUP; | ||
| 1695 | extern unsigned IOCTL_IOC_NPF_TABLE_REPLACE; | ||
| 1696 | extern unsigned IOCTL_PPPOESETPARMS; | ||
| 1697 | extern unsigned IOCTL_PPPOEGETPARMS; | ||
| 1698 | extern unsigned IOCTL_PPPOEGETSESSION; | ||
| 1699 | extern unsigned IOCTL_SPPPGETAUTHCFG; | ||
| 1700 | extern unsigned IOCTL_SPPPSETAUTHCFG; | ||
| 1701 | extern unsigned IOCTL_SPPPGETLCPCFG; | ||
| 1702 | extern unsigned IOCTL_SPPPSETLCPCFG; | ||
| 1703 | extern unsigned IOCTL_SPPPGETSTATUS; | ||
| 1704 | extern unsigned IOCTL_SPPPGETSTATUSNCP; | ||
| 1705 | extern unsigned IOCTL_SPPPGETIDLETO; | ||
| 1706 | extern unsigned IOCTL_SPPPSETIDLETO; | ||
| 1707 | extern unsigned IOCTL_SPPPGETAUTHFAILURES; | ||
| 1708 | extern unsigned IOCTL_SPPPSETAUTHFAILURE; | ||
| 1709 | extern unsigned IOCTL_SPPPSETDNSOPTS; | ||
| 1710 | extern unsigned IOCTL_SPPPGETDNSOPTS; | ||
| 1711 | extern unsigned IOCTL_SPPPGETDNSADDRS; | ||
| 1712 | extern unsigned IOCTL_SPPPSETKEEPALIVE; | ||
| 1713 | extern unsigned IOCTL_SPPPGETKEEPALIVE; | ||
| 1714 | extern unsigned IOCTL_SRT_GETNRT; | ||
| 1715 | extern unsigned IOCTL_SRT_GETRT; | ||
| 1716 | extern unsigned IOCTL_SRT_SETRT; | ||
| 1717 | extern unsigned IOCTL_SRT_DELRT; | ||
| 1718 | extern unsigned IOCTL_SRT_SFLAGS; | ||
| 1719 | extern unsigned IOCTL_SRT_GFLAGS; | ||
| 1720 | extern unsigned IOCTL_SRT_SGFLAGS; | ||
| 1721 | extern unsigned IOCTL_SRT_DEBUG; | ||
| 1722 | extern unsigned IOCTL_TAPGIFNAME; | ||
| 1723 | extern unsigned IOCTL_TUNSDEBUG; | ||
| 1724 | extern unsigned IOCTL_TUNGDEBUG; | ||
| 1725 | extern unsigned IOCTL_TUNSIFMODE; | ||
| 1726 | extern unsigned IOCTL_TUNSLMODE; | ||
| 1727 | extern unsigned IOCTL_TUNSIFHEAD; | ||
| 1728 | extern unsigned IOCTL_TUNGIFHEAD; | ||
| 1729 | extern unsigned IOCTL_DIOCSTART; | ||
| 1730 | extern unsigned IOCTL_DIOCSTOP; | ||
| 1731 | extern unsigned IOCTL_DIOCADDRULE; | ||
| 1732 | extern unsigned IOCTL_DIOCGETRULES; | ||
| 1733 | extern unsigned IOCTL_DIOCGETRULE; | ||
| 1734 | extern unsigned IOCTL_DIOCSETLCK; | ||
| 1735 | extern unsigned IOCTL_DIOCCLRSTATES; | ||
| 1736 | extern unsigned IOCTL_DIOCGETSTATE; | ||
| 1737 | extern unsigned IOCTL_DIOCSETSTATUSIF; | ||
| 1738 | extern unsigned IOCTL_DIOCGETSTATUS; | ||
| 1739 | extern unsigned IOCTL_DIOCCLRSTATUS; | ||
| 1740 | extern unsigned IOCTL_DIOCNATLOOK; | ||
| 1741 | extern unsigned IOCTL_DIOCSETDEBUG; | ||
| 1742 | extern unsigned IOCTL_DIOCGETSTATES; | ||
| 1743 | extern unsigned IOCTL_DIOCCHANGERULE; | ||
| 1744 | extern unsigned IOCTL_DIOCSETTIMEOUT; | ||
| 1745 | extern unsigned IOCTL_DIOCGETTIMEOUT; | ||
| 1746 | extern unsigned IOCTL_DIOCADDSTATE; | ||
| 1747 | extern unsigned IOCTL_DIOCCLRRULECTRS; | ||
| 1748 | extern unsigned IOCTL_DIOCGETLIMIT; | ||
| 1749 | extern unsigned IOCTL_DIOCSETLIMIT; | ||
| 1750 | extern unsigned IOCTL_DIOCKILLSTATES; | ||
| 1751 | extern unsigned IOCTL_DIOCSTARTALTQ; | ||
| 1752 | extern unsigned IOCTL_DIOCSTOPALTQ; | ||
| 1753 | extern unsigned IOCTL_DIOCADDALTQ; | ||
| 1754 | extern unsigned IOCTL_DIOCGETALTQS; | ||
| 1755 | extern unsigned IOCTL_DIOCGETALTQ; | ||
| 1756 | extern unsigned IOCTL_DIOCCHANGEALTQ; | ||
| 1757 | extern unsigned IOCTL_DIOCGETQSTATS; | ||
| 1758 | extern unsigned IOCTL_DIOCBEGINADDRS; | ||
| 1759 | extern unsigned IOCTL_DIOCADDADDR; | ||
| 1760 | extern unsigned IOCTL_DIOCGETADDRS; | ||
| 1761 | extern unsigned IOCTL_DIOCGETADDR; | ||
| 1762 | extern unsigned IOCTL_DIOCCHANGEADDR; | ||
| 1763 | extern unsigned IOCTL_DIOCADDSTATES; | ||
| 1764 | extern unsigned IOCTL_DIOCGETRULESETS; | ||
| 1765 | extern unsigned IOCTL_DIOCGETRULESET; | ||
| 1766 | extern unsigned IOCTL_DIOCRCLRTABLES; | ||
| 1767 | extern unsigned IOCTL_DIOCRADDTABLES; | ||
| 1768 | extern unsigned IOCTL_DIOCRDELTABLES; | ||
| 1769 | extern unsigned IOCTL_DIOCRGETTABLES; | ||
| 1770 | extern unsigned IOCTL_DIOCRGETTSTATS; | ||
| 1771 | extern unsigned IOCTL_DIOCRCLRTSTATS; | ||
| 1772 | extern unsigned IOCTL_DIOCRCLRADDRS; | ||
| 1773 | extern unsigned IOCTL_DIOCRADDADDRS; | ||
| 1774 | extern unsigned IOCTL_DIOCRDELADDRS; | ||
| 1775 | extern unsigned IOCTL_DIOCRSETADDRS; | ||
| 1776 | extern unsigned IOCTL_DIOCRGETADDRS; | ||
| 1777 | extern unsigned IOCTL_DIOCRGETASTATS; | ||
| 1778 | extern unsigned IOCTL_DIOCRCLRASTATS; | ||
| 1779 | extern unsigned IOCTL_DIOCRTSTADDRS; | ||
| 1780 | extern unsigned IOCTL_DIOCRSETTFLAGS; | ||
| 1781 | extern unsigned IOCTL_DIOCRINADEFINE; | ||
| 1782 | extern unsigned IOCTL_DIOCOSFPFLUSH; | ||
| 1783 | extern unsigned IOCTL_DIOCOSFPADD; | ||
| 1784 | extern unsigned IOCTL_DIOCOSFPGET; | ||
| 1785 | extern unsigned IOCTL_DIOCXBEGIN; | ||
| 1786 | extern unsigned IOCTL_DIOCXCOMMIT; | ||
| 1787 | extern unsigned IOCTL_DIOCXROLLBACK; | ||
| 1788 | extern unsigned IOCTL_DIOCGETSRCNODES; | ||
| 1789 | extern unsigned IOCTL_DIOCCLRSRCNODES; | ||
| 1790 | extern unsigned IOCTL_DIOCSETHOSTID; | ||
| 1791 | extern unsigned IOCTL_DIOCIGETIFACES; | ||
| 1792 | extern unsigned IOCTL_DIOCSETIFFLAG; | ||
| 1793 | extern unsigned IOCTL_DIOCCLRIFFLAG; | ||
| 1794 | extern unsigned IOCTL_DIOCKILLSRCNODES; | ||
| 1795 | extern unsigned IOCTL_SLIOCGUNIT; | ||
| 1796 | extern unsigned IOCTL_SIOCGBTINFO; | ||
| 1797 | extern unsigned IOCTL_SIOCGBTINFOA; | ||
| 1798 | extern unsigned IOCTL_SIOCNBTINFO; | ||
| 1799 | extern unsigned IOCTL_SIOCSBTFLAGS; | ||
| 1800 | extern unsigned IOCTL_SIOCSBTPOLICY; | ||
| 1801 | extern unsigned IOCTL_SIOCSBTPTYPE; | ||
| 1802 | extern unsigned IOCTL_SIOCGBTSTATS; | ||
| 1803 | extern unsigned IOCTL_SIOCZBTSTATS; | ||
| 1804 | extern unsigned IOCTL_SIOCBTDUMP; | ||
| 1805 | extern unsigned IOCTL_SIOCSBTSCOMTU; | ||
| 1806 | extern unsigned IOCTL_SIOCGBTFEAT; | ||
| 1807 | extern unsigned IOCTL_SIOCADNAT; | ||
| 1808 | extern unsigned IOCTL_SIOCRMNAT; | ||
| 1809 | extern unsigned IOCTL_SIOCGNATS; | ||
| 1810 | extern unsigned IOCTL_SIOCGNATL; | ||
| 1811 | extern unsigned IOCTL_SIOCPURGENAT; | ||
| 1812 | extern unsigned IOCTL_SIOCCONNECTX; | ||
| 1813 | extern unsigned IOCTL_SIOCCONNECTXDEL; | ||
| 1814 | extern unsigned IOCTL_SIOCSIFINFO_FLAGS; | ||
| 1815 | extern unsigned IOCTL_SIOCAADDRCTL_POLICY; | ||
| 1816 | extern unsigned IOCTL_SIOCDADDRCTL_POLICY; | ||
| 1817 | extern unsigned IOCTL_SMBIOC_OPENSESSION; | ||
| 1818 | extern unsigned IOCTL_SMBIOC_OPENSHARE; | ||
| 1819 | extern unsigned IOCTL_SMBIOC_REQUEST; | ||
| 1820 | extern unsigned IOCTL_SMBIOC_SETFLAGS; | ||
| 1821 | extern unsigned IOCTL_SMBIOC_LOOKUP; | ||
| 1822 | extern unsigned IOCTL_SMBIOC_READ; | ||
| 1823 | extern unsigned IOCTL_SMBIOC_WRITE; | ||
| 1824 | extern unsigned IOCTL_AGPIOC_INFO; | ||
| 1825 | extern unsigned IOCTL_AGPIOC_ACQUIRE; | ||
| 1826 | extern unsigned IOCTL_AGPIOC_RELEASE; | ||
| 1827 | extern unsigned IOCTL_AGPIOC_SETUP; | ||
| 1828 | extern unsigned IOCTL_AGPIOC_ALLOCATE; | ||
| 1829 | extern unsigned IOCTL_AGPIOC_DEALLOCATE; | ||
| 1830 | extern unsigned IOCTL_AGPIOC_BIND; | ||
| 1831 | extern unsigned IOCTL_AGPIOC_UNBIND; | ||
| 1832 | extern unsigned IOCTL_AUDIO_GETINFO; | ||
| 1833 | extern unsigned IOCTL_AUDIO_SETINFO; | ||
| 1834 | extern unsigned IOCTL_AUDIO_DRAIN; | ||
| 1835 | extern unsigned IOCTL_AUDIO_FLUSH; | ||
| 1836 | extern unsigned IOCTL_AUDIO_WSEEK; | ||
| 1837 | extern unsigned IOCTL_AUDIO_RERROR; | ||
| 1838 | extern unsigned IOCTL_AUDIO_GETDEV; | ||
| 1839 | extern unsigned IOCTL_AUDIO_GETENC; | ||
| 1840 | extern unsigned IOCTL_AUDIO_GETFD; | ||
| 1841 | extern unsigned IOCTL_AUDIO_SETFD; | ||
| 1842 | extern unsigned IOCTL_AUDIO_PERROR; | ||
| 1843 | extern unsigned IOCTL_AUDIO_GETIOFFS; | ||
| 1844 | extern unsigned IOCTL_AUDIO_GETOOFFS; | ||
| 1845 | extern unsigned IOCTL_AUDIO_GETPROPS; | ||
| 1846 | extern unsigned IOCTL_AUDIO_GETBUFINFO; | ||
| 1847 | extern unsigned IOCTL_AUDIO_SETCHAN; | ||
| 1848 | extern unsigned IOCTL_AUDIO_GETCHAN; | ||
| 1849 | extern unsigned IOCTL_AUDIO_QUERYFORMAT; | ||
| 1850 | extern unsigned IOCTL_AUDIO_GETFORMAT; | ||
| 1851 | extern unsigned IOCTL_AUDIO_SETFORMAT; | ||
| 1852 | extern unsigned IOCTL_AUDIO_MIXER_READ; | ||
| 1853 | extern unsigned IOCTL_AUDIO_MIXER_WRITE; | ||
| 1854 | extern unsigned IOCTL_AUDIO_MIXER_DEVINFO; | ||
| 1855 | extern unsigned IOCTL_ATAIOCCOMMAND; | ||
| 1856 | extern unsigned IOCTL_ATABUSIOSCAN; | ||
| 1857 | extern unsigned IOCTL_ATABUSIORESET; | ||
| 1858 | extern unsigned IOCTL_ATABUSIODETACH; | ||
| 1859 | extern unsigned IOCTL_CDIOCPLAYTRACKS; | ||
| 1860 | extern unsigned IOCTL_CDIOCPLAYBLOCKS; | ||
| 1861 | extern unsigned IOCTL_CDIOCREADSUBCHANNEL; | ||
| 1862 | extern unsigned IOCTL_CDIOREADTOCHEADER; | ||
| 1863 | extern unsigned IOCTL_CDIOREADTOCENTRIES; | ||
| 1864 | extern unsigned IOCTL_CDIOREADMSADDR; | ||
| 1865 | extern unsigned IOCTL_CDIOCSETPATCH; | ||
| 1866 | extern unsigned IOCTL_CDIOCGETVOL; | ||
| 1867 | extern unsigned IOCTL_CDIOCSETVOL; | ||
| 1868 | extern unsigned IOCTL_CDIOCSETMONO; | ||
| 1869 | extern unsigned IOCTL_CDIOCSETSTEREO; | ||
| 1870 | extern unsigned IOCTL_CDIOCSETMUTE; | ||
| 1871 | extern unsigned IOCTL_CDIOCSETLEFT; | ||
| 1872 | extern unsigned IOCTL_CDIOCSETRIGHT; | ||
| 1873 | extern unsigned IOCTL_CDIOCSETDEBUG; | ||
| 1874 | extern unsigned IOCTL_CDIOCCLRDEBUG; | ||
| 1875 | extern unsigned IOCTL_CDIOCPAUSE; | ||
| 1876 | extern unsigned IOCTL_CDIOCRESUME; | ||
| 1877 | extern unsigned IOCTL_CDIOCRESET; | ||
| 1878 | extern unsigned IOCTL_CDIOCSTART; | ||
| 1879 | extern unsigned IOCTL_CDIOCSTOP; | ||
| 1880 | extern unsigned IOCTL_CDIOCEJECT; | ||
| 1881 | extern unsigned IOCTL_CDIOCALLOW; | ||
| 1882 | extern unsigned IOCTL_CDIOCPREVENT; | ||
| 1883 | extern unsigned IOCTL_CDIOCCLOSE; | ||
| 1884 | extern unsigned IOCTL_CDIOCPLAYMSF; | ||
| 1885 | extern unsigned IOCTL_CDIOCLOADUNLOAD; | ||
| 1886 | extern unsigned IOCTL_CHIOMOVE; | ||
| 1887 | extern unsigned IOCTL_CHIOEXCHANGE; | ||
| 1888 | extern unsigned IOCTL_CHIOPOSITION; | ||
| 1889 | extern unsigned IOCTL_CHIOGPICKER; | ||
| 1890 | extern unsigned IOCTL_CHIOSPICKER; | ||
| 1891 | extern unsigned IOCTL_CHIOGPARAMS; | ||
| 1892 | extern unsigned IOCTL_CHIOIELEM; | ||
| 1893 | extern unsigned IOCTL_OCHIOGSTATUS; | ||
| 1894 | extern unsigned IOCTL_CHIOGSTATUS; | ||
| 1895 | extern unsigned IOCTL_CHIOSVOLTAG; | ||
| 1896 | extern unsigned IOCTL_CLOCKCTL_SETTIMEOFDAY; | ||
| 1897 | extern unsigned IOCTL_CLOCKCTL_ADJTIME; | ||
| 1898 | extern unsigned IOCTL_CLOCKCTL_CLOCK_SETTIME; | ||
| 1899 | extern unsigned IOCTL_CLOCKCTL_NTP_ADJTIME; | ||
| 1900 | extern unsigned IOCTL_IOC_CPU_SETSTATE; | ||
| 1901 | extern unsigned IOCTL_IOC_CPU_GETSTATE; | ||
| 1902 | extern unsigned IOCTL_IOC_CPU_GETCOUNT; | ||
| 1903 | extern unsigned IOCTL_IOC_CPU_MAPID; | ||
| 1904 | extern unsigned IOCTL_IOC_CPU_UCODE_GET_VERSION; | ||
| 1905 | extern unsigned IOCTL_IOC_CPU_UCODE_APPLY; | ||
| 1906 | extern unsigned IOCTL_DIOCGDINFO; | ||
| 1907 | extern unsigned IOCTL_DIOCSDINFO; | ||
| 1908 | extern unsigned IOCTL_DIOCWDINFO; | ||
| 1909 | extern unsigned IOCTL_DIOCRFORMAT; | ||
| 1910 | extern unsigned IOCTL_DIOCWFORMAT; | ||
| 1911 | extern unsigned IOCTL_DIOCSSTEP; | ||
| 1912 | extern unsigned IOCTL_DIOCSRETRIES; | ||
| 1913 | extern unsigned IOCTL_DIOCKLABEL; | ||
| 1914 | extern unsigned IOCTL_DIOCWLABEL; | ||
| 1915 | extern unsigned IOCTL_DIOCSBAD; | ||
| 1916 | extern unsigned IOCTL_DIOCEJECT; | ||
| 1917 | extern unsigned IOCTL_ODIOCEJECT; | ||
| 1918 | extern unsigned IOCTL_DIOCLOCK; | ||
| 1919 | extern unsigned IOCTL_DIOCGDEFLABEL; | ||
| 1920 | extern unsigned IOCTL_DIOCCLRLABEL; | ||
| 1921 | extern unsigned IOCTL_DIOCGCACHE; | ||
| 1922 | extern unsigned IOCTL_DIOCSCACHE; | ||
| 1923 | extern unsigned IOCTL_DIOCCACHESYNC; | ||
| 1924 | extern unsigned IOCTL_DIOCBSLIST; | ||
| 1925 | extern unsigned IOCTL_DIOCBSFLUSH; | ||
| 1926 | extern unsigned IOCTL_DIOCAWEDGE; | ||
| 1927 | extern unsigned IOCTL_DIOCGWEDGEINFO; | ||
| 1928 | extern unsigned IOCTL_DIOCDWEDGE; | ||
| 1929 | extern unsigned IOCTL_DIOCLWEDGES; | ||
| 1930 | extern unsigned IOCTL_DIOCGSTRATEGY; | ||
| 1931 | extern unsigned IOCTL_DIOCSSTRATEGY; | ||
| 1932 | extern unsigned IOCTL_DIOCGDISKINFO; | ||
| 1933 | extern unsigned IOCTL_DIOCTUR; | ||
| 1934 | extern unsigned IOCTL_DIOCMWEDGES; | ||
| 1935 | extern unsigned IOCTL_DIOCGSECTORSIZE; | ||
| 1936 | extern unsigned IOCTL_DIOCGMEDIASIZE; | ||
| 1937 | extern unsigned IOCTL_DIOCRMWEDGES; | ||
| 1938 | extern unsigned IOCTL_DRVDETACHDEV; | ||
| 1939 | extern unsigned IOCTL_DRVRESCANBUS; | ||
| 1940 | extern unsigned IOCTL_DRVCTLCOMMAND; | ||
| 1941 | extern unsigned IOCTL_DRVRESUMEDEV; | ||
| 1942 | extern unsigned IOCTL_DRVLISTDEV; | ||
| 1943 | extern unsigned IOCTL_DRVGETEVENT; | ||
| 1944 | extern unsigned IOCTL_DRVSUSPENDDEV; | ||
| 1945 | extern unsigned IOCTL_DVD_READ_STRUCT; | ||
| 1946 | extern unsigned IOCTL_DVD_WRITE_STRUCT; | ||
| 1947 | extern unsigned IOCTL_DVD_AUTH; | ||
| 1948 | extern unsigned IOCTL_ENVSYS_GETDICTIONARY; | ||
| 1949 | extern unsigned IOCTL_ENVSYS_SETDICTIONARY; | ||
| 1950 | extern unsigned IOCTL_ENVSYS_REMOVEPROPS; | ||
| 1951 | extern unsigned IOCTL_ENVSYS_GTREDATA; | ||
| 1952 | extern unsigned IOCTL_ENVSYS_GTREINFO; | ||
| 1953 | extern unsigned IOCTL_KFILTER_BYFILTER; | ||
| 1954 | extern unsigned IOCTL_KFILTER_BYNAME; | ||
| 1955 | extern unsigned IOCTL_FDIOCGETOPTS; | ||
| 1956 | extern unsigned IOCTL_FDIOCSETOPTS; | ||
| 1957 | extern unsigned IOCTL_FDIOCSETFORMAT; | ||
| 1958 | extern unsigned IOCTL_FDIOCGETFORMAT; | ||
| 1959 | extern unsigned IOCTL_FDIOCFORMAT_TRACK; | ||
| 1960 | extern unsigned IOCTL_FIOCLEX; | ||
| 1961 | extern unsigned IOCTL_FIONCLEX; | ||
| 1962 | extern unsigned IOCTL_FIOSEEKDATA; | ||
| 1963 | extern unsigned IOCTL_FIOSEEKHOLE; | ||
| 1964 | extern unsigned IOCTL_FIONREAD; | ||
| 1965 | extern unsigned IOCTL_FIONBIO; | ||
| 1966 | extern unsigned IOCTL_FIOASYNC; | ||
| 1967 | extern unsigned IOCTL_FIOSETOWN; | ||
| 1968 | extern unsigned IOCTL_FIOGETOWN; | ||
| 1969 | extern unsigned IOCTL_OFIOGETBMAP; | ||
| 1970 | extern unsigned IOCTL_FIOGETBMAP; | ||
| 1971 | extern unsigned IOCTL_FIONWRITE; | ||
| 1972 | extern unsigned IOCTL_FIONSPACE; | ||
| 1973 | extern unsigned IOCTL_GPIOINFO; | ||
| 1974 | extern unsigned IOCTL_GPIOSET; | ||
| 1975 | extern unsigned IOCTL_GPIOUNSET; | ||
| 1976 | extern unsigned IOCTL_GPIOREAD; | ||
| 1977 | extern unsigned IOCTL_GPIOWRITE; | ||
| 1978 | extern unsigned IOCTL_GPIOTOGGLE; | ||
| 1979 | extern unsigned IOCTL_GPIOATTACH; | ||
| 1980 | extern unsigned IOCTL_PTIOCNETBSD; | ||
| 1981 | extern unsigned IOCTL_PTIOCSUNOS; | ||
| 1982 | extern unsigned IOCTL_PTIOCLINUX; | ||
| 1983 | extern unsigned IOCTL_PTIOCFREEBSD; | ||
| 1984 | extern unsigned IOCTL_PTIOCULTRIX; | ||
| 1985 | extern unsigned IOCTL_TIOCHPCL; | ||
| 1986 | extern unsigned IOCTL_TIOCGETP; | ||
| 1987 | extern unsigned IOCTL_TIOCSETP; | ||
| 1988 | extern unsigned IOCTL_TIOCSETN; | ||
| 1989 | extern unsigned IOCTL_TIOCSETC; | ||
| 1990 | extern unsigned IOCTL_TIOCGETC; | ||
| 1991 | extern unsigned IOCTL_TIOCLBIS; | ||
| 1992 | extern unsigned IOCTL_TIOCLBIC; | ||
| 1993 | extern unsigned IOCTL_TIOCLSET; | ||
| 1994 | extern unsigned IOCTL_TIOCLGET; | ||
| 1995 | extern unsigned IOCTL_TIOCSLTC; | ||
| 1996 | extern unsigned IOCTL_TIOCGLTC; | ||
| 1997 | extern unsigned IOCTL_OTIOCCONS; | ||
| 1998 | extern unsigned IOCTL_JOY_SETTIMEOUT; | ||
| 1999 | extern unsigned IOCTL_JOY_GETTIMEOUT; | ||
| 2000 | extern unsigned IOCTL_JOY_SET_X_OFFSET; | ||
| 2001 | extern unsigned IOCTL_JOY_SET_Y_OFFSET; | ||
| 2002 | extern unsigned IOCTL_JOY_GET_X_OFFSET; | ||
| 2003 | extern unsigned IOCTL_JOY_GET_Y_OFFSET; | ||
| 2004 | extern unsigned IOCTL_OKIOCGSYMBOL; | ||
| 2005 | extern unsigned IOCTL_OKIOCGVALUE; | ||
| 2006 | extern unsigned IOCTL_KIOCGSIZE; | ||
| 2007 | extern unsigned IOCTL_KIOCGVALUE; | ||
| 2008 | extern unsigned IOCTL_KIOCGSYMBOL; | ||
| 2009 | extern unsigned IOCTL_LUAINFO; | ||
| 2010 | extern unsigned IOCTL_LUACREATE; | ||
| 2011 | extern unsigned IOCTL_LUADESTROY; | ||
| 2012 | extern unsigned IOCTL_LUAREQUIRE; | ||
| 2013 | extern unsigned IOCTL_LUALOAD; | ||
| 2014 | extern unsigned IOCTL_MIDI_PRETIME; | ||
| 2015 | extern unsigned IOCTL_MIDI_MPUMODE; | ||
| 2016 | extern unsigned IOCTL_MIDI_MPUCMD; | ||
| 2017 | extern unsigned IOCTL_SEQUENCER_RESET; | ||
| 2018 | extern unsigned IOCTL_SEQUENCER_SYNC; | ||
| 2019 | extern unsigned IOCTL_SEQUENCER_INFO; | ||
| 2020 | extern unsigned IOCTL_SEQUENCER_CTRLRATE; | ||
| 2021 | extern unsigned IOCTL_SEQUENCER_GETOUTCOUNT; | ||
| 2022 | extern unsigned IOCTL_SEQUENCER_GETINCOUNT; | ||
| 2023 | extern unsigned IOCTL_SEQUENCER_RESETSAMPLES; | ||
| 2024 | extern unsigned IOCTL_SEQUENCER_NRSYNTHS; | ||
| 2025 | extern unsigned IOCTL_SEQUENCER_NRMIDIS; | ||
| 2026 | extern unsigned IOCTL_SEQUENCER_THRESHOLD; | ||
| 2027 | extern unsigned IOCTL_SEQUENCER_MEMAVL; | ||
| 2028 | extern unsigned IOCTL_SEQUENCER_PANIC; | ||
| 2029 | extern unsigned IOCTL_SEQUENCER_OUTOFBAND; | ||
| 2030 | extern unsigned IOCTL_SEQUENCER_GETTIME; | ||
| 2031 | extern unsigned IOCTL_SEQUENCER_TMR_TIMEBASE; | ||
| 2032 | extern unsigned IOCTL_SEQUENCER_TMR_START; | ||
| 2033 | extern unsigned IOCTL_SEQUENCER_TMR_STOP; | ||
| 2034 | extern unsigned IOCTL_SEQUENCER_TMR_CONTINUE; | ||
| 2035 | extern unsigned IOCTL_SEQUENCER_TMR_TEMPO; | ||
| 2036 | extern unsigned IOCTL_SEQUENCER_TMR_SOURCE; | ||
| 2037 | extern unsigned IOCTL_SEQUENCER_TMR_METRONOME; | ||
| 2038 | extern unsigned IOCTL_SEQUENCER_TMR_SELECT; | ||
| 2039 | extern unsigned IOCTL_SPI_IOCTL_CONFIGURE; | ||
| 2040 | extern unsigned IOCTL_SPI_IOCTL_TRANSFER; | ||
| 2041 | extern unsigned IOCTL_MTIOCTOP; | ||
| 2042 | extern unsigned IOCTL_MTIOCGET; | ||
| 2043 | extern unsigned IOCTL_MTIOCIEOT; | ||
| 2044 | extern unsigned IOCTL_MTIOCEEOT; | ||
| 2045 | extern unsigned IOCTL_MTIOCRDSPOS; | ||
| 2046 | extern unsigned IOCTL_MTIOCRDHPOS; | ||
| 2047 | extern unsigned IOCTL_MTIOCSLOCATE; | ||
| 2048 | extern unsigned IOCTL_MTIOCHLOCATE; | ||
| 2049 | extern unsigned IOCTL_POWER_EVENT_RECVDICT; | ||
| 2050 | extern unsigned IOCTL_POWER_IOC_GET_TYPE; | ||
| 2051 | extern unsigned IOCTL_RIOCGINFO; | ||
| 2052 | extern unsigned IOCTL_RIOCSINFO; | ||
| 2053 | extern unsigned IOCTL_RIOCSSRCH; | ||
| 2054 | extern unsigned IOCTL_RNDGETENTCNT; | ||
| 2055 | extern unsigned IOCTL_RNDGETSRCNUM; | ||
| 2056 | extern unsigned IOCTL_RNDGETSRCNAME; | ||
| 2057 | extern unsigned IOCTL_RNDCTL; | ||
| 2058 | extern unsigned IOCTL_RNDADDDATA; | ||
| 2059 | extern unsigned IOCTL_RNDGETPOOLSTAT; | ||
| 2060 | extern unsigned IOCTL_RNDGETESTNUM; | ||
| 2061 | extern unsigned IOCTL_RNDGETESTNAME; | ||
| 2062 | extern unsigned IOCTL_SCIOCGET; | ||
| 2063 | extern unsigned IOCTL_SCIOCSET; | ||
| 2064 | extern unsigned IOCTL_SCIOCRESTART; | ||
| 2065 | extern unsigned IOCTL_SCIOC_USE_ADF; | ||
| 2066 | extern unsigned IOCTL_SCIOCCOMMAND; | ||
| 2067 | extern unsigned IOCTL_SCIOCDEBUG; | ||
| 2068 | extern unsigned IOCTL_SCIOCIDENTIFY; | ||
| 2069 | extern unsigned IOCTL_OSCIOCIDENTIFY; | ||
| 2070 | extern unsigned IOCTL_SCIOCDECONFIG; | ||
| 2071 | extern unsigned IOCTL_SCIOCRECONFIG; | ||
| 2072 | extern unsigned IOCTL_SCIOCRESET; | ||
| 2073 | extern unsigned IOCTL_SCBUSIOSCAN; | ||
| 2074 | extern unsigned IOCTL_SCBUSIORESET; | ||
| 2075 | extern unsigned IOCTL_SCBUSIODETACH; | ||
| 2076 | extern unsigned IOCTL_SCBUSACCEL; | ||
| 2077 | extern unsigned IOCTL_SCBUSIOLLSCAN; | ||
| 2078 | extern unsigned IOCTL_SIOCSHIWAT; | ||
| 2079 | extern unsigned IOCTL_SIOCGHIWAT; | ||
| 2080 | extern unsigned IOCTL_SIOCSLOWAT; | ||
| 2081 | extern unsigned IOCTL_SIOCGLOWAT; | ||
| 2082 | extern unsigned IOCTL_SIOCATMARK; | ||
| 2083 | extern unsigned IOCTL_SIOCSPGRP; | ||
| 2084 | extern unsigned IOCTL_SIOCGPGRP; | ||
| 2085 | extern unsigned IOCTL_SIOCPEELOFF; | ||
| 2086 | extern unsigned IOCTL_SIOCADDRT; | ||
| 2087 | extern unsigned IOCTL_SIOCDELRT; | ||
| 2088 | extern unsigned IOCTL_SIOCSIFADDR; | ||
| 2089 | extern unsigned IOCTL_SIOCGIFADDR; | ||
| 2090 | extern unsigned IOCTL_SIOCSIFDSTADDR; | ||
| 2091 | extern unsigned IOCTL_SIOCGIFDSTADDR; | ||
| 2092 | extern unsigned IOCTL_SIOCSIFFLAGS; | ||
| 2093 | extern unsigned IOCTL_SIOCGIFFLAGS; | ||
| 2094 | extern unsigned IOCTL_SIOCGIFBRDADDR; | ||
| 2095 | extern unsigned IOCTL_SIOCSIFBRDADDR; | ||
| 2096 | extern unsigned IOCTL_SIOCGIFCONF; | ||
| 2097 | extern unsigned IOCTL_SIOCGIFNETMASK; | ||
| 2098 | extern unsigned IOCTL_SIOCSIFNETMASK; | ||
| 2099 | extern unsigned IOCTL_SIOCGIFMETRIC; | ||
| 2100 | extern unsigned IOCTL_SIOCSIFMETRIC; | ||
| 2101 | extern unsigned IOCTL_SIOCDIFADDR; | ||
| 2102 | extern unsigned IOCTL_SIOCAIFADDR; | ||
| 2103 | extern unsigned IOCTL_SIOCGIFALIAS; | ||
| 2104 | extern unsigned IOCTL_SIOCGIFAFLAG_IN; | ||
| 2105 | extern unsigned IOCTL_SIOCALIFADDR; | ||
| 2106 | extern unsigned IOCTL_SIOCGLIFADDR; | ||
| 2107 | extern unsigned IOCTL_SIOCDLIFADDR; | ||
| 2108 | extern unsigned IOCTL_SIOCSIFADDRPREF; | ||
| 2109 | extern unsigned IOCTL_SIOCGIFADDRPREF; | ||
| 2110 | extern unsigned IOCTL_SIOCADDMULTI; | ||
| 2111 | extern unsigned IOCTL_SIOCDELMULTI; | ||
| 2112 | extern unsigned IOCTL_SIOCGETVIFCNT; | ||
| 2113 | extern unsigned IOCTL_SIOCGETSGCNT; | ||
| 2114 | extern unsigned IOCTL_SIOCSIFMEDIA; | ||
| 2115 | extern unsigned IOCTL_SIOCGIFMEDIA; | ||
| 2116 | extern unsigned IOCTL_SIOCSIFGENERIC; | ||
| 2117 | extern unsigned IOCTL_SIOCGIFGENERIC; | ||
| 2118 | extern unsigned IOCTL_SIOCSIFPHYADDR; | ||
| 2119 | extern unsigned IOCTL_SIOCGIFPSRCADDR; | ||
| 2120 | extern unsigned IOCTL_SIOCGIFPDSTADDR; | ||
| 2121 | extern unsigned IOCTL_SIOCDIFPHYADDR; | ||
| 2122 | extern unsigned IOCTL_SIOCSLIFPHYADDR; | ||
| 2123 | extern unsigned IOCTL_SIOCGLIFPHYADDR; | ||
| 2124 | extern unsigned IOCTL_SIOCSIFMTU; | ||
| 2125 | extern unsigned IOCTL_SIOCGIFMTU; | ||
| 2126 | extern unsigned IOCTL_SIOCSDRVSPEC; | ||
| 2127 | extern unsigned IOCTL_SIOCGDRVSPEC; | ||
| 2128 | extern unsigned IOCTL_SIOCIFCREATE; | ||
| 2129 | extern unsigned IOCTL_SIOCIFDESTROY; | ||
| 2130 | extern unsigned IOCTL_SIOCIFGCLONERS; | ||
| 2131 | extern unsigned IOCTL_SIOCGIFDLT; | ||
| 2132 | extern unsigned IOCTL_SIOCGIFCAP; | ||
| 2133 | extern unsigned IOCTL_SIOCSIFCAP; | ||
| 2134 | extern unsigned IOCTL_SIOCSVH; | ||
| 2135 | extern unsigned IOCTL_SIOCGVH; | ||
| 2136 | extern unsigned IOCTL_SIOCINITIFADDR; | ||
| 2137 | extern unsigned IOCTL_SIOCGIFDATA; | ||
| 2138 | extern unsigned IOCTL_SIOCZIFDATA; | ||
| 2139 | extern unsigned IOCTL_SIOCGLINKSTR; | ||
| 2140 | extern unsigned IOCTL_SIOCSLINKSTR; | ||
| 2141 | extern unsigned IOCTL_SIOCGETHERCAP; | ||
| 2142 | extern unsigned IOCTL_SIOCGIFINDEX; | ||
| 2143 | extern unsigned IOCTL_SIOCSETHERCAP; | ||
| 2144 | extern unsigned IOCTL_SIOCSIFDESCR; | ||
| 2145 | extern unsigned IOCTL_SIOCGIFDESCR; | ||
| 2146 | extern unsigned IOCTL_SIOCGUMBINFO; | ||
| 2147 | extern unsigned IOCTL_SIOCSUMBPARAM; | ||
| 2148 | extern unsigned IOCTL_SIOCGUMBPARAM; | ||
| 2149 | extern unsigned IOCTL_SIOCSETPFSYNC; | ||
| 2150 | extern unsigned IOCTL_SIOCGETPFSYNC; | ||
| 2151 | extern unsigned IOCTL_PPS_IOC_CREATE; | ||
| 2152 | extern unsigned IOCTL_PPS_IOC_DESTROY; | ||
| 2153 | extern unsigned IOCTL_PPS_IOC_SETPARAMS; | ||
| 2154 | extern unsigned IOCTL_PPS_IOC_GETPARAMS; | ||
| 2155 | extern unsigned IOCTL_PPS_IOC_GETCAP; | ||
| 2156 | extern unsigned IOCTL_PPS_IOC_FETCH; | ||
| 2157 | extern unsigned IOCTL_PPS_IOC_KCBIND; | ||
| 2158 | extern unsigned IOCTL_TIOCEXCL; | ||
| 2159 | extern unsigned IOCTL_TIOCNXCL; | ||
| 2160 | extern unsigned IOCTL_TIOCFLUSH; | ||
| 2161 | extern unsigned IOCTL_TIOCGETA; | ||
| 2162 | extern unsigned IOCTL_TIOCSETA; | ||
| 2163 | extern unsigned IOCTL_TIOCSETAW; | ||
| 2164 | extern unsigned IOCTL_TIOCSETAF; | ||
| 2165 | extern unsigned IOCTL_TIOCGETD; | ||
| 2166 | extern unsigned IOCTL_TIOCSETD; | ||
| 2167 | extern unsigned IOCTL_TIOCGLINED; | ||
| 2168 | extern unsigned IOCTL_TIOCSLINED; | ||
| 2169 | extern unsigned IOCTL_TIOCSBRK; | ||
| 2170 | extern unsigned IOCTL_TIOCCBRK; | ||
| 2171 | extern unsigned IOCTL_TIOCSDTR; | ||
| 2172 | extern unsigned IOCTL_TIOCCDTR; | ||
| 2173 | extern unsigned IOCTL_TIOCGPGRP; | ||
| 2174 | extern unsigned IOCTL_TIOCSPGRP; | ||
| 2175 | extern unsigned IOCTL_TIOCOUTQ; | ||
| 2176 | extern unsigned IOCTL_TIOCSTI; | ||
| 2177 | extern unsigned IOCTL_TIOCNOTTY; | ||
| 2178 | extern unsigned IOCTL_TIOCPKT; | ||
| 2179 | extern unsigned IOCTL_TIOCSTOP; | ||
| 2180 | extern unsigned IOCTL_TIOCSTART; | ||
| 2181 | extern unsigned IOCTL_TIOCMSET; | ||
| 2182 | extern unsigned IOCTL_TIOCMBIS; | ||
| 2183 | extern unsigned IOCTL_TIOCMBIC; | ||
| 2184 | extern unsigned IOCTL_TIOCMGET; | ||
| 2185 | extern unsigned IOCTL_TIOCREMOTE; | ||
| 2186 | extern unsigned IOCTL_TIOCGWINSZ; | ||
| 2187 | extern unsigned IOCTL_TIOCSWINSZ; | ||
| 2188 | extern unsigned IOCTL_TIOCUCNTL; | ||
| 2189 | extern unsigned IOCTL_TIOCSTAT; | ||
| 2190 | extern unsigned IOCTL_TIOCGSID; | ||
| 2191 | extern unsigned IOCTL_TIOCCONS; | ||
| 2192 | extern unsigned IOCTL_TIOCSCTTY; | ||
| 2193 | extern unsigned IOCTL_TIOCEXT; | ||
| 2194 | extern unsigned IOCTL_TIOCSIG; | ||
| 2195 | extern unsigned IOCTL_TIOCDRAIN; | ||
| 2196 | extern unsigned IOCTL_TIOCGFLAGS; | ||
| 2197 | extern unsigned IOCTL_TIOCSFLAGS; | ||
| 2198 | extern unsigned IOCTL_TIOCDCDTIMESTAMP; | ||
| 2199 | extern unsigned IOCTL_TIOCRCVFRAME; | ||
| 2200 | extern unsigned IOCTL_TIOCXMTFRAME; | ||
| 2201 | extern unsigned IOCTL_TIOCPTMGET; | ||
| 2202 | extern unsigned IOCTL_TIOCGRANTPT; | ||
| 2203 | extern unsigned IOCTL_TIOCPTSNAME; | ||
| 2204 | extern unsigned IOCTL_TIOCSQSIZE; | ||
| 2205 | extern unsigned IOCTL_TIOCGQSIZE; | ||
| 2206 | extern unsigned IOCTL_VERIEXEC_LOAD; | ||
| 2207 | extern unsigned IOCTL_VERIEXEC_TABLESIZE; | ||
| 2208 | extern unsigned IOCTL_VERIEXEC_DELETE; | ||
| 2209 | extern unsigned IOCTL_VERIEXEC_QUERY; | ||
| 2210 | extern unsigned IOCTL_VERIEXEC_DUMP; | ||
| 2211 | extern unsigned IOCTL_VERIEXEC_FLUSH; | ||
| 2212 | extern unsigned IOCTL_VIDIOC_QUERYCAP; | ||
| 2213 | extern unsigned IOCTL_VIDIOC_RESERVED; | ||
| 2214 | extern unsigned IOCTL_VIDIOC_ENUM_FMT; | ||
| 2215 | extern unsigned IOCTL_VIDIOC_G_FMT; | ||
| 2216 | extern unsigned IOCTL_VIDIOC_S_FMT; | ||
| 2217 | extern unsigned IOCTL_VIDIOC_REQBUFS; | ||
| 2218 | extern unsigned IOCTL_VIDIOC_QUERYBUF; | ||
| 2219 | extern unsigned IOCTL_VIDIOC_G_FBUF; | ||
| 2220 | extern unsigned IOCTL_VIDIOC_S_FBUF; | ||
| 2221 | extern unsigned IOCTL_VIDIOC_OVERLAY; | ||
| 2222 | extern unsigned IOCTL_VIDIOC_QBUF; | ||
| 2223 | extern unsigned IOCTL_VIDIOC_DQBUF; | ||
| 2224 | extern unsigned IOCTL_VIDIOC_STREAMON; | ||
| 2225 | extern unsigned IOCTL_VIDIOC_STREAMOFF; | ||
| 2226 | extern unsigned IOCTL_VIDIOC_G_PARM; | ||
| 2227 | extern unsigned IOCTL_VIDIOC_S_PARM; | ||
| 2228 | extern unsigned IOCTL_VIDIOC_G_STD; | ||
| 2229 | extern unsigned IOCTL_VIDIOC_S_STD; | ||
| 2230 | extern unsigned IOCTL_VIDIOC_ENUMSTD; | ||
| 2231 | extern unsigned IOCTL_VIDIOC_ENUMINPUT; | ||
| 2232 | extern unsigned IOCTL_VIDIOC_G_CTRL; | ||
| 2233 | extern unsigned IOCTL_VIDIOC_S_CTRL; | ||
| 2234 | extern unsigned IOCTL_VIDIOC_G_TUNER; | ||
| 2235 | extern unsigned IOCTL_VIDIOC_S_TUNER; | ||
| 2236 | extern unsigned IOCTL_VIDIOC_G_AUDIO; | ||
| 2237 | extern unsigned IOCTL_VIDIOC_S_AUDIO; | ||
| 2238 | extern unsigned IOCTL_VIDIOC_QUERYCTRL; | ||
| 2239 | extern unsigned IOCTL_VIDIOC_QUERYMENU; | ||
| 2240 | extern unsigned IOCTL_VIDIOC_G_INPUT; | ||
| 2241 | extern unsigned IOCTL_VIDIOC_S_INPUT; | ||
| 2242 | extern unsigned IOCTL_VIDIOC_G_OUTPUT; | ||
| 2243 | extern unsigned IOCTL_VIDIOC_S_OUTPUT; | ||
| 2244 | extern unsigned IOCTL_VIDIOC_ENUMOUTPUT; | ||
| 2245 | extern unsigned IOCTL_VIDIOC_G_AUDOUT; | ||
| 2246 | extern unsigned IOCTL_VIDIOC_S_AUDOUT; | ||
| 2247 | extern unsigned IOCTL_VIDIOC_G_MODULATOR; | ||
| 2248 | extern unsigned IOCTL_VIDIOC_S_MODULATOR; | ||
| 2249 | extern unsigned IOCTL_VIDIOC_G_FREQUENCY; | ||
| 2250 | extern unsigned IOCTL_VIDIOC_S_FREQUENCY; | ||
| 2251 | extern unsigned IOCTL_VIDIOC_CROPCAP; | ||
| 2252 | extern unsigned IOCTL_VIDIOC_G_CROP; | ||
| 2253 | extern unsigned IOCTL_VIDIOC_S_CROP; | ||
| 2254 | extern unsigned IOCTL_VIDIOC_G_JPEGCOMP; | ||
| 2255 | extern unsigned IOCTL_VIDIOC_S_JPEGCOMP; | ||
| 2256 | extern unsigned IOCTL_VIDIOC_QUERYSTD; | ||
| 2257 | extern unsigned IOCTL_VIDIOC_TRY_FMT; | ||
| 2258 | extern unsigned IOCTL_VIDIOC_ENUMAUDIO; | ||
| 2259 | extern unsigned IOCTL_VIDIOC_ENUMAUDOUT; | ||
| 2260 | extern unsigned IOCTL_VIDIOC_G_PRIORITY; | ||
| 2261 | extern unsigned IOCTL_VIDIOC_S_PRIORITY; | ||
| 2262 | extern unsigned IOCTL_VIDIOC_ENUM_FRAMESIZES; | ||
| 2263 | extern unsigned IOCTL_VIDIOC_ENUM_FRAMEINTERVALS; | ||
| 2264 | extern unsigned IOCTL_WDOGIOC_GMODE; | ||
| 2265 | extern unsigned IOCTL_WDOGIOC_SMODE; | ||
| 2266 | extern unsigned IOCTL_WDOGIOC_WHICH; | ||
| 2267 | extern unsigned IOCTL_WDOGIOC_TICKLE; | ||
| 2268 | extern unsigned IOCTL_WDOGIOC_GTICKLER; | ||
| 2269 | extern unsigned IOCTL_WDOGIOC_GWDOGS; | ||
| 2270 | extern unsigned IOCTL_KCOV_IOC_SETBUFSIZE; | ||
| 2271 | extern unsigned IOCTL_KCOV_IOC_ENABLE; | ||
| 2272 | extern unsigned IOCTL_KCOV_IOC_DISABLE; | ||
| 2273 | extern unsigned IOCTL_IPMICTL_RECEIVE_MSG_TRUNC; | ||
| 2274 | extern unsigned IOCTL_IPMICTL_RECEIVE_MSG; | ||
| 2275 | extern unsigned IOCTL_IPMICTL_SEND_COMMAND; | ||
| 2276 | extern unsigned IOCTL_IPMICTL_REGISTER_FOR_CMD; | ||
| 2277 | extern unsigned IOCTL_IPMICTL_UNREGISTER_FOR_CMD; | ||
| 2278 | extern unsigned IOCTL_IPMICTL_SET_GETS_EVENTS_CMD; | ||
| 2279 | extern unsigned IOCTL_IPMICTL_SET_MY_ADDRESS_CMD; | ||
| 2280 | extern unsigned IOCTL_IPMICTL_GET_MY_ADDRESS_CMD; | ||
| 2281 | extern unsigned IOCTL_IPMICTL_SET_MY_LUN_CMD; | ||
| 2282 | extern unsigned IOCTL_IPMICTL_GET_MY_LUN_CMD; | ||
| 2283 | extern unsigned IOCTL_SNDCTL_DSP_RESET; | ||
| 2284 | extern unsigned IOCTL_SNDCTL_DSP_SYNC; | ||
| 2285 | extern unsigned IOCTL_SNDCTL_DSP_SPEED; | ||
| 2286 | extern unsigned IOCTL_SOUND_PCM_READ_RATE; | ||
| 2287 | extern unsigned IOCTL_SNDCTL_DSP_STEREO; | ||
| 2288 | extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; | ||
| 2289 | extern unsigned IOCTL_SNDCTL_DSP_SETFMT; | ||
| 2290 | extern unsigned IOCTL_SOUND_PCM_READ_BITS; | ||
| 2291 | extern unsigned IOCTL_SNDCTL_DSP_CHANNELS; | ||
| 2292 | extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; | ||
| 2293 | extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; | ||
| 2294 | extern unsigned IOCTL_SOUND_PCM_READ_FILTER; | ||
| 2295 | extern unsigned IOCTL_SNDCTL_DSP_POST; | ||
| 2296 | extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; | ||
| 2297 | extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; | ||
| 2298 | extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; | ||
| 2299 | extern unsigned IOCTL_SNDCTL_DSP_GETOSPACE; | ||
| 2300 | extern unsigned IOCTL_SNDCTL_DSP_GETISPACE; | ||
| 2301 | extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; | ||
| 2302 | extern unsigned IOCTL_SNDCTL_DSP_GETCAPS; | ||
| 2303 | extern unsigned IOCTL_SNDCTL_DSP_GETTRIGGER; | ||
| 2304 | extern unsigned IOCTL_SNDCTL_DSP_SETTRIGGER; | ||
| 2305 | extern unsigned IOCTL_SNDCTL_DSP_GETIPTR; | ||
| 2306 | extern unsigned IOCTL_SNDCTL_DSP_GETOPTR; | ||
| 2307 | extern unsigned IOCTL_SNDCTL_DSP_MAPINBUF; | ||
| 2308 | extern unsigned IOCTL_SNDCTL_DSP_MAPOUTBUF; | ||
| 2309 | extern unsigned IOCTL_SNDCTL_DSP_SETSYNCRO; | ||
| 2310 | extern unsigned IOCTL_SNDCTL_DSP_SETDUPLEX; | ||
| 2311 | extern unsigned IOCTL_SNDCTL_DSP_PROFILE; | ||
| 2312 | extern unsigned IOCTL_SNDCTL_DSP_GETODELAY; | ||
| 2313 | extern unsigned IOCTL_SOUND_MIXER_INFO; | ||
| 2314 | extern unsigned IOCTL_SOUND_OLD_MIXER_INFO; | ||
| 2315 | extern unsigned IOCTL_OSS_GETVERSION; | ||
| 2316 | extern unsigned IOCTL_SNDCTL_SYSINFO; | ||
| 2317 | extern unsigned IOCTL_SNDCTL_AUDIOINFO; | ||
| 2318 | extern unsigned IOCTL_SNDCTL_ENGINEINFO; | ||
| 2319 | extern unsigned IOCTL_SNDCTL_DSP_GETPLAYVOL; | ||
| 2320 | extern unsigned IOCTL_SNDCTL_DSP_SETPLAYVOL; | ||
| 2321 | extern unsigned IOCTL_SNDCTL_DSP_GETRECVOL; | ||
| 2322 | extern unsigned IOCTL_SNDCTL_DSP_SETRECVOL; | ||
| 2323 | extern unsigned IOCTL_SNDCTL_DSP_SKIP; | ||
| 2324 | extern unsigned IOCTL_SNDCTL_DSP_SILENCE; | ||
| 2325 | |||
| 2326 | extern const int si_SEGV_MAPERR; | ||
| 2327 | extern const int si_SEGV_ACCERR; | ||
| 2328 | |||
| 2329 | extern const unsigned SHA1_CTX_sz; | ||
| 2330 | extern const unsigned SHA1_return_length; | ||
| 2331 | |||
| 2332 | extern const unsigned MD4_CTX_sz; | ||
| 2333 | extern const unsigned MD4_return_length; | ||
| 2334 | |||
| 2335 | extern const unsigned RMD160_CTX_sz; | ||
| 2336 | extern const unsigned RMD160_return_length; | ||
| 2337 | |||
| 2338 | extern const unsigned MD5_CTX_sz; | ||
| 2339 | extern const unsigned MD5_return_length; | ||
| 2340 | |||
| 2341 | extern const unsigned fpos_t_sz; | ||
| 2342 | |||
| 2343 | extern const unsigned MD2_CTX_sz; | ||
| 2344 | extern const unsigned MD2_return_length; | ||
| 2345 | |||
| 2346 | #define SHA2_EXTERN(LEN) \ | ||
| 2347 | extern const unsigned SHA##LEN##_CTX_sz; \ | ||
| 2348 | extern const unsigned SHA##LEN##_return_length; \ | ||
| 2349 | extern const unsigned SHA##LEN##_block_length; \ | ||
| 2350 | extern const unsigned SHA##LEN##_digest_length | ||
| 2351 | |||
| 2352 | SHA2_EXTERN(224); | ||
| 2353 | SHA2_EXTERN(256); | ||
| 2354 | SHA2_EXTERN(384); | ||
| 2355 | SHA2_EXTERN(512); | ||
| 2356 | |||
| 2357 | #undef SHA2_EXTERN | ||
| 2358 | |||
| 2359 | extern const int unvis_valid; | ||
| 2360 | extern const int unvis_validpush; | ||
| 2361 | |||
| 2362 | struct __sanitizer_cdbr { | ||
| 2363 | void (*unmap)(void *, void *, uptr); | ||
| 2364 | void *cookie; | ||
| 2365 | u8 *mmap_base; | ||
| 2366 | uptr mmap_size; | ||
| 2367 | |||
| 2368 | u8 *hash_base; | ||
| 2369 | u8 *offset_base; | ||
| 2370 | u8 *data_base; | ||
| 2371 | |||
| 2372 | u32 data_size; | ||
| 2373 | u32 entries; | ||
| 2374 | u32 entries_index; | ||
| 2375 | u32 seed; | ||
| 2376 | |||
| 2377 | u8 offset_size; | ||
| 2378 | u8 index_size; | ||
| 2379 | |||
| 2380 | u32 entries_m; | ||
| 2381 | u32 entries_index_m; | ||
| 2382 | u8 entries_s1, entries_s2; | ||
| 2383 | u8 entries_index_s1, entries_index_s2; | ||
| 2384 | }; | ||
| 2385 | |||
| 2386 | struct __sanitizer_cdbw { | ||
| 2387 | uptr data_counter; | ||
| 2388 | uptr data_allocated; | ||
| 2389 | uptr data_size; | ||
| 2390 | uptr *data_len; | ||
| 2391 | void **data_ptr; | ||
| 2392 | uptr hash_size; | ||
| 2393 | void *hash; | ||
| 2394 | uptr key_counter; | ||
| 2395 | }; | ||
| 2396 | } // namespace __sanitizer | ||
| 2397 | |||
| 2398 | #define CHECK_TYPE_SIZE(TYPE) \ | ||
| 2399 | COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) | ||
| 2400 | |||
| 2401 | #define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ | ||
| 2402 | COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \ | ||
| 2403 | sizeof(((CLASS *)NULL)->MEMBER)); \ | ||
| 2404 | COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ | ||
| 2405 | offsetof(CLASS, MEMBER)) | ||
| 2406 | |||
| 2407 | // For sigaction, which is a function and struct at the same time, | ||
| 2408 | // and thus requires explicit "struct" in sizeof() expression. | ||
| 2409 | #define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ | ||
| 2410 | COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \ | ||
| 2411 | sizeof(((struct CLASS *)NULL)->MEMBER)); \ | ||
| 2412 | COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ | ||
| 2413 | offsetof(struct CLASS, MEMBER)) | ||
| 2414 | |||
| 2415 | #define SIGACTION_SYMNAME __sigaction14 | ||
| 2416 | |||
| 2417 | // Compat with 9.0 | ||
| 2418 | extern unsigned struct_statvfs90_sz; | ||
| 2419 | |||
| 2420 | #endif // SANITIZER_NETBSD | ||
| 2421 | |||
| 2422 | #endif | ||
lib/tsan/sanitizer_common/sanitizer_platform_limits_openbsd.cpp created+279| ... | @@ -0,0 +1,279 @@ | ||
| 1 | //===-- sanitizer_platform_limits_openbsd.cpp -----------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer common code. | ||
| 10 | // | ||
| 11 | // Sizes and layouts of platform-specific NetBSD data structures. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_platform.h" | ||
| 15 | |||
| 16 | #if SANITIZER_OPENBSD | ||
| 17 | #include <arpa/inet.h> | ||
| 18 | #include <dirent.h> | ||
| 19 | #include <glob.h> | ||
| 20 | #include <grp.h> | ||
| 21 | #include <ifaddrs.h> | ||
| 22 | #include <limits.h> | ||
| 23 | #include <link_elf.h> | ||
| 24 | #include <sys/socket.h> | ||
| 25 | #include <net/if.h> | ||
| 26 | #include <net/ppp_defs.h> | ||
| 27 | #include <net/route.h> | ||
| 28 | #include <netdb.h> | ||
| 29 | #include <netinet/in.h> | ||
| 30 | #include <netinet/ip_mroute.h> | ||
| 31 | #include <poll.h> | ||
| 32 | #include <pthread.h> | ||
| 33 | #include <pwd.h> | ||
| 34 | #include <semaphore.h> | ||
| 35 | #include <signal.h> | ||
| 36 | #include <soundcard.h> | ||
| 37 | #include <stddef.h> | ||
| 38 | #include <stdint.h> | ||
| 39 | #include <sys/filio.h> | ||
| 40 | #include <sys/ipc.h> | ||
| 41 | #include <sys/mman.h> | ||
| 42 | #include <sys/mount.h> | ||
| 43 | #include <sys/msg.h> | ||
| 44 | #include <sys/mtio.h> | ||
| 45 | #include <sys/ptrace.h> | ||
| 46 | #include <sys/resource.h> | ||
| 47 | #include <sys/shm.h> | ||
| 48 | #include <sys/signal.h> | ||
| 49 | #include <sys/sockio.h> | ||
| 50 | #include <sys/stat.h> | ||
| 51 | #include <sys/statvfs.h> | ||
| 52 | #include <sys/time.h> | ||
| 53 | #include <sys/times.h> | ||
| 54 | #include <sys/types.h> | ||
| 55 | #include <sys/utsname.h> | ||
| 56 | #include <term.h> | ||
| 57 | #include <time.h> | ||
| 58 | #include <utime.h> | ||
| 59 | #include <utmp.h> | ||
| 60 | #include <wchar.h> | ||
| 61 | |||
| 62 | // Include these after system headers to avoid name clashes and ambiguities. | ||
| 63 | #include "sanitizer_internal_defs.h" | ||
| 64 | #include "sanitizer_platform_limits_openbsd.h" | ||
| 65 | |||
| 66 | namespace __sanitizer { | ||
| 67 | unsigned struct_utsname_sz = sizeof(struct utsname); | ||
| 68 | unsigned struct_stat_sz = sizeof(struct stat); | ||
| 69 | unsigned struct_rusage_sz = sizeof(struct rusage); | ||
| 70 | unsigned struct_tm_sz = sizeof(struct tm); | ||
| 71 | unsigned struct_passwd_sz = sizeof(struct passwd); | ||
| 72 | unsigned struct_group_sz = sizeof(struct group); | ||
| 73 | unsigned siginfo_t_sz = sizeof(siginfo_t); | ||
| 74 | unsigned struct_sigaction_sz = sizeof(struct sigaction); | ||
| 75 | unsigned struct_stack_t_sz = sizeof(stack_t); | ||
| 76 | unsigned struct_itimerval_sz = sizeof(struct itimerval); | ||
| 77 | unsigned pthread_t_sz = sizeof(pthread_t); | ||
| 78 | unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); | ||
| 79 | unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); | ||
| 80 | unsigned pid_t_sz = sizeof(pid_t); | ||
| 81 | unsigned timeval_sz = sizeof(timeval); | ||
| 82 | unsigned uid_t_sz = sizeof(uid_t); | ||
| 83 | unsigned gid_t_sz = sizeof(gid_t); | ||
| 84 | unsigned mbstate_t_sz = sizeof(mbstate_t); | ||
| 85 | unsigned sigset_t_sz = sizeof(sigset_t); | ||
| 86 | unsigned struct_timezone_sz = sizeof(struct timezone); | ||
| 87 | unsigned struct_tms_sz = sizeof(struct tms); | ||
| 88 | unsigned struct_sched_param_sz = sizeof(struct sched_param); | ||
| 89 | unsigned struct_sockaddr_sz = sizeof(struct sockaddr); | ||
| 90 | unsigned struct_rlimit_sz = sizeof(struct rlimit); | ||
| 91 | unsigned struct_timespec_sz = sizeof(struct timespec); | ||
| 92 | unsigned struct_utimbuf_sz = sizeof(struct utimbuf); | ||
| 93 | unsigned struct_itimerspec_sz = sizeof(struct itimerspec); | ||
| 94 | unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); | ||
| 95 | unsigned struct_statvfs_sz = sizeof(struct statvfs); | ||
| 96 | |||
| 97 | const uptr sig_ign = (uptr)SIG_IGN; | ||
| 98 | const uptr sig_dfl = (uptr)SIG_DFL; | ||
| 99 | const uptr sig_err = (uptr)SIG_ERR; | ||
| 100 | const uptr sa_siginfo = (uptr)SA_SIGINFO; | ||
| 101 | |||
| 102 | int shmctl_ipc_stat = (int)IPC_STAT; | ||
| 103 | |||
| 104 | unsigned struct_utmp_sz = sizeof(struct utmp); | ||
| 105 | |||
| 106 | int map_fixed = MAP_FIXED; | ||
| 107 | |||
| 108 | int af_inet = (int)AF_INET; | ||
| 109 | int af_inet6 = (int)AF_INET6; | ||
| 110 | |||
| 111 | uptr __sanitizer_in_addr_sz(int af) { | ||
| 112 | if (af == AF_INET) | ||
| 113 | return sizeof(struct in_addr); | ||
| 114 | else if (af == AF_INET6) | ||
| 115 | return sizeof(struct in6_addr); | ||
| 116 | else | ||
| 117 | return 0; | ||
| 118 | } | ||
| 119 | |||
| 120 | unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); | ||
| 121 | |||
| 122 | int glob_nomatch = GLOB_NOMATCH; | ||
| 123 | int glob_altdirfunc = GLOB_ALTDIRFUNC; | ||
| 124 | |||
| 125 | unsigned path_max = PATH_MAX; | ||
| 126 | |||
| 127 | const int si_SEGV_MAPERR = SEGV_MAPERR; | ||
| 128 | const int si_SEGV_ACCERR = SEGV_ACCERR; | ||
| 129 | } // namespace __sanitizer | ||
| 130 | |||
| 131 | using namespace __sanitizer; | ||
| 132 | |||
| 133 | COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); | ||
| 134 | |||
| 135 | COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); | ||
| 136 | CHECK_TYPE_SIZE(pthread_key_t); | ||
| 137 | |||
| 138 | CHECK_TYPE_SIZE(dl_phdr_info); | ||
| 139 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); | ||
| 140 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); | ||
| 141 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); | ||
| 142 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); | ||
| 143 | |||
| 144 | CHECK_TYPE_SIZE(glob_t); | ||
| 145 | CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); | ||
| 146 | CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); | ||
| 147 | CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); | ||
| 148 | CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); | ||
| 149 | CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); | ||
| 150 | CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); | ||
| 151 | CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); | ||
| 152 | CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); | ||
| 153 | CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); | ||
| 154 | |||
| 155 | CHECK_TYPE_SIZE(addrinfo); | ||
| 156 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); | ||
| 157 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); | ||
| 158 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); | ||
| 159 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); | ||
| 160 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); | ||
| 161 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); | ||
| 162 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); | ||
| 163 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_next); | ||
| 164 | |||
| 165 | CHECK_TYPE_SIZE(hostent); | ||
| 166 | CHECK_SIZE_AND_OFFSET(hostent, h_name); | ||
| 167 | CHECK_SIZE_AND_OFFSET(hostent, h_aliases); | ||
| 168 | CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); | ||
| 169 | CHECK_SIZE_AND_OFFSET(hostent, h_length); | ||
| 170 | CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); | ||
| 171 | |||
| 172 | CHECK_TYPE_SIZE(iovec); | ||
| 173 | CHECK_SIZE_AND_OFFSET(iovec, iov_base); | ||
| 174 | CHECK_SIZE_AND_OFFSET(iovec, iov_len); | ||
| 175 | |||
| 176 | CHECK_TYPE_SIZE(msghdr); | ||
| 177 | CHECK_SIZE_AND_OFFSET(msghdr, msg_name); | ||
| 178 | CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); | ||
| 179 | CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); | ||
| 180 | CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); | ||
| 181 | CHECK_SIZE_AND_OFFSET(msghdr, msg_control); | ||
| 182 | CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); | ||
| 183 | CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); | ||
| 184 | |||
| 185 | CHECK_TYPE_SIZE(cmsghdr); | ||
| 186 | CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); | ||
| 187 | CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); | ||
| 188 | CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); | ||
| 189 | |||
| 190 | COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); | ||
| 191 | CHECK_SIZE_AND_OFFSET(dirent, d_fileno); | ||
| 192 | CHECK_SIZE_AND_OFFSET(dirent, d_off); | ||
| 193 | CHECK_SIZE_AND_OFFSET(dirent, d_reclen); | ||
| 194 | |||
| 195 | CHECK_TYPE_SIZE(ifconf); | ||
| 196 | CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); | ||
| 197 | CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); | ||
| 198 | |||
| 199 | CHECK_TYPE_SIZE(pollfd); | ||
| 200 | CHECK_SIZE_AND_OFFSET(pollfd, fd); | ||
| 201 | CHECK_SIZE_AND_OFFSET(pollfd, events); | ||
| 202 | CHECK_SIZE_AND_OFFSET(pollfd, revents); | ||
| 203 | |||
| 204 | CHECK_TYPE_SIZE(nfds_t); | ||
| 205 | |||
| 206 | CHECK_TYPE_SIZE(sigset_t); | ||
| 207 | |||
| 208 | COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); | ||
| 209 | // Can't write checks for sa_handler and sa_sigaction due to them being | ||
| 210 | // preprocessor macros. | ||
| 211 | CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); | ||
| 212 | |||
| 213 | CHECK_TYPE_SIZE(tm); | ||
| 214 | CHECK_SIZE_AND_OFFSET(tm, tm_sec); | ||
| 215 | CHECK_SIZE_AND_OFFSET(tm, tm_min); | ||
| 216 | CHECK_SIZE_AND_OFFSET(tm, tm_hour); | ||
| 217 | CHECK_SIZE_AND_OFFSET(tm, tm_mday); | ||
| 218 | CHECK_SIZE_AND_OFFSET(tm, tm_mon); | ||
| 219 | CHECK_SIZE_AND_OFFSET(tm, tm_year); | ||
| 220 | CHECK_SIZE_AND_OFFSET(tm, tm_wday); | ||
| 221 | CHECK_SIZE_AND_OFFSET(tm, tm_yday); | ||
| 222 | CHECK_SIZE_AND_OFFSET(tm, tm_isdst); | ||
| 223 | CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); | ||
| 224 | CHECK_SIZE_AND_OFFSET(tm, tm_zone); | ||
| 225 | |||
| 226 | CHECK_TYPE_SIZE(ipc_perm); | ||
| 227 | CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); | ||
| 228 | CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); | ||
| 229 | CHECK_SIZE_AND_OFFSET(ipc_perm, uid); | ||
| 230 | CHECK_SIZE_AND_OFFSET(ipc_perm, gid); | ||
| 231 | CHECK_SIZE_AND_OFFSET(ipc_perm, mode); | ||
| 232 | CHECK_SIZE_AND_OFFSET(ipc_perm, seq); | ||
| 233 | CHECK_SIZE_AND_OFFSET(ipc_perm, key); | ||
| 234 | |||
| 235 | CHECK_TYPE_SIZE(shmid_ds); | ||
| 236 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); | ||
| 237 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); | ||
| 238 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); | ||
| 239 | CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_atimensec); | ||
| 240 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); | ||
| 241 | CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_dtimensec); | ||
| 242 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); | ||
| 243 | CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_ctimensec); | ||
| 244 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); | ||
| 245 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); | ||
| 246 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); | ||
| 247 | |||
| 248 | CHECK_TYPE_SIZE(clock_t); | ||
| 249 | |||
| 250 | CHECK_TYPE_SIZE(ifaddrs); | ||
| 251 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); | ||
| 252 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); | ||
| 253 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); | ||
| 254 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); | ||
| 255 | // Compare against the union, because we can't reach into the union in a | ||
| 256 | // compliant way. | ||
| 257 | #ifdef ifa_dstaddr | ||
| 258 | #undef ifa_dstaddr | ||
| 259 | #endif | ||
| 260 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); | ||
| 261 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); | ||
| 262 | |||
| 263 | CHECK_TYPE_SIZE(passwd); | ||
| 264 | CHECK_SIZE_AND_OFFSET(passwd, pw_name); | ||
| 265 | CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); | ||
| 266 | CHECK_SIZE_AND_OFFSET(passwd, pw_uid); | ||
| 267 | CHECK_SIZE_AND_OFFSET(passwd, pw_gid); | ||
| 268 | CHECK_SIZE_AND_OFFSET(passwd, pw_dir); | ||
| 269 | CHECK_SIZE_AND_OFFSET(passwd, pw_shell); | ||
| 270 | |||
| 271 | CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); | ||
| 272 | |||
| 273 | CHECK_TYPE_SIZE(group); | ||
| 274 | CHECK_SIZE_AND_OFFSET(group, gr_name); | ||
| 275 | CHECK_SIZE_AND_OFFSET(group, gr_passwd); | ||
| 276 | CHECK_SIZE_AND_OFFSET(group, gr_gid); | ||
| 277 | CHECK_SIZE_AND_OFFSET(group, gr_mem); | ||
| 278 | |||
| 279 | #endif // SANITIZER_OPENBSD | ||
lib/tsan/sanitizer_common/sanitizer_platform_limits_openbsd.h created+382| ... | @@ -0,0 +1,382 @@ | ||
| 1 | //===-- sanitizer_platform_limits_openbsd.h -------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer common code. | ||
| 10 | // | ||
| 11 | // Sizes and layouts of platform-specific OpenBSD data structures. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_PLATFORM_LIMITS_OPENBSD_H | ||
| 15 | #define SANITIZER_PLATFORM_LIMITS_OPENBSD_H | ||
| 16 | |||
| 17 | #if SANITIZER_OPENBSD | ||
| 18 | |||
| 19 | #include "sanitizer_internal_defs.h" | ||
| 20 | #include "sanitizer_platform.h" | ||
| 21 | |||
| 22 | #define _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, shift) \ | ||
| 23 | ((link_map *)((handle) == nullptr ? nullptr : ((char *)(handle) + (shift)))) | ||
| 24 | |||
| 25 | #if defined(__x86_64__) | ||
| 26 | #define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ | ||
| 27 | _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 312) | ||
| 28 | #elif defined(__i386__) | ||
| 29 | #define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ | ||
| 30 | _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 164) | ||
| 31 | #endif | ||
| 32 | |||
| 33 | #define RLIMIT_AS RLIMIT_DATA | ||
| 34 | |||
| 35 | namespace __sanitizer { | ||
| 36 | extern unsigned struct_utsname_sz; | ||
| 37 | extern unsigned struct_stat_sz; | ||
| 38 | extern unsigned struct_rusage_sz; | ||
| 39 | extern unsigned siginfo_t_sz; | ||
| 40 | extern unsigned struct_itimerval_sz; | ||
| 41 | extern unsigned pthread_t_sz; | ||
| 42 | extern unsigned pthread_mutex_t_sz; | ||
| 43 | extern unsigned pthread_cond_t_sz; | ||
| 44 | extern unsigned pid_t_sz; | ||
| 45 | extern unsigned timeval_sz; | ||
| 46 | extern unsigned uid_t_sz; | ||
| 47 | extern unsigned gid_t_sz; | ||
| 48 | extern unsigned mbstate_t_sz; | ||
| 49 | extern unsigned struct_timezone_sz; | ||
| 50 | extern unsigned struct_tms_sz; | ||
| 51 | extern unsigned struct_itimerspec_sz; | ||
| 52 | extern unsigned struct_sigevent_sz; | ||
| 53 | extern unsigned struct_stack_t_sz; | ||
| 54 | extern unsigned struct_statfs_sz; | ||
| 55 | extern unsigned struct_sockaddr_sz; | ||
| 56 | |||
| 57 | extern unsigned struct_rlimit_sz; | ||
| 58 | extern unsigned struct_utimbuf_sz; | ||
| 59 | extern unsigned struct_timespec_sz; | ||
| 60 | |||
| 61 | struct __sanitizer_iocb { | ||
| 62 | u64 aio_offset; | ||
| 63 | uptr aio_buf; | ||
| 64 | long aio_nbytes; | ||
| 65 | u32 aio_fildes; | ||
| 66 | u32 aio_lio_opcode; | ||
| 67 | long aio_reqprio; | ||
| 68 | #if SANITIZER_WORDSIZE == 64 | ||
| 69 | u8 aio_sigevent[32]; | ||
| 70 | #else | ||
| 71 | u8 aio_sigevent[20]; | ||
| 72 | #endif | ||
| 73 | u32 _state; | ||
| 74 | u32 _errno; | ||
| 75 | long _retval; | ||
| 76 | }; | ||
| 77 | |||
| 78 | struct __sanitizer___sysctl_args { | ||
| 79 | int *name; | ||
| 80 | int nlen; | ||
| 81 | void *oldval; | ||
| 82 | uptr *oldlenp; | ||
| 83 | void *newval; | ||
| 84 | uptr newlen; | ||
| 85 | }; | ||
| 86 | |||
| 87 | struct __sanitizer_sem_t { | ||
| 88 | uptr data[5]; | ||
| 89 | }; | ||
| 90 | |||
| 91 | struct __sanitizer_ipc_perm { | ||
| 92 | u32 cuid; | ||
| 93 | u32 cgid; | ||
| 94 | u32 uid; | ||
| 95 | u32 gid; | ||
| 96 | u32 mode; | ||
| 97 | unsigned short seq; | ||
| 98 | long key; | ||
| 99 | }; | ||
| 100 | |||
| 101 | struct __sanitizer_shmid_ds { | ||
| 102 | __sanitizer_ipc_perm shm_perm; | ||
| 103 | int shm_segsz; | ||
| 104 | u32 shm_lpid; | ||
| 105 | u32 shm_cpid; | ||
| 106 | short shm_nattch; | ||
| 107 | u64 shm_atime; | ||
| 108 | long __shm_atimensec; | ||
| 109 | u64 shm_dtime; | ||
| 110 | long __shm_dtimensec; | ||
| 111 | u64 shm_ctime; | ||
| 112 | long __shm_ctimensec; | ||
| 113 | void *_shm_internal; | ||
| 114 | }; | ||
| 115 | |||
| 116 | extern unsigned struct_msqid_ds_sz; | ||
| 117 | extern unsigned struct_mq_attr_sz; | ||
| 118 | extern unsigned struct_timex_sz; | ||
| 119 | extern unsigned struct_statvfs_sz; | ||
| 120 | |||
| 121 | struct __sanitizer_iovec { | ||
| 122 | void *iov_base; | ||
| 123 | uptr iov_len; | ||
| 124 | }; | ||
| 125 | |||
| 126 | struct __sanitizer_ifaddrs { | ||
| 127 | struct __sanitizer_ifaddrs *ifa_next; | ||
| 128 | char *ifa_name; | ||
| 129 | unsigned int ifa_flags; | ||
| 130 | struct __sanitizer_sockaddr *ifa_addr; // (struct sockaddr *) | ||
| 131 | struct __sanitizer_sockaddr *ifa_netmask; // (struct sockaddr *) | ||
| 132 | struct __sanitizer_sockaddr *ifa_dstaddr; // (struct sockaddr *) | ||
| 133 | void *ifa_data; | ||
| 134 | }; | ||
| 135 | |||
| 136 | typedef unsigned __sanitizer_pthread_key_t; | ||
| 137 | |||
| 138 | typedef long long __sanitizer_time_t; | ||
| 139 | typedef int __sanitizer_suseconds_t; | ||
| 140 | |||
| 141 | struct __sanitizer_timeval { | ||
| 142 | __sanitizer_time_t tv_sec; | ||
| 143 | __sanitizer_suseconds_t tv_usec; | ||
| 144 | }; | ||
| 145 | |||
| 146 | struct __sanitizer_itimerval { | ||
| 147 | struct __sanitizer_timeval it_interval; | ||
| 148 | struct __sanitizer_timeval it_value; | ||
| 149 | }; | ||
| 150 | |||
| 151 | struct __sanitizer_passwd { | ||
| 152 | char *pw_name; | ||
| 153 | char *pw_passwd; | ||
| 154 | int pw_uid; | ||
| 155 | int pw_gid; | ||
| 156 | __sanitizer_time_t pw_change; | ||
| 157 | char *pw_class; | ||
| 158 | char *pw_gecos; | ||
| 159 | char *pw_dir; | ||
| 160 | char *pw_shell; | ||
| 161 | __sanitizer_time_t pw_expire; | ||
| 162 | }; | ||
| 163 | |||
| 164 | struct __sanitizer_group { | ||
| 165 | char *gr_name; | ||
| 166 | char *gr_passwd; | ||
| 167 | int gr_gid; | ||
| 168 | char **gr_mem; | ||
| 169 | }; | ||
| 170 | |||
| 171 | struct __sanitizer_ether_addr { | ||
| 172 | u8 octet[6]; | ||
| 173 | }; | ||
| 174 | |||
| 175 | struct __sanitizer_tm { | ||
| 176 | int tm_sec; | ||
| 177 | int tm_min; | ||
| 178 | int tm_hour; | ||
| 179 | int tm_mday; | ||
| 180 | int tm_mon; | ||
| 181 | int tm_year; | ||
| 182 | int tm_wday; | ||
| 183 | int tm_yday; | ||
| 184 | int tm_isdst; | ||
| 185 | long int tm_gmtoff; | ||
| 186 | const char *tm_zone; | ||
| 187 | }; | ||
| 188 | |||
| 189 | struct __sanitizer_msghdr { | ||
| 190 | void *msg_name; | ||
| 191 | unsigned msg_namelen; | ||
| 192 | struct __sanitizer_iovec *msg_iov; | ||
| 193 | unsigned msg_iovlen; | ||
| 194 | void *msg_control; | ||
| 195 | unsigned msg_controllen; | ||
| 196 | int msg_flags; | ||
| 197 | }; | ||
| 198 | struct __sanitizer_cmsghdr { | ||
| 199 | unsigned cmsg_len; | ||
| 200 | int cmsg_level; | ||
| 201 | int cmsg_type; | ||
| 202 | }; | ||
| 203 | |||
| 204 | struct __sanitizer_dirent { | ||
| 205 | u64 d_fileno; | ||
| 206 | u64 d_off; | ||
| 207 | u16 d_reclen; | ||
| 208 | }; | ||
| 209 | |||
| 210 | typedef u64 __sanitizer_clock_t; | ||
| 211 | typedef u32 __sanitizer_clockid_t; | ||
| 212 | |||
| 213 | typedef u32 __sanitizer___kernel_uid_t; | ||
| 214 | typedef u32 __sanitizer___kernel_gid_t; | ||
| 215 | typedef u64 __sanitizer___kernel_off_t; | ||
| 216 | typedef struct { | ||
| 217 | u32 fds_bits[8]; | ||
| 218 | } __sanitizer___kernel_fd_set; | ||
| 219 | |||
| 220 | typedef struct { | ||
| 221 | unsigned int pta_magic; | ||
| 222 | int pta_flags; | ||
| 223 | void *pta_private; | ||
| 224 | } __sanitizer_pthread_attr_t; | ||
| 225 | |||
| 226 | typedef unsigned int __sanitizer_sigset_t; | ||
| 227 | |||
| 228 | struct __sanitizer_siginfo { | ||
| 229 | // The size is determined by looking at sizeof of real siginfo_t on linux. | ||
| 230 | u64 opaque[128 / sizeof(u64)]; | ||
| 231 | }; | ||
| 232 | |||
| 233 | using __sanitizer_sighandler_ptr = void (*)(int sig); | ||
| 234 | using __sanitizer_sigactionhandler_ptr = void (*)(int sig, | ||
| 235 | __sanitizer_siginfo *siginfo, | ||
| 236 | void *uctx); | ||
| 237 | |||
| 238 | struct __sanitizer_sigaction { | ||
| 239 | union { | ||
| 240 | __sanitizer_sighandler_ptr handler; | ||
| 241 | __sanitizer_sigactionhandler_ptr sigaction; | ||
| 242 | }; | ||
| 243 | __sanitizer_sigset_t sa_mask; | ||
| 244 | int sa_flags; | ||
| 245 | }; | ||
| 246 | |||
| 247 | typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t; | ||
| 248 | |||
| 249 | struct __sanitizer_kernel_sigaction_t { | ||
| 250 | union { | ||
| 251 | void (*handler)(int signo); | ||
| 252 | void (*sigaction)(int signo, void *info, void *ctx); | ||
| 253 | }; | ||
| 254 | unsigned long sa_flags; | ||
| 255 | void (*sa_restorer)(void); | ||
| 256 | __sanitizer_kernel_sigset_t sa_mask; | ||
| 257 | }; | ||
| 258 | |||
| 259 | extern const uptr sig_ign; | ||
| 260 | extern const uptr sig_dfl; | ||
| 261 | extern const uptr sig_err; | ||
| 262 | extern const uptr sa_siginfo; | ||
| 263 | |||
| 264 | extern int af_inet; | ||
| 265 | extern int af_inet6; | ||
| 266 | uptr __sanitizer_in_addr_sz(int af); | ||
| 267 | |||
| 268 | struct __sanitizer_dl_phdr_info { | ||
| 269 | #if SANITIZER_WORDSIZE == 64 | ||
| 270 | u64 dlpi_addr; | ||
| 271 | #else | ||
| 272 | u32 dlpi_addr; | ||
| 273 | #endif | ||
| 274 | const char *dlpi_name; | ||
| 275 | const void *dlpi_phdr; | ||
| 276 | #if SANITIZER_WORDSIZE == 64 | ||
| 277 | u32 dlpi_phnum; | ||
| 278 | #else | ||
| 279 | u16 dlpi_phnum; | ||
| 280 | #endif | ||
| 281 | }; | ||
| 282 | |||
| 283 | extern unsigned struct_ElfW_Phdr_sz; | ||
| 284 | |||
| 285 | struct __sanitizer_addrinfo { | ||
| 286 | int ai_flags; | ||
| 287 | int ai_family; | ||
| 288 | int ai_socktype; | ||
| 289 | int ai_protocol; | ||
| 290 | unsigned ai_addrlen; | ||
| 291 | struct __sanitizer_sockaddr *ai_addr; | ||
| 292 | char *ai_canonname; | ||
| 293 | struct __sanitizer_addrinfo *ai_next; | ||
| 294 | }; | ||
| 295 | |||
| 296 | struct __sanitizer_hostent { | ||
| 297 | char *h_name; | ||
| 298 | char **h_aliases; | ||
| 299 | int h_addrtype; | ||
| 300 | int h_length; | ||
| 301 | char **h_addr_list; | ||
| 302 | }; | ||
| 303 | |||
| 304 | struct __sanitizer_pollfd { | ||
| 305 | int fd; | ||
| 306 | short events; | ||
| 307 | short revents; | ||
| 308 | }; | ||
| 309 | |||
| 310 | typedef unsigned __sanitizer_nfds_t; | ||
| 311 | |||
| 312 | struct __sanitizer_glob_t { | ||
| 313 | int gl_pathc; | ||
| 314 | int gl_matchc; | ||
| 315 | int gl_offs; | ||
| 316 | int gl_flags; | ||
| 317 | char **gl_pathv; | ||
| 318 | void **gl_statv; | ||
| 319 | int (*gl_errfunc)(const char *, int); | ||
| 320 | void (*gl_closedir)(void *dirp); | ||
| 321 | struct dirent *(*gl_readdir)(void *dirp); | ||
| 322 | void *(*gl_opendir)(const char *); | ||
| 323 | int (*gl_lstat)(const char *, void * /* struct stat* */); | ||
| 324 | int (*gl_stat)(const char *, void * /* struct stat* */); | ||
| 325 | }; | ||
| 326 | |||
| 327 | extern int glob_nomatch; | ||
| 328 | extern int glob_altdirfunc; | ||
| 329 | |||
| 330 | extern unsigned path_max; | ||
| 331 | |||
| 332 | typedef char __sanitizer_FILE; | ||
| 333 | #define SANITIZER_HAS_STRUCT_FILE 0 | ||
| 334 | |||
| 335 | extern int shmctl_ipc_stat; | ||
| 336 | |||
| 337 | // This simplifies generic code | ||
| 338 | #define struct_shminfo_sz -1 | ||
| 339 | #define struct_shm_info_sz -1 | ||
| 340 | #define shmctl_shm_stat -1 | ||
| 341 | #define shmctl_ipc_info -1 | ||
| 342 | #define shmctl_shm_info -1 | ||
| 343 | |||
| 344 | extern unsigned struct_utmp_sz; | ||
| 345 | extern unsigned struct_utmpx_sz; | ||
| 346 | |||
| 347 | extern int map_fixed; | ||
| 348 | |||
| 349 | // ioctl arguments | ||
| 350 | struct __sanitizer_ifconf { | ||
| 351 | int ifc_len; | ||
| 352 | union { | ||
| 353 | void *ifcu_req; | ||
| 354 | } ifc_ifcu; | ||
| 355 | }; | ||
| 356 | |||
| 357 | extern const int si_SEGV_MAPERR; | ||
| 358 | extern const int si_SEGV_ACCERR; | ||
| 359 | } // namespace __sanitizer | ||
| 360 | |||
| 361 | #define CHECK_TYPE_SIZE(TYPE) \ | ||
| 362 | COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) | ||
| 363 | |||
| 364 | #define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ | ||
| 365 | COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \ | ||
| 366 | sizeof(((CLASS *)NULL)->MEMBER)); \ | ||
| 367 | COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ | ||
| 368 | offsetof(CLASS, MEMBER)) | ||
| 369 | |||
| 370 | // For sigaction, which is a function and struct at the same time, | ||
| 371 | // and thus requires explicit "struct" in sizeof() expression. | ||
| 372 | #define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ | ||
| 373 | COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \ | ||
| 374 | sizeof(((struct CLASS *)NULL)->MEMBER)); \ | ||
| 375 | COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ | ||
| 376 | offsetof(struct CLASS, MEMBER)) | ||
| 377 | |||
| 378 | #define SIGACTION_SYMNAME __sigaction14 | ||
| 379 | |||
| 380 | #endif // SANITIZER_OPENBSD | ||
| 381 | |||
| 382 | #endif | ||
lib/tsan/sanitizer_common/sanitizer_platform_limits_posix.cpp created+1275| ... | @@ -0,0 +1,1275 @@ | ||
| 1 | //===-- sanitizer_platform_limits_posix.cpp -------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer common code. | ||
| 10 | // | ||
| 11 | // Sizes and layouts of platform-specific POSIX data structures. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_platform.h" | ||
| 15 | |||
| 16 | #if SANITIZER_LINUX || SANITIZER_MAC | ||
| 17 | // Tests in this file assume that off_t-dependent data structures match the | ||
| 18 | // libc ABI. For example, struct dirent here is what readdir() function (as | ||
| 19 | // exported from libc) returns, and not the user-facing "dirent", which | ||
| 20 | // depends on _FILE_OFFSET_BITS setting. | ||
| 21 | // To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below. | ||
| 22 | #ifdef _FILE_OFFSET_BITS | ||
| 23 | #undef _FILE_OFFSET_BITS | ||
| 24 | #endif | ||
| 25 | |||
| 26 | // Must go after undef _FILE_OFFSET_BITS. | ||
| 27 | #include "sanitizer_glibc_version.h" | ||
| 28 | |||
| 29 | #include <arpa/inet.h> | ||
| 30 | #include <dirent.h> | ||
| 31 | #include <grp.h> | ||
| 32 | #include <limits.h> | ||
| 33 | #include <net/if.h> | ||
| 34 | #include <netdb.h> | ||
| 35 | #include <poll.h> | ||
| 36 | #include <pthread.h> | ||
| 37 | #include <pwd.h> | ||
| 38 | #include <signal.h> | ||
| 39 | #include <stddef.h> | ||
| 40 | #include <sys/mman.h> | ||
| 41 | #include <sys/resource.h> | ||
| 42 | #include <sys/socket.h> | ||
| 43 | #include <sys/stat.h> | ||
| 44 | #include <sys/time.h> | ||
| 45 | #include <sys/times.h> | ||
| 46 | #include <sys/types.h> | ||
| 47 | #include <sys/utsname.h> | ||
| 48 | #include <termios.h> | ||
| 49 | #include <time.h> | ||
| 50 | #include <wchar.h> | ||
| 51 | #include <regex.h> | ||
| 52 | #if !SANITIZER_MAC | ||
| 53 | #include <utmp.h> | ||
| 54 | #endif | ||
| 55 | |||
| 56 | #if !SANITIZER_IOS | ||
| 57 | #include <net/route.h> | ||
| 58 | #endif | ||
| 59 | |||
| 60 | #if !SANITIZER_ANDROID | ||
| 61 | #include <fstab.h> | ||
| 62 | #include <sys/mount.h> | ||
| 63 | #include <sys/timeb.h> | ||
| 64 | #include <utmpx.h> | ||
| 65 | #endif | ||
| 66 | |||
| 67 | #if SANITIZER_LINUX | ||
| 68 | #include <malloc.h> | ||
| 69 | #include <mntent.h> | ||
| 70 | #include <netinet/ether.h> | ||
| 71 | #include <sys/sysinfo.h> | ||
| 72 | #include <sys/vt.h> | ||
| 73 | #include <linux/cdrom.h> | ||
| 74 | #include <linux/fd.h> | ||
| 75 | #include <linux/fs.h> | ||
| 76 | #include <linux/hdreg.h> | ||
| 77 | #include <linux/input.h> | ||
| 78 | #include <linux/ioctl.h> | ||
| 79 | #include <linux/soundcard.h> | ||
| 80 | #include <linux/sysctl.h> | ||
| 81 | #include <linux/utsname.h> | ||
| 82 | #include <linux/posix_types.h> | ||
| 83 | #include <net/if_arp.h> | ||
| 84 | #endif | ||
| 85 | |||
| 86 | #if SANITIZER_IOS | ||
| 87 | #undef IOC_DIRMASK | ||
| 88 | #endif | ||
| 89 | |||
| 90 | #if SANITIZER_LINUX | ||
| 91 | # include <utime.h> | ||
| 92 | # include <sys/ptrace.h> | ||
| 93 | # if defined(__mips64) || defined(__aarch64__) || defined(__arm__) | ||
| 94 | # include <asm/ptrace.h> | ||
| 95 | # ifdef __arm__ | ||
| 96 | typedef struct user_fpregs elf_fpregset_t; | ||
| 97 | # define ARM_VFPREGS_SIZE_ASAN (32 * 8 /*fpregs*/ + 4 /*fpscr*/) | ||
| 98 | # if !defined(ARM_VFPREGS_SIZE) | ||
| 99 | # define ARM_VFPREGS_SIZE ARM_VFPREGS_SIZE_ASAN | ||
| 100 | # endif | ||
| 101 | # endif | ||
| 102 | # endif | ||
| 103 | # include <semaphore.h> | ||
| 104 | #endif | ||
| 105 | |||
| 106 | #if !SANITIZER_ANDROID | ||
| 107 | #include <ifaddrs.h> | ||
| 108 | #include <sys/ucontext.h> | ||
| 109 | #include <wordexp.h> | ||
| 110 | #endif | ||
| 111 | |||
| 112 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 113 | #include <glob.h> | ||
| 114 | #include <obstack.h> | ||
| 115 | #include <mqueue.h> | ||
| 116 | #include <net/if_ppp.h> | ||
| 117 | #include <netax25/ax25.h> | ||
| 118 | #include <netipx/ipx.h> | ||
| 119 | #include <netrom/netrom.h> | ||
| 120 | #if HAVE_RPC_XDR_H | ||
| 121 | # include <rpc/xdr.h> | ||
| 122 | #endif | ||
| 123 | #include <scsi/scsi.h> | ||
| 124 | #include <sys/mtio.h> | ||
| 125 | #include <sys/kd.h> | ||
| 126 | #include <sys/shm.h> | ||
| 127 | #include <sys/statvfs.h> | ||
| 128 | #include <sys/timex.h> | ||
| 129 | #if defined(__mips64) | ||
| 130 | # include <sys/procfs.h> | ||
| 131 | #endif | ||
| 132 | #include <sys/user.h> | ||
| 133 | #include <linux/cyclades.h> | ||
| 134 | #include <linux/if_eql.h> | ||
| 135 | #include <linux/if_plip.h> | ||
| 136 | #include <linux/lp.h> | ||
| 137 | #include <linux/mroute.h> | ||
| 138 | #include <linux/mroute6.h> | ||
| 139 | #include <linux/scc.h> | ||
| 140 | #include <linux/serial.h> | ||
| 141 | #include <sys/msg.h> | ||
| 142 | #include <sys/ipc.h> | ||
| 143 | #include <crypt.h> | ||
| 144 | #endif // SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 145 | |||
| 146 | #if SANITIZER_ANDROID | ||
| 147 | #include <linux/kd.h> | ||
| 148 | #include <linux/mtio.h> | ||
| 149 | #include <linux/ppp_defs.h> | ||
| 150 | #include <linux/if_ppp.h> | ||
| 151 | #endif | ||
| 152 | |||
| 153 | #if SANITIZER_LINUX | ||
| 154 | #include <link.h> | ||
| 155 | #include <sys/vfs.h> | ||
| 156 | #include <sys/epoll.h> | ||
| 157 | #include <linux/capability.h> | ||
| 158 | #endif // SANITIZER_LINUX | ||
| 159 | |||
| 160 | #if SANITIZER_MAC | ||
| 161 | #include <net/ethernet.h> | ||
| 162 | #include <sys/filio.h> | ||
| 163 | #include <sys/sockio.h> | ||
| 164 | #endif | ||
| 165 | |||
| 166 | // Include these after system headers to avoid name clashes and ambiguities. | ||
| 167 | #include "sanitizer_internal_defs.h" | ||
| 168 | #include "sanitizer_platform_limits_posix.h" | ||
| 169 | |||
| 170 | namespace __sanitizer { | ||
| 171 | unsigned struct_utsname_sz = sizeof(struct utsname); | ||
| 172 | unsigned struct_stat_sz = sizeof(struct stat); | ||
| 173 | #if !SANITIZER_IOS && !(SANITIZER_MAC && TARGET_CPU_ARM64) | ||
| 174 | unsigned struct_stat64_sz = sizeof(struct stat64); | ||
| 175 | #endif // !SANITIZER_IOS && !(SANITIZER_MAC && TARGET_CPU_ARM64) | ||
| 176 | unsigned struct_rusage_sz = sizeof(struct rusage); | ||
| 177 | unsigned struct_tm_sz = sizeof(struct tm); | ||
| 178 | unsigned struct_passwd_sz = sizeof(struct passwd); | ||
| 179 | unsigned struct_group_sz = sizeof(struct group); | ||
| 180 | unsigned siginfo_t_sz = sizeof(siginfo_t); | ||
| 181 | unsigned struct_sigaction_sz = sizeof(struct sigaction); | ||
| 182 | unsigned struct_stack_t_sz = sizeof(stack_t); | ||
| 183 | unsigned struct_itimerval_sz = sizeof(struct itimerval); | ||
| 184 | unsigned pthread_t_sz = sizeof(pthread_t); | ||
| 185 | unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); | ||
| 186 | unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); | ||
| 187 | unsigned pid_t_sz = sizeof(pid_t); | ||
| 188 | unsigned timeval_sz = sizeof(timeval); | ||
| 189 | unsigned uid_t_sz = sizeof(uid_t); | ||
| 190 | unsigned gid_t_sz = sizeof(gid_t); | ||
| 191 | unsigned mbstate_t_sz = sizeof(mbstate_t); | ||
| 192 | unsigned sigset_t_sz = sizeof(sigset_t); | ||
| 193 | unsigned struct_timezone_sz = sizeof(struct timezone); | ||
| 194 | unsigned struct_tms_sz = sizeof(struct tms); | ||
| 195 | unsigned struct_sigevent_sz = sizeof(struct sigevent); | ||
| 196 | unsigned struct_sched_param_sz = sizeof(struct sched_param); | ||
| 197 | unsigned struct_regex_sz = sizeof(regex_t); | ||
| 198 | unsigned struct_regmatch_sz = sizeof(regmatch_t); | ||
| 199 | |||
| 200 | #if (SANITIZER_MAC && !TARGET_CPU_ARM64) && !SANITIZER_IOS | ||
| 201 | unsigned struct_statfs64_sz = sizeof(struct statfs64); | ||
| 202 | #endif // (SANITIZER_MAC && !TARGET_CPU_ARM64) && !SANITIZER_IOS | ||
| 203 | |||
| 204 | #if !SANITIZER_ANDROID | ||
| 205 | unsigned struct_fstab_sz = sizeof(struct fstab); | ||
| 206 | unsigned struct_statfs_sz = sizeof(struct statfs); | ||
| 207 | unsigned struct_sockaddr_sz = sizeof(struct sockaddr); | ||
| 208 | unsigned ucontext_t_sz = sizeof(ucontext_t); | ||
| 209 | #endif // !SANITIZER_ANDROID | ||
| 210 | |||
| 211 | #if SANITIZER_LINUX | ||
| 212 | unsigned struct_epoll_event_sz = sizeof(struct epoll_event); | ||
| 213 | unsigned struct_sysinfo_sz = sizeof(struct sysinfo); | ||
| 214 | unsigned __user_cap_header_struct_sz = | ||
| 215 | sizeof(struct __user_cap_header_struct); | ||
| 216 | unsigned __user_cap_data_struct_sz = sizeof(struct __user_cap_data_struct); | ||
| 217 | unsigned struct_new_utsname_sz = sizeof(struct new_utsname); | ||
| 218 | unsigned struct_old_utsname_sz = sizeof(struct old_utsname); | ||
| 219 | unsigned struct_oldold_utsname_sz = sizeof(struct oldold_utsname); | ||
| 220 | #endif // SANITIZER_LINUX | ||
| 221 | |||
| 222 | #if SANITIZER_LINUX | ||
| 223 | unsigned struct_rlimit_sz = sizeof(struct rlimit); | ||
| 224 | unsigned struct_timespec_sz = sizeof(struct timespec); | ||
| 225 | unsigned struct_utimbuf_sz = sizeof(struct utimbuf); | ||
| 226 | unsigned struct_itimerspec_sz = sizeof(struct itimerspec); | ||
| 227 | #endif // SANITIZER_LINUX | ||
| 228 | |||
| 229 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 230 | // Use pre-computed size of struct ustat to avoid <sys/ustat.h> which | ||
| 231 | // has been removed from glibc 2.28. | ||
| 232 | #if defined(__aarch64__) || defined(__s390x__) || defined (__mips64) \ | ||
| 233 | || defined(__powerpc64__) || defined(__arch64__) || defined(__sparcv9) \ | ||
| 234 | || defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64) | ||
| 235 | #define SIZEOF_STRUCT_USTAT 32 | ||
| 236 | #elif defined(__arm__) || defined(__i386__) || defined(__mips__) \ | ||
| 237 | || defined(__powerpc__) || defined(__s390__) || defined(__sparc__) | ||
| 238 | #define SIZEOF_STRUCT_USTAT 20 | ||
| 239 | #else | ||
| 240 | #error Unknown size of struct ustat | ||
| 241 | #endif | ||
| 242 | unsigned struct_ustat_sz = SIZEOF_STRUCT_USTAT; | ||
| 243 | unsigned struct_rlimit64_sz = sizeof(struct rlimit64); | ||
| 244 | unsigned struct_statvfs64_sz = sizeof(struct statvfs64); | ||
| 245 | unsigned struct_crypt_data_sz = sizeof(struct crypt_data); | ||
| 246 | #endif // SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 247 | |||
| 248 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 249 | unsigned struct_timex_sz = sizeof(struct timex); | ||
| 250 | unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); | ||
| 251 | unsigned struct_mq_attr_sz = sizeof(struct mq_attr); | ||
| 252 | unsigned struct_statvfs_sz = sizeof(struct statvfs); | ||
| 253 | #endif // SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 254 | |||
| 255 | const uptr sig_ign = (uptr)SIG_IGN; | ||
| 256 | const uptr sig_dfl = (uptr)SIG_DFL; | ||
| 257 | const uptr sig_err = (uptr)SIG_ERR; | ||
| 258 | const uptr sa_siginfo = (uptr)SA_SIGINFO; | ||
| 259 | |||
| 260 | #if SANITIZER_LINUX | ||
| 261 | int e_tabsz = (int)E_TABSZ; | ||
| 262 | #endif | ||
| 263 | |||
| 264 | |||
| 265 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 266 | unsigned struct_shminfo_sz = sizeof(struct shminfo); | ||
| 267 | unsigned struct_shm_info_sz = sizeof(struct shm_info); | ||
| 268 | int shmctl_ipc_stat = (int)IPC_STAT; | ||
| 269 | int shmctl_ipc_info = (int)IPC_INFO; | ||
| 270 | int shmctl_shm_info = (int)SHM_INFO; | ||
| 271 | int shmctl_shm_stat = (int)SHM_STAT; | ||
| 272 | #endif | ||
| 273 | |||
| 274 | #if !SANITIZER_MAC && !SANITIZER_FREEBSD | ||
| 275 | unsigned struct_utmp_sz = sizeof(struct utmp); | ||
| 276 | #endif | ||
| 277 | #if !SANITIZER_ANDROID | ||
| 278 | unsigned struct_utmpx_sz = sizeof(struct utmpx); | ||
| 279 | #endif | ||
| 280 | |||
| 281 | int map_fixed = MAP_FIXED; | ||
| 282 | |||
| 283 | int af_inet = (int)AF_INET; | ||
| 284 | int af_inet6 = (int)AF_INET6; | ||
| 285 | |||
| 286 | uptr __sanitizer_in_addr_sz(int af) { | ||
| 287 | if (af == AF_INET) | ||
| 288 | return sizeof(struct in_addr); | ||
| 289 | else if (af == AF_INET6) | ||
| 290 | return sizeof(struct in6_addr); | ||
| 291 | else | ||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | |||
| 295 | #if SANITIZER_LINUX | ||
| 296 | unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr)); | ||
| 297 | #elif SANITIZER_FREEBSD | ||
| 298 | unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); | ||
| 299 | #endif | ||
| 300 | |||
| 301 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 302 | int glob_nomatch = GLOB_NOMATCH; | ||
| 303 | int glob_altdirfunc = GLOB_ALTDIRFUNC; | ||
| 304 | #endif | ||
| 305 | |||
| 306 | #if SANITIZER_LINUX && !SANITIZER_ANDROID && \ | ||
| 307 | (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ | ||
| 308 | defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ | ||
| 309 | defined(__s390__)) | ||
| 310 | #if defined(__mips64) || defined(__powerpc64__) || defined(__arm__) | ||
| 311 | unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs); | ||
| 312 | unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t); | ||
| 313 | #elif defined(__aarch64__) | ||
| 314 | unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs); | ||
| 315 | unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpsimd_state); | ||
| 316 | #elif defined(__s390__) | ||
| 317 | unsigned struct_user_regs_struct_sz = sizeof(struct _user_regs_struct); | ||
| 318 | unsigned struct_user_fpregs_struct_sz = sizeof(struct _user_fpregs_struct); | ||
| 319 | #else | ||
| 320 | unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct); | ||
| 321 | unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct); | ||
| 322 | #endif // __mips64 || __powerpc64__ || __aarch64__ | ||
| 323 | #if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \ | ||
| 324 | defined(__aarch64__) || defined(__arm__) || defined(__s390__) | ||
| 325 | unsigned struct_user_fpxregs_struct_sz = 0; | ||
| 326 | #else | ||
| 327 | unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct); | ||
| 328 | #endif // __x86_64 || __mips64 || __powerpc64__ || __aarch64__ || __arm__ | ||
| 329 | // || __s390__ | ||
| 330 | #ifdef __arm__ | ||
| 331 | unsigned struct_user_vfpregs_struct_sz = ARM_VFPREGS_SIZE; | ||
| 332 | #else | ||
| 333 | unsigned struct_user_vfpregs_struct_sz = 0; | ||
| 334 | #endif | ||
| 335 | |||
| 336 | int ptrace_peektext = PTRACE_PEEKTEXT; | ||
| 337 | int ptrace_peekdata = PTRACE_PEEKDATA; | ||
| 338 | int ptrace_peekuser = PTRACE_PEEKUSER; | ||
| 339 | #if (defined(PTRACE_GETREGS) && defined(PTRACE_SETREGS)) || \ | ||
| 340 | (defined(PT_GETREGS) && defined(PT_SETREGS)) | ||
| 341 | int ptrace_getregs = PTRACE_GETREGS; | ||
| 342 | int ptrace_setregs = PTRACE_SETREGS; | ||
| 343 | #else | ||
| 344 | int ptrace_getregs = -1; | ||
| 345 | int ptrace_setregs = -1; | ||
| 346 | #endif | ||
| 347 | #if (defined(PTRACE_GETFPREGS) && defined(PTRACE_SETFPREGS)) || \ | ||
| 348 | (defined(PT_GETFPREGS) && defined(PT_SETFPREGS)) | ||
| 349 | int ptrace_getfpregs = PTRACE_GETFPREGS; | ||
| 350 | int ptrace_setfpregs = PTRACE_SETFPREGS; | ||
| 351 | #else | ||
| 352 | int ptrace_getfpregs = -1; | ||
| 353 | int ptrace_setfpregs = -1; | ||
| 354 | #endif | ||
| 355 | #if (defined(PTRACE_GETFPXREGS) && defined(PTRACE_SETFPXREGS)) || \ | ||
| 356 | (defined(PT_GETFPXREGS) && defined(PT_SETFPXREGS)) | ||
| 357 | int ptrace_getfpxregs = PTRACE_GETFPXREGS; | ||
| 358 | int ptrace_setfpxregs = PTRACE_SETFPXREGS; | ||
| 359 | #else | ||
| 360 | int ptrace_getfpxregs = -1; | ||
| 361 | int ptrace_setfpxregs = -1; | ||
| 362 | #endif // PTRACE_GETFPXREGS/PTRACE_SETFPXREGS | ||
| 363 | #if defined(PTRACE_GETVFPREGS) && defined(PTRACE_SETVFPREGS) | ||
| 364 | int ptrace_getvfpregs = PTRACE_GETVFPREGS; | ||
| 365 | int ptrace_setvfpregs = PTRACE_SETVFPREGS; | ||
| 366 | #else | ||
| 367 | int ptrace_getvfpregs = -1; | ||
| 368 | int ptrace_setvfpregs = -1; | ||
| 369 | #endif | ||
| 370 | int ptrace_geteventmsg = PTRACE_GETEVENTMSG; | ||
| 371 | #if (defined(PTRACE_GETSIGINFO) && defined(PTRACE_SETSIGINFO)) || \ | ||
| 372 | (defined(PT_GETSIGINFO) && defined(PT_SETSIGINFO)) | ||
| 373 | int ptrace_getsiginfo = PTRACE_GETSIGINFO; | ||
| 374 | int ptrace_setsiginfo = PTRACE_SETSIGINFO; | ||
| 375 | #else | ||
| 376 | int ptrace_getsiginfo = -1; | ||
| 377 | int ptrace_setsiginfo = -1; | ||
| 378 | #endif // PTRACE_GETSIGINFO/PTRACE_SETSIGINFO | ||
| 379 | #if defined(PTRACE_GETREGSET) && defined(PTRACE_SETREGSET) | ||
| 380 | int ptrace_getregset = PTRACE_GETREGSET; | ||
| 381 | int ptrace_setregset = PTRACE_SETREGSET; | ||
| 382 | #else | ||
| 383 | int ptrace_getregset = -1; | ||
| 384 | int ptrace_setregset = -1; | ||
| 385 | #endif // PTRACE_GETREGSET/PTRACE_SETREGSET | ||
| 386 | #endif | ||
| 387 | |||
| 388 | unsigned path_max = PATH_MAX; | ||
| 389 | |||
| 390 | // ioctl arguments | ||
| 391 | unsigned struct_ifreq_sz = sizeof(struct ifreq); | ||
| 392 | unsigned struct_termios_sz = sizeof(struct termios); | ||
| 393 | unsigned struct_winsize_sz = sizeof(struct winsize); | ||
| 394 | |||
| 395 | #if SANITIZER_LINUX | ||
| 396 | unsigned struct_arpreq_sz = sizeof(struct arpreq); | ||
| 397 | unsigned struct_cdrom_msf_sz = sizeof(struct cdrom_msf); | ||
| 398 | unsigned struct_cdrom_multisession_sz = sizeof(struct cdrom_multisession); | ||
| 399 | unsigned struct_cdrom_read_audio_sz = sizeof(struct cdrom_read_audio); | ||
| 400 | unsigned struct_cdrom_subchnl_sz = sizeof(struct cdrom_subchnl); | ||
| 401 | unsigned struct_cdrom_ti_sz = sizeof(struct cdrom_ti); | ||
| 402 | unsigned struct_cdrom_tocentry_sz = sizeof(struct cdrom_tocentry); | ||
| 403 | unsigned struct_cdrom_tochdr_sz = sizeof(struct cdrom_tochdr); | ||
| 404 | unsigned struct_cdrom_volctrl_sz = sizeof(struct cdrom_volctrl); | ||
| 405 | unsigned struct_ff_effect_sz = sizeof(struct ff_effect); | ||
| 406 | unsigned struct_floppy_drive_params_sz = sizeof(struct floppy_drive_params); | ||
| 407 | unsigned struct_floppy_drive_struct_sz = sizeof(struct floppy_drive_struct); | ||
| 408 | unsigned struct_floppy_fdc_state_sz = sizeof(struct floppy_fdc_state); | ||
| 409 | unsigned struct_floppy_max_errors_sz = sizeof(struct floppy_max_errors); | ||
| 410 | unsigned struct_floppy_raw_cmd_sz = sizeof(struct floppy_raw_cmd); | ||
| 411 | unsigned struct_floppy_struct_sz = sizeof(struct floppy_struct); | ||
| 412 | unsigned struct_floppy_write_errors_sz = sizeof(struct floppy_write_errors); | ||
| 413 | unsigned struct_format_descr_sz = sizeof(struct format_descr); | ||
| 414 | unsigned struct_hd_driveid_sz = sizeof(struct hd_driveid); | ||
| 415 | unsigned struct_hd_geometry_sz = sizeof(struct hd_geometry); | ||
| 416 | unsigned struct_input_absinfo_sz = sizeof(struct input_absinfo); | ||
| 417 | unsigned struct_input_id_sz = sizeof(struct input_id); | ||
| 418 | unsigned struct_mtpos_sz = sizeof(struct mtpos); | ||
| 419 | unsigned struct_rtentry_sz = sizeof(struct rtentry); | ||
| 420 | unsigned struct_termio_sz = sizeof(struct termio); | ||
| 421 | unsigned struct_vt_consize_sz = sizeof(struct vt_consize); | ||
| 422 | unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes); | ||
| 423 | unsigned struct_vt_stat_sz = sizeof(struct vt_stat); | ||
| 424 | #endif // SANITIZER_LINUX | ||
| 425 | |||
| 426 | #if SANITIZER_LINUX | ||
| 427 | #if SOUND_VERSION >= 0x040000 | ||
| 428 | unsigned struct_copr_buffer_sz = 0; | ||
| 429 | unsigned struct_copr_debug_buf_sz = 0; | ||
| 430 | unsigned struct_copr_msg_sz = 0; | ||
| 431 | #else | ||
| 432 | unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer); | ||
| 433 | unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf); | ||
| 434 | unsigned struct_copr_msg_sz = sizeof(struct copr_msg); | ||
| 435 | #endif | ||
| 436 | unsigned struct_midi_info_sz = sizeof(struct midi_info); | ||
| 437 | unsigned struct_mtget_sz = sizeof(struct mtget); | ||
| 438 | unsigned struct_mtop_sz = sizeof(struct mtop); | ||
| 439 | unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument); | ||
| 440 | unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec); | ||
| 441 | unsigned struct_synth_info_sz = sizeof(struct synth_info); | ||
| 442 | unsigned struct_vt_mode_sz = sizeof(struct vt_mode); | ||
| 443 | #endif // SANITIZER_LINUX | ||
| 444 | |||
| 445 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 446 | unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct); | ||
| 447 | unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor); | ||
| 448 | #if EV_VERSION > (0x010000) | ||
| 449 | unsigned struct_input_keymap_entry_sz = sizeof(struct input_keymap_entry); | ||
| 450 | #else | ||
| 451 | unsigned struct_input_keymap_entry_sz = 0; | ||
| 452 | #endif | ||
| 453 | unsigned struct_ipx_config_data_sz = sizeof(struct ipx_config_data); | ||
| 454 | unsigned struct_kbdiacrs_sz = sizeof(struct kbdiacrs); | ||
| 455 | unsigned struct_kbentry_sz = sizeof(struct kbentry); | ||
| 456 | unsigned struct_kbkeycode_sz = sizeof(struct kbkeycode); | ||
| 457 | unsigned struct_kbsentry_sz = sizeof(struct kbsentry); | ||
| 458 | unsigned struct_mtconfiginfo_sz = sizeof(struct mtconfiginfo); | ||
| 459 | unsigned struct_nr_parms_struct_sz = sizeof(struct nr_parms_struct); | ||
| 460 | unsigned struct_scc_modem_sz = sizeof(struct scc_modem); | ||
| 461 | unsigned struct_scc_stat_sz = sizeof(struct scc_stat); | ||
| 462 | unsigned struct_serial_multiport_struct_sz | ||
| 463 | = sizeof(struct serial_multiport_struct); | ||
| 464 | unsigned struct_serial_struct_sz = sizeof(struct serial_struct); | ||
| 465 | unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25); | ||
| 466 | unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc); | ||
| 467 | unsigned struct_unimapinit_sz = sizeof(struct unimapinit); | ||
| 468 | #endif // SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 469 | |||
| 470 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 471 | unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); | ||
| 472 | unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); | ||
| 473 | #endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID | ||
| 474 | |||
| 475 | #if !SANITIZER_ANDROID && !SANITIZER_MAC | ||
| 476 | unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); | ||
| 477 | unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); | ||
| 478 | #endif | ||
| 479 | |||
| 480 | const unsigned long __sanitizer_bufsiz = BUFSIZ; | ||
| 481 | |||
| 482 | const unsigned IOCTL_NOT_PRESENT = 0; | ||
| 483 | |||
| 484 | unsigned IOCTL_FIOASYNC = FIOASYNC; | ||
| 485 | unsigned IOCTL_FIOCLEX = FIOCLEX; | ||
| 486 | unsigned IOCTL_FIOGETOWN = FIOGETOWN; | ||
| 487 | unsigned IOCTL_FIONBIO = FIONBIO; | ||
| 488 | unsigned IOCTL_FIONCLEX = FIONCLEX; | ||
| 489 | unsigned IOCTL_FIOSETOWN = FIOSETOWN; | ||
| 490 | unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; | ||
| 491 | unsigned IOCTL_SIOCATMARK = SIOCATMARK; | ||
| 492 | unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; | ||
| 493 | unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; | ||
| 494 | unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; | ||
| 495 | unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; | ||
| 496 | unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; | ||
| 497 | unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; | ||
| 498 | unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; | ||
| 499 | unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; | ||
| 500 | unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; | ||
| 501 | unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; | ||
| 502 | unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; | ||
| 503 | unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; | ||
| 504 | unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; | ||
| 505 | unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; | ||
| 506 | unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; | ||
| 507 | unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; | ||
| 508 | unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; | ||
| 509 | unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; | ||
| 510 | unsigned IOCTL_TIOCCONS = TIOCCONS; | ||
| 511 | unsigned IOCTL_TIOCEXCL = TIOCEXCL; | ||
| 512 | unsigned IOCTL_TIOCGETD = TIOCGETD; | ||
| 513 | unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; | ||
| 514 | unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; | ||
| 515 | unsigned IOCTL_TIOCMBIC = TIOCMBIC; | ||
| 516 | unsigned IOCTL_TIOCMBIS = TIOCMBIS; | ||
| 517 | unsigned IOCTL_TIOCMGET = TIOCMGET; | ||
| 518 | unsigned IOCTL_TIOCMSET = TIOCMSET; | ||
| 519 | unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; | ||
| 520 | unsigned IOCTL_TIOCNXCL = TIOCNXCL; | ||
| 521 | unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; | ||
| 522 | unsigned IOCTL_TIOCPKT = TIOCPKT; | ||
| 523 | unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; | ||
| 524 | unsigned IOCTL_TIOCSETD = TIOCSETD; | ||
| 525 | unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; | ||
| 526 | unsigned IOCTL_TIOCSTI = TIOCSTI; | ||
| 527 | unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; | ||
| 528 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 529 | unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; | ||
| 530 | unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; | ||
| 531 | #endif | ||
| 532 | |||
| 533 | #if SANITIZER_LINUX | ||
| 534 | unsigned IOCTL_EVIOCGABS = EVIOCGABS(0); | ||
| 535 | unsigned IOCTL_EVIOCGBIT = EVIOCGBIT(0, 0); | ||
| 536 | unsigned IOCTL_EVIOCGEFFECTS = EVIOCGEFFECTS; | ||
| 537 | unsigned IOCTL_EVIOCGID = EVIOCGID; | ||
| 538 | unsigned IOCTL_EVIOCGKEY = EVIOCGKEY(0); | ||
| 539 | unsigned IOCTL_EVIOCGKEYCODE = EVIOCGKEYCODE; | ||
| 540 | unsigned IOCTL_EVIOCGLED = EVIOCGLED(0); | ||
| 541 | unsigned IOCTL_EVIOCGNAME = EVIOCGNAME(0); | ||
| 542 | unsigned IOCTL_EVIOCGPHYS = EVIOCGPHYS(0); | ||
| 543 | unsigned IOCTL_EVIOCGRAB = EVIOCGRAB; | ||
| 544 | unsigned IOCTL_EVIOCGREP = EVIOCGREP; | ||
| 545 | unsigned IOCTL_EVIOCGSND = EVIOCGSND(0); | ||
| 546 | unsigned IOCTL_EVIOCGSW = EVIOCGSW(0); | ||
| 547 | unsigned IOCTL_EVIOCGUNIQ = EVIOCGUNIQ(0); | ||
| 548 | unsigned IOCTL_EVIOCGVERSION = EVIOCGVERSION; | ||
| 549 | unsigned IOCTL_EVIOCRMFF = EVIOCRMFF; | ||
| 550 | unsigned IOCTL_EVIOCSABS = EVIOCSABS(0); | ||
| 551 | unsigned IOCTL_EVIOCSFF = EVIOCSFF; | ||
| 552 | unsigned IOCTL_EVIOCSKEYCODE = EVIOCSKEYCODE; | ||
| 553 | unsigned IOCTL_EVIOCSREP = EVIOCSREP; | ||
| 554 | unsigned IOCTL_BLKFLSBUF = BLKFLSBUF; | ||
| 555 | unsigned IOCTL_BLKGETSIZE = BLKGETSIZE; | ||
| 556 | unsigned IOCTL_BLKRAGET = BLKRAGET; | ||
| 557 | unsigned IOCTL_BLKRASET = BLKRASET; | ||
| 558 | unsigned IOCTL_BLKROGET = BLKROGET; | ||
| 559 | unsigned IOCTL_BLKROSET = BLKROSET; | ||
| 560 | unsigned IOCTL_BLKRRPART = BLKRRPART; | ||
| 561 | unsigned IOCTL_CDROMAUDIOBUFSIZ = CDROMAUDIOBUFSIZ; | ||
| 562 | unsigned IOCTL_CDROMEJECT = CDROMEJECT; | ||
| 563 | unsigned IOCTL_CDROMEJECT_SW = CDROMEJECT_SW; | ||
| 564 | unsigned IOCTL_CDROMMULTISESSION = CDROMMULTISESSION; | ||
| 565 | unsigned IOCTL_CDROMPAUSE = CDROMPAUSE; | ||
| 566 | unsigned IOCTL_CDROMPLAYMSF = CDROMPLAYMSF; | ||
| 567 | unsigned IOCTL_CDROMPLAYTRKIND = CDROMPLAYTRKIND; | ||
| 568 | unsigned IOCTL_CDROMREADAUDIO = CDROMREADAUDIO; | ||
| 569 | unsigned IOCTL_CDROMREADCOOKED = CDROMREADCOOKED; | ||
| 570 | unsigned IOCTL_CDROMREADMODE1 = CDROMREADMODE1; | ||
| 571 | unsigned IOCTL_CDROMREADMODE2 = CDROMREADMODE2; | ||
| 572 | unsigned IOCTL_CDROMREADRAW = CDROMREADRAW; | ||
| 573 | unsigned IOCTL_CDROMREADTOCENTRY = CDROMREADTOCENTRY; | ||
| 574 | unsigned IOCTL_CDROMREADTOCHDR = CDROMREADTOCHDR; | ||
| 575 | unsigned IOCTL_CDROMRESET = CDROMRESET; | ||
| 576 | unsigned IOCTL_CDROMRESUME = CDROMRESUME; | ||
| 577 | unsigned IOCTL_CDROMSEEK = CDROMSEEK; | ||
| 578 | unsigned IOCTL_CDROMSTART = CDROMSTART; | ||
| 579 | unsigned IOCTL_CDROMSTOP = CDROMSTOP; | ||
| 580 | unsigned IOCTL_CDROMSUBCHNL = CDROMSUBCHNL; | ||
| 581 | unsigned IOCTL_CDROMVOLCTRL = CDROMVOLCTRL; | ||
| 582 | unsigned IOCTL_CDROMVOLREAD = CDROMVOLREAD; | ||
| 583 | unsigned IOCTL_CDROM_GET_UPC = CDROM_GET_UPC; | ||
| 584 | unsigned IOCTL_FDCLRPRM = FDCLRPRM; | ||
| 585 | unsigned IOCTL_FDDEFPRM = FDDEFPRM; | ||
| 586 | unsigned IOCTL_FDFLUSH = FDFLUSH; | ||
| 587 | unsigned IOCTL_FDFMTBEG = FDFMTBEG; | ||
| 588 | unsigned IOCTL_FDFMTEND = FDFMTEND; | ||
| 589 | unsigned IOCTL_FDFMTTRK = FDFMTTRK; | ||
| 590 | unsigned IOCTL_FDGETDRVPRM = FDGETDRVPRM; | ||
| 591 | unsigned IOCTL_FDGETDRVSTAT = FDGETDRVSTAT; | ||
| 592 | unsigned IOCTL_FDGETDRVTYP = FDGETDRVTYP; | ||
| 593 | unsigned IOCTL_FDGETFDCSTAT = FDGETFDCSTAT; | ||
| 594 | unsigned IOCTL_FDGETMAXERRS = FDGETMAXERRS; | ||
| 595 | unsigned IOCTL_FDGETPRM = FDGETPRM; | ||
| 596 | unsigned IOCTL_FDMSGOFF = FDMSGOFF; | ||
| 597 | unsigned IOCTL_FDMSGON = FDMSGON; | ||
| 598 | unsigned IOCTL_FDPOLLDRVSTAT = FDPOLLDRVSTAT; | ||
| 599 | unsigned IOCTL_FDRAWCMD = FDRAWCMD; | ||
| 600 | unsigned IOCTL_FDRESET = FDRESET; | ||
| 601 | unsigned IOCTL_FDSETDRVPRM = FDSETDRVPRM; | ||
| 602 | unsigned IOCTL_FDSETEMSGTRESH = FDSETEMSGTRESH; | ||
| 603 | unsigned IOCTL_FDSETMAXERRS = FDSETMAXERRS; | ||
| 604 | unsigned IOCTL_FDSETPRM = FDSETPRM; | ||
| 605 | unsigned IOCTL_FDTWADDLE = FDTWADDLE; | ||
| 606 | unsigned IOCTL_FDWERRORCLR = FDWERRORCLR; | ||
| 607 | unsigned IOCTL_FDWERRORGET = FDWERRORGET; | ||
| 608 | unsigned IOCTL_HDIO_DRIVE_CMD = HDIO_DRIVE_CMD; | ||
| 609 | unsigned IOCTL_HDIO_GETGEO = HDIO_GETGEO; | ||
| 610 | unsigned IOCTL_HDIO_GET_32BIT = HDIO_GET_32BIT; | ||
| 611 | unsigned IOCTL_HDIO_GET_DMA = HDIO_GET_DMA; | ||
| 612 | unsigned IOCTL_HDIO_GET_IDENTITY = HDIO_GET_IDENTITY; | ||
| 613 | unsigned IOCTL_HDIO_GET_KEEPSETTINGS = HDIO_GET_KEEPSETTINGS; | ||
| 614 | unsigned IOCTL_HDIO_GET_MULTCOUNT = HDIO_GET_MULTCOUNT; | ||
| 615 | unsigned IOCTL_HDIO_GET_NOWERR = HDIO_GET_NOWERR; | ||
| 616 | unsigned IOCTL_HDIO_GET_UNMASKINTR = HDIO_GET_UNMASKINTR; | ||
| 617 | unsigned IOCTL_HDIO_SET_32BIT = HDIO_SET_32BIT; | ||
| 618 | unsigned IOCTL_HDIO_SET_DMA = HDIO_SET_DMA; | ||
| 619 | unsigned IOCTL_HDIO_SET_KEEPSETTINGS = HDIO_SET_KEEPSETTINGS; | ||
| 620 | unsigned IOCTL_HDIO_SET_MULTCOUNT = HDIO_SET_MULTCOUNT; | ||
| 621 | unsigned IOCTL_HDIO_SET_NOWERR = HDIO_SET_NOWERR; | ||
| 622 | unsigned IOCTL_HDIO_SET_UNMASKINTR = HDIO_SET_UNMASKINTR; | ||
| 623 | unsigned IOCTL_MTIOCPOS = MTIOCPOS; | ||
| 624 | unsigned IOCTL_PPPIOCGASYNCMAP = PPPIOCGASYNCMAP; | ||
| 625 | unsigned IOCTL_PPPIOCGDEBUG = PPPIOCGDEBUG; | ||
| 626 | unsigned IOCTL_PPPIOCGFLAGS = PPPIOCGFLAGS; | ||
| 627 | unsigned IOCTL_PPPIOCGUNIT = PPPIOCGUNIT; | ||
| 628 | unsigned IOCTL_PPPIOCGXASYNCMAP = PPPIOCGXASYNCMAP; | ||
| 629 | unsigned IOCTL_PPPIOCSASYNCMAP = PPPIOCSASYNCMAP; | ||
| 630 | unsigned IOCTL_PPPIOCSDEBUG = PPPIOCSDEBUG; | ||
| 631 | unsigned IOCTL_PPPIOCSFLAGS = PPPIOCSFLAGS; | ||
| 632 | unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID; | ||
| 633 | unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU; | ||
| 634 | unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP; | ||
| 635 | unsigned IOCTL_SIOCADDRT = SIOCADDRT; | ||
| 636 | unsigned IOCTL_SIOCDARP = SIOCDARP; | ||
| 637 | unsigned IOCTL_SIOCDELRT = SIOCDELRT; | ||
| 638 | unsigned IOCTL_SIOCDRARP = SIOCDRARP; | ||
| 639 | unsigned IOCTL_SIOCGARP = SIOCGARP; | ||
| 640 | unsigned IOCTL_SIOCGIFENCAP = SIOCGIFENCAP; | ||
| 641 | unsigned IOCTL_SIOCGIFHWADDR = SIOCGIFHWADDR; | ||
| 642 | unsigned IOCTL_SIOCGIFMAP = SIOCGIFMAP; | ||
| 643 | unsigned IOCTL_SIOCGIFMEM = SIOCGIFMEM; | ||
| 644 | unsigned IOCTL_SIOCGIFNAME = SIOCGIFNAME; | ||
| 645 | unsigned IOCTL_SIOCGIFSLAVE = SIOCGIFSLAVE; | ||
| 646 | unsigned IOCTL_SIOCGRARP = SIOCGRARP; | ||
| 647 | unsigned IOCTL_SIOCGSTAMP = SIOCGSTAMP; | ||
| 648 | unsigned IOCTL_SIOCSARP = SIOCSARP; | ||
| 649 | unsigned IOCTL_SIOCSIFENCAP = SIOCSIFENCAP; | ||
| 650 | unsigned IOCTL_SIOCSIFHWADDR = SIOCSIFHWADDR; | ||
| 651 | unsigned IOCTL_SIOCSIFLINK = SIOCSIFLINK; | ||
| 652 | unsigned IOCTL_SIOCSIFMAP = SIOCSIFMAP; | ||
| 653 | unsigned IOCTL_SIOCSIFMEM = SIOCSIFMEM; | ||
| 654 | unsigned IOCTL_SIOCSIFSLAVE = SIOCSIFSLAVE; | ||
| 655 | unsigned IOCTL_SIOCSRARP = SIOCSRARP; | ||
| 656 | # if SOUND_VERSION >= 0x040000 | ||
| 657 | unsigned IOCTL_SNDCTL_COPR_HALT = IOCTL_NOT_PRESENT; | ||
| 658 | unsigned IOCTL_SNDCTL_COPR_LOAD = IOCTL_NOT_PRESENT; | ||
| 659 | unsigned IOCTL_SNDCTL_COPR_RCODE = IOCTL_NOT_PRESENT; | ||
| 660 | unsigned IOCTL_SNDCTL_COPR_RCVMSG = IOCTL_NOT_PRESENT; | ||
| 661 | unsigned IOCTL_SNDCTL_COPR_RDATA = IOCTL_NOT_PRESENT; | ||
| 662 | unsigned IOCTL_SNDCTL_COPR_RESET = IOCTL_NOT_PRESENT; | ||
| 663 | unsigned IOCTL_SNDCTL_COPR_RUN = IOCTL_NOT_PRESENT; | ||
| 664 | unsigned IOCTL_SNDCTL_COPR_SENDMSG = IOCTL_NOT_PRESENT; | ||
| 665 | unsigned IOCTL_SNDCTL_COPR_WCODE = IOCTL_NOT_PRESENT; | ||
| 666 | unsigned IOCTL_SNDCTL_COPR_WDATA = IOCTL_NOT_PRESENT; | ||
| 667 | unsigned IOCTL_SOUND_PCM_READ_BITS = IOCTL_NOT_PRESENT; | ||
| 668 | unsigned IOCTL_SOUND_PCM_READ_CHANNELS = IOCTL_NOT_PRESENT; | ||
| 669 | unsigned IOCTL_SOUND_PCM_READ_FILTER = IOCTL_NOT_PRESENT; | ||
| 670 | unsigned IOCTL_SOUND_PCM_READ_RATE = IOCTL_NOT_PRESENT; | ||
| 671 | unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = IOCTL_NOT_PRESENT; | ||
| 672 | unsigned IOCTL_SOUND_PCM_WRITE_FILTER = IOCTL_NOT_PRESENT; | ||
| 673 | # else // SOUND_VERSION | ||
| 674 | unsigned IOCTL_SNDCTL_COPR_HALT = SNDCTL_COPR_HALT; | ||
| 675 | unsigned IOCTL_SNDCTL_COPR_LOAD = SNDCTL_COPR_LOAD; | ||
| 676 | unsigned IOCTL_SNDCTL_COPR_RCODE = SNDCTL_COPR_RCODE; | ||
| 677 | unsigned IOCTL_SNDCTL_COPR_RCVMSG = SNDCTL_COPR_RCVMSG; | ||
| 678 | unsigned IOCTL_SNDCTL_COPR_RDATA = SNDCTL_COPR_RDATA; | ||
| 679 | unsigned IOCTL_SNDCTL_COPR_RESET = SNDCTL_COPR_RESET; | ||
| 680 | unsigned IOCTL_SNDCTL_COPR_RUN = SNDCTL_COPR_RUN; | ||
| 681 | unsigned IOCTL_SNDCTL_COPR_SENDMSG = SNDCTL_COPR_SENDMSG; | ||
| 682 | unsigned IOCTL_SNDCTL_COPR_WCODE = SNDCTL_COPR_WCODE; | ||
| 683 | unsigned IOCTL_SNDCTL_COPR_WDATA = SNDCTL_COPR_WDATA; | ||
| 684 | unsigned IOCTL_SOUND_PCM_READ_BITS = SOUND_PCM_READ_BITS; | ||
| 685 | unsigned IOCTL_SOUND_PCM_READ_CHANNELS = SOUND_PCM_READ_CHANNELS; | ||
| 686 | unsigned IOCTL_SOUND_PCM_READ_FILTER = SOUND_PCM_READ_FILTER; | ||
| 687 | unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE; | ||
| 688 | unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = SOUND_PCM_WRITE_CHANNELS; | ||
| 689 | unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER; | ||
| 690 | #endif // SOUND_VERSION | ||
| 691 | unsigned IOCTL_TCFLSH = TCFLSH; | ||
| 692 | unsigned IOCTL_TCGETA = TCGETA; | ||
| 693 | unsigned IOCTL_TCGETS = TCGETS; | ||
| 694 | unsigned IOCTL_TCSBRK = TCSBRK; | ||
| 695 | unsigned IOCTL_TCSBRKP = TCSBRKP; | ||
| 696 | unsigned IOCTL_TCSETA = TCSETA; | ||
| 697 | unsigned IOCTL_TCSETAF = TCSETAF; | ||
| 698 | unsigned IOCTL_TCSETAW = TCSETAW; | ||
| 699 | unsigned IOCTL_TCSETS = TCSETS; | ||
| 700 | unsigned IOCTL_TCSETSF = TCSETSF; | ||
| 701 | unsigned IOCTL_TCSETSW = TCSETSW; | ||
| 702 | unsigned IOCTL_TCXONC = TCXONC; | ||
| 703 | unsigned IOCTL_TIOCGLCKTRMIOS = TIOCGLCKTRMIOS; | ||
| 704 | unsigned IOCTL_TIOCGSOFTCAR = TIOCGSOFTCAR; | ||
| 705 | unsigned IOCTL_TIOCINQ = TIOCINQ; | ||
| 706 | unsigned IOCTL_TIOCLINUX = TIOCLINUX; | ||
| 707 | unsigned IOCTL_TIOCSERCONFIG = TIOCSERCONFIG; | ||
| 708 | unsigned IOCTL_TIOCSERGETLSR = TIOCSERGETLSR; | ||
| 709 | unsigned IOCTL_TIOCSERGWILD = TIOCSERGWILD; | ||
| 710 | unsigned IOCTL_TIOCSERSWILD = TIOCSERSWILD; | ||
| 711 | unsigned IOCTL_TIOCSLCKTRMIOS = TIOCSLCKTRMIOS; | ||
| 712 | unsigned IOCTL_TIOCSSOFTCAR = TIOCSSOFTCAR; | ||
| 713 | unsigned IOCTL_VT_DISALLOCATE = VT_DISALLOCATE; | ||
| 714 | unsigned IOCTL_VT_GETSTATE = VT_GETSTATE; | ||
| 715 | unsigned IOCTL_VT_RESIZE = VT_RESIZE; | ||
| 716 | unsigned IOCTL_VT_RESIZEX = VT_RESIZEX; | ||
| 717 | unsigned IOCTL_VT_SENDSIG = VT_SENDSIG; | ||
| 718 | unsigned IOCTL_MTIOCGET = MTIOCGET; | ||
| 719 | unsigned IOCTL_MTIOCTOP = MTIOCTOP; | ||
| 720 | unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; | ||
| 721 | unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; | ||
| 722 | unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; | ||
| 723 | unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; | ||
| 724 | unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; | ||
| 725 | unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; | ||
| 726 | unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; | ||
| 727 | unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; | ||
| 728 | unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; | ||
| 729 | unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; | ||
| 730 | unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; | ||
| 731 | unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE; | ||
| 732 | unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR; | ||
| 733 | unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO; | ||
| 734 | unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME; | ||
| 735 | unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE; | ||
| 736 | unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT; | ||
| 737 | unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT; | ||
| 738 | unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS; | ||
| 739 | unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS; | ||
| 740 | unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND; | ||
| 741 | unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC; | ||
| 742 | unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE; | ||
| 743 | unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET; | ||
| 744 | unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES; | ||
| 745 | unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC; | ||
| 746 | unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI; | ||
| 747 | unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD; | ||
| 748 | unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO; | ||
| 749 | unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL; | ||
| 750 | unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE; | ||
| 751 | unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME; | ||
| 752 | unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT; | ||
| 753 | unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE; | ||
| 754 | unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START; | ||
| 755 | unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP; | ||
| 756 | unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO; | ||
| 757 | unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE; | ||
| 758 | unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM; | ||
| 759 | unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS; | ||
| 760 | unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS; | ||
| 761 | unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD; | ||
| 762 | unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK; | ||
| 763 | unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE; | ||
| 764 | unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN; | ||
| 765 | unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX; | ||
| 766 | unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE; | ||
| 767 | unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1; | ||
| 768 | unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2; | ||
| 769 | unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3; | ||
| 770 | unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD; | ||
| 771 | unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC; | ||
| 772 | unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE; | ||
| 773 | unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN; | ||
| 774 | unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM; | ||
| 775 | unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV; | ||
| 776 | unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK; | ||
| 777 | unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC; | ||
| 778 | unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER; | ||
| 779 | unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS; | ||
| 780 | unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH; | ||
| 781 | unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE; | ||
| 782 | unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME; | ||
| 783 | unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM; | ||
| 784 | unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS; | ||
| 785 | unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD; | ||
| 786 | unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE; | ||
| 787 | unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN; | ||
| 788 | unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX; | ||
| 789 | unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE; | ||
| 790 | unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1; | ||
| 791 | unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2; | ||
| 792 | unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3; | ||
| 793 | unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD; | ||
| 794 | unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC; | ||
| 795 | unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE; | ||
| 796 | unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN; | ||
| 797 | unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM; | ||
| 798 | unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV; | ||
| 799 | unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC; | ||
| 800 | unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER; | ||
| 801 | unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH; | ||
| 802 | unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE; | ||
| 803 | unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME; | ||
| 804 | unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; | ||
| 805 | unsigned IOCTL_VT_GETMODE = VT_GETMODE; | ||
| 806 | unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; | ||
| 807 | unsigned IOCTL_VT_RELDISP = VT_RELDISP; | ||
| 808 | unsigned IOCTL_VT_SETMODE = VT_SETMODE; | ||
| 809 | unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; | ||
| 810 | #endif // SANITIZER_LINUX | ||
| 811 | |||
| 812 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 813 | unsigned IOCTL_CYGETDEFTHRESH = CYGETDEFTHRESH; | ||
| 814 | unsigned IOCTL_CYGETDEFTIMEOUT = CYGETDEFTIMEOUT; | ||
| 815 | unsigned IOCTL_CYGETMON = CYGETMON; | ||
| 816 | unsigned IOCTL_CYGETTHRESH = CYGETTHRESH; | ||
| 817 | unsigned IOCTL_CYGETTIMEOUT = CYGETTIMEOUT; | ||
| 818 | unsigned IOCTL_CYSETDEFTHRESH = CYSETDEFTHRESH; | ||
| 819 | unsigned IOCTL_CYSETDEFTIMEOUT = CYSETDEFTIMEOUT; | ||
| 820 | unsigned IOCTL_CYSETTHRESH = CYSETTHRESH; | ||
| 821 | unsigned IOCTL_CYSETTIMEOUT = CYSETTIMEOUT; | ||
| 822 | unsigned IOCTL_EQL_EMANCIPATE = EQL_EMANCIPATE; | ||
| 823 | unsigned IOCTL_EQL_ENSLAVE = EQL_ENSLAVE; | ||
| 824 | unsigned IOCTL_EQL_GETMASTRCFG = EQL_GETMASTRCFG; | ||
| 825 | unsigned IOCTL_EQL_GETSLAVECFG = EQL_GETSLAVECFG; | ||
| 826 | unsigned IOCTL_EQL_SETMASTRCFG = EQL_SETMASTRCFG; | ||
| 827 | unsigned IOCTL_EQL_SETSLAVECFG = EQL_SETSLAVECFG; | ||
| 828 | #if EV_VERSION > (0x010000) | ||
| 829 | unsigned IOCTL_EVIOCGKEYCODE_V2 = EVIOCGKEYCODE_V2; | ||
| 830 | unsigned IOCTL_EVIOCGPROP = EVIOCGPROP(0); | ||
| 831 | unsigned IOCTL_EVIOCSKEYCODE_V2 = EVIOCSKEYCODE_V2; | ||
| 832 | #else | ||
| 833 | unsigned IOCTL_EVIOCGKEYCODE_V2 = IOCTL_NOT_PRESENT; | ||
| 834 | unsigned IOCTL_EVIOCGPROP = IOCTL_NOT_PRESENT; | ||
| 835 | unsigned IOCTL_EVIOCSKEYCODE_V2 = IOCTL_NOT_PRESENT; | ||
| 836 | #endif | ||
| 837 | unsigned IOCTL_FS_IOC_GETFLAGS = FS_IOC_GETFLAGS; | ||
| 838 | unsigned IOCTL_FS_IOC_GETVERSION = FS_IOC_GETVERSION; | ||
| 839 | unsigned IOCTL_FS_IOC_SETFLAGS = FS_IOC_SETFLAGS; | ||
| 840 | unsigned IOCTL_FS_IOC_SETVERSION = FS_IOC_SETVERSION; | ||
| 841 | unsigned IOCTL_GIO_CMAP = GIO_CMAP; | ||
| 842 | unsigned IOCTL_GIO_FONT = GIO_FONT; | ||
| 843 | unsigned IOCTL_GIO_UNIMAP = GIO_UNIMAP; | ||
| 844 | unsigned IOCTL_GIO_UNISCRNMAP = GIO_UNISCRNMAP; | ||
| 845 | unsigned IOCTL_KDADDIO = KDADDIO; | ||
| 846 | unsigned IOCTL_KDDELIO = KDDELIO; | ||
| 847 | unsigned IOCTL_KDGETKEYCODE = KDGETKEYCODE; | ||
| 848 | unsigned IOCTL_KDGKBDIACR = KDGKBDIACR; | ||
| 849 | unsigned IOCTL_KDGKBENT = KDGKBENT; | ||
| 850 | unsigned IOCTL_KDGKBLED = KDGKBLED; | ||
| 851 | unsigned IOCTL_KDGKBMETA = KDGKBMETA; | ||
| 852 | unsigned IOCTL_KDGKBSENT = KDGKBSENT; | ||
| 853 | unsigned IOCTL_KDMAPDISP = KDMAPDISP; | ||
| 854 | unsigned IOCTL_KDSETKEYCODE = KDSETKEYCODE; | ||
| 855 | unsigned IOCTL_KDSIGACCEPT = KDSIGACCEPT; | ||
| 856 | unsigned IOCTL_KDSKBDIACR = KDSKBDIACR; | ||
| 857 | unsigned IOCTL_KDSKBENT = KDSKBENT; | ||
| 858 | unsigned IOCTL_KDSKBLED = KDSKBLED; | ||
| 859 | unsigned IOCTL_KDSKBMETA = KDSKBMETA; | ||
| 860 | unsigned IOCTL_KDSKBSENT = KDSKBSENT; | ||
| 861 | unsigned IOCTL_KDUNMAPDISP = KDUNMAPDISP; | ||
| 862 | unsigned IOCTL_LPABORT = LPABORT; | ||
| 863 | unsigned IOCTL_LPABORTOPEN = LPABORTOPEN; | ||
| 864 | unsigned IOCTL_LPCAREFUL = LPCAREFUL; | ||
| 865 | unsigned IOCTL_LPCHAR = LPCHAR; | ||
| 866 | unsigned IOCTL_LPGETIRQ = LPGETIRQ; | ||
| 867 | unsigned IOCTL_LPGETSTATUS = LPGETSTATUS; | ||
| 868 | unsigned IOCTL_LPRESET = LPRESET; | ||
| 869 | unsigned IOCTL_LPSETIRQ = LPSETIRQ; | ||
| 870 | unsigned IOCTL_LPTIME = LPTIME; | ||
| 871 | unsigned IOCTL_LPWAIT = LPWAIT; | ||
| 872 | unsigned IOCTL_MTIOCGETCONFIG = MTIOCGETCONFIG; | ||
| 873 | unsigned IOCTL_MTIOCSETCONFIG = MTIOCSETCONFIG; | ||
| 874 | unsigned IOCTL_PIO_CMAP = PIO_CMAP; | ||
| 875 | unsigned IOCTL_PIO_FONT = PIO_FONT; | ||
| 876 | unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP; | ||
| 877 | unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR; | ||
| 878 | unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP; | ||
| 879 | unsigned IOCTL_SCSI_IOCTL_GET_IDLUN = SCSI_IOCTL_GET_IDLUN; | ||
| 880 | unsigned IOCTL_SCSI_IOCTL_PROBE_HOST = SCSI_IOCTL_PROBE_HOST; | ||
| 881 | unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE = SCSI_IOCTL_TAGGED_DISABLE; | ||
| 882 | unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE = SCSI_IOCTL_TAGGED_ENABLE; | ||
| 883 | unsigned IOCTL_SIOCAIPXITFCRT = SIOCAIPXITFCRT; | ||
| 884 | unsigned IOCTL_SIOCAIPXPRISLT = SIOCAIPXPRISLT; | ||
| 885 | unsigned IOCTL_SIOCAX25ADDUID = SIOCAX25ADDUID; | ||
| 886 | unsigned IOCTL_SIOCAX25DELUID = SIOCAX25DELUID; | ||
| 887 | unsigned IOCTL_SIOCAX25GETPARMS = SIOCAX25GETPARMS; | ||
| 888 | unsigned IOCTL_SIOCAX25GETUID = SIOCAX25GETUID; | ||
| 889 | unsigned IOCTL_SIOCAX25NOUID = SIOCAX25NOUID; | ||
| 890 | unsigned IOCTL_SIOCAX25SETPARMS = SIOCAX25SETPARMS; | ||
| 891 | unsigned IOCTL_SIOCDEVPLIP = SIOCDEVPLIP; | ||
| 892 | unsigned IOCTL_SIOCIPXCFGDATA = SIOCIPXCFGDATA; | ||
| 893 | unsigned IOCTL_SIOCNRDECOBS = SIOCNRDECOBS; | ||
| 894 | unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS; | ||
| 895 | unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL; | ||
| 896 | unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS; | ||
| 897 | unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL; | ||
| 898 | unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI; | ||
| 899 | unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI; | ||
| 900 | unsigned IOCTL_TIOCSSERIAL = TIOCSSERIAL; | ||
| 901 | #endif // SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 902 | |||
| 903 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 904 | unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP; | ||
| 905 | unsigned IOCTL_KDDISABIO = KDDISABIO; | ||
| 906 | unsigned IOCTL_KDENABIO = KDENABIO; | ||
| 907 | unsigned IOCTL_KDGETLED = KDGETLED; | ||
| 908 | unsigned IOCTL_KDGETMODE = KDGETMODE; | ||
| 909 | unsigned IOCTL_KDGKBMODE = KDGKBMODE; | ||
| 910 | unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; | ||
| 911 | unsigned IOCTL_KDMKTONE = KDMKTONE; | ||
| 912 | unsigned IOCTL_KDSETLED = KDSETLED; | ||
| 913 | unsigned IOCTL_KDSETMODE = KDSETMODE; | ||
| 914 | unsigned IOCTL_KDSKBMODE = KDSKBMODE; | ||
| 915 | unsigned IOCTL_KIOCSOUND = KIOCSOUND; | ||
| 916 | unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP; | ||
| 917 | unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; | ||
| 918 | unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE; | ||
| 919 | #endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID | ||
| 920 | |||
| 921 | const int si_SEGV_MAPERR = SEGV_MAPERR; | ||
| 922 | const int si_SEGV_ACCERR = SEGV_ACCERR; | ||
| 923 | } // namespace __sanitizer | ||
| 924 | |||
| 925 | using namespace __sanitizer; | ||
| 926 | |||
| 927 | COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); | ||
| 928 | |||
| 929 | COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); | ||
| 930 | CHECK_TYPE_SIZE(pthread_key_t); | ||
| 931 | |||
| 932 | #if SANITIZER_LINUX | ||
| 933 | // FIXME: We define those on Linux and Mac, but only check on Linux. | ||
| 934 | COMPILER_CHECK(IOC_NRBITS == _IOC_NRBITS); | ||
| 935 | COMPILER_CHECK(IOC_TYPEBITS == _IOC_TYPEBITS); | ||
| 936 | COMPILER_CHECK(IOC_SIZEBITS == _IOC_SIZEBITS); | ||
| 937 | COMPILER_CHECK(IOC_DIRBITS == _IOC_DIRBITS); | ||
| 938 | COMPILER_CHECK(IOC_NRMASK == _IOC_NRMASK); | ||
| 939 | COMPILER_CHECK(IOC_TYPEMASK == _IOC_TYPEMASK); | ||
| 940 | COMPILER_CHECK(IOC_SIZEMASK == _IOC_SIZEMASK); | ||
| 941 | COMPILER_CHECK(IOC_DIRMASK == _IOC_DIRMASK); | ||
| 942 | COMPILER_CHECK(IOC_NRSHIFT == _IOC_NRSHIFT); | ||
| 943 | COMPILER_CHECK(IOC_TYPESHIFT == _IOC_TYPESHIFT); | ||
| 944 | COMPILER_CHECK(IOC_SIZESHIFT == _IOC_SIZESHIFT); | ||
| 945 | COMPILER_CHECK(IOC_DIRSHIFT == _IOC_DIRSHIFT); | ||
| 946 | COMPILER_CHECK(IOC_NONE == _IOC_NONE); | ||
| 947 | COMPILER_CHECK(IOC_WRITE == _IOC_WRITE); | ||
| 948 | COMPILER_CHECK(IOC_READ == _IOC_READ); | ||
| 949 | COMPILER_CHECK(EVIOC_ABS_MAX == ABS_MAX); | ||
| 950 | COMPILER_CHECK(EVIOC_EV_MAX == EV_MAX); | ||
| 951 | COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678)); | ||
| 952 | COMPILER_CHECK(IOC_DIR(0x12345678) == _IOC_DIR(0x12345678)); | ||
| 953 | COMPILER_CHECK(IOC_NR(0x12345678) == _IOC_NR(0x12345678)); | ||
| 954 | COMPILER_CHECK(IOC_TYPE(0x12345678) == _IOC_TYPE(0x12345678)); | ||
| 955 | #endif // SANITIZER_LINUX | ||
| 956 | |||
| 957 | #if SANITIZER_LINUX || SANITIZER_FREEBSD | ||
| 958 | // There are more undocumented fields in dl_phdr_info that we are not interested | ||
| 959 | // in. | ||
| 960 | COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); | ||
| 961 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); | ||
| 962 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); | ||
| 963 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); | ||
| 964 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); | ||
| 965 | #endif // SANITIZER_LINUX || SANITIZER_FREEBSD | ||
| 966 | |||
| 967 | #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID | ||
| 968 | CHECK_TYPE_SIZE(glob_t); | ||
| 969 | CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); | ||
| 970 | CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); | ||
| 971 | CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); | ||
| 972 | CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); | ||
| 973 | CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); | ||
| 974 | CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); | ||
| 975 | CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); | ||
| 976 | CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); | ||
| 977 | CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); | ||
| 978 | #endif | ||
| 979 | |||
| 980 | CHECK_TYPE_SIZE(addrinfo); | ||
| 981 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); | ||
| 982 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); | ||
| 983 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); | ||
| 984 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); | ||
| 985 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); | ||
| 986 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); | ||
| 987 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); | ||
| 988 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); | ||
| 989 | |||
| 990 | CHECK_TYPE_SIZE(hostent); | ||
| 991 | CHECK_SIZE_AND_OFFSET(hostent, h_name); | ||
| 992 | CHECK_SIZE_AND_OFFSET(hostent, h_aliases); | ||
| 993 | CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); | ||
| 994 | CHECK_SIZE_AND_OFFSET(hostent, h_length); | ||
| 995 | CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); | ||
| 996 | |||
| 997 | CHECK_TYPE_SIZE(iovec); | ||
| 998 | CHECK_SIZE_AND_OFFSET(iovec, iov_base); | ||
| 999 | CHECK_SIZE_AND_OFFSET(iovec, iov_len); | ||
| 1000 | |||
| 1001 | CHECK_TYPE_SIZE(msghdr); | ||
| 1002 | CHECK_SIZE_AND_OFFSET(msghdr, msg_name); | ||
| 1003 | CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); | ||
| 1004 | CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); | ||
| 1005 | CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); | ||
| 1006 | CHECK_SIZE_AND_OFFSET(msghdr, msg_control); | ||
| 1007 | CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); | ||
| 1008 | CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); | ||
| 1009 | |||
| 1010 | CHECK_TYPE_SIZE(cmsghdr); | ||
| 1011 | CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); | ||
| 1012 | CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); | ||
| 1013 | CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); | ||
| 1014 | |||
| 1015 | #if SANITIZER_LINUX && (__ANDROID_API__ >= 21 || __GLIBC_PREREQ (2, 14)) | ||
| 1016 | CHECK_TYPE_SIZE(mmsghdr); | ||
| 1017 | CHECK_SIZE_AND_OFFSET(mmsghdr, msg_hdr); | ||
| 1018 | CHECK_SIZE_AND_OFFSET(mmsghdr, msg_len); | ||
| 1019 | #endif | ||
| 1020 | |||
| 1021 | COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); | ||
| 1022 | CHECK_SIZE_AND_OFFSET(dirent, d_ino); | ||
| 1023 | #if SANITIZER_MAC | ||
| 1024 | CHECK_SIZE_AND_OFFSET(dirent, d_seekoff); | ||
| 1025 | #elif SANITIZER_FREEBSD | ||
| 1026 | // There is no 'd_off' field on FreeBSD. | ||
| 1027 | #else | ||
| 1028 | CHECK_SIZE_AND_OFFSET(dirent, d_off); | ||
| 1029 | #endif | ||
| 1030 | CHECK_SIZE_AND_OFFSET(dirent, d_reclen); | ||
| 1031 | |||
| 1032 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 1033 | COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64)); | ||
| 1034 | CHECK_SIZE_AND_OFFSET(dirent64, d_ino); | ||
| 1035 | CHECK_SIZE_AND_OFFSET(dirent64, d_off); | ||
| 1036 | CHECK_SIZE_AND_OFFSET(dirent64, d_reclen); | ||
| 1037 | #endif | ||
| 1038 | |||
| 1039 | CHECK_TYPE_SIZE(ifconf); | ||
| 1040 | CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); | ||
| 1041 | CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); | ||
| 1042 | |||
| 1043 | CHECK_TYPE_SIZE(pollfd); | ||
| 1044 | CHECK_SIZE_AND_OFFSET(pollfd, fd); | ||
| 1045 | CHECK_SIZE_AND_OFFSET(pollfd, events); | ||
| 1046 | CHECK_SIZE_AND_OFFSET(pollfd, revents); | ||
| 1047 | |||
| 1048 | CHECK_TYPE_SIZE(nfds_t); | ||
| 1049 | |||
| 1050 | CHECK_TYPE_SIZE(sigset_t); | ||
| 1051 | |||
| 1052 | COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); | ||
| 1053 | // Can't write checks for sa_handler and sa_sigaction due to them being | ||
| 1054 | // preprocessor macros. | ||
| 1055 | CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); | ||
| 1056 | #if !defined(__s390x__) || __GLIBC_PREREQ (2, 20) | ||
| 1057 | // On s390x glibc 2.19 and earlier sa_flags was unsigned long, and sa_resv | ||
| 1058 | // didn't exist. | ||
| 1059 | CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags); | ||
| 1060 | #endif | ||
| 1061 | #if SANITIZER_LINUX && (!SANITIZER_ANDROID || !SANITIZER_MIPS32) | ||
| 1062 | CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer); | ||
| 1063 | #endif | ||
| 1064 | |||
| 1065 | #if SANITIZER_LINUX | ||
| 1066 | CHECK_TYPE_SIZE(__sysctl_args); | ||
| 1067 | CHECK_SIZE_AND_OFFSET(__sysctl_args, name); | ||
| 1068 | CHECK_SIZE_AND_OFFSET(__sysctl_args, nlen); | ||
| 1069 | CHECK_SIZE_AND_OFFSET(__sysctl_args, oldval); | ||
| 1070 | CHECK_SIZE_AND_OFFSET(__sysctl_args, oldlenp); | ||
| 1071 | CHECK_SIZE_AND_OFFSET(__sysctl_args, newval); | ||
| 1072 | CHECK_SIZE_AND_OFFSET(__sysctl_args, newlen); | ||
| 1073 | |||
| 1074 | CHECK_TYPE_SIZE(__kernel_uid_t); | ||
| 1075 | CHECK_TYPE_SIZE(__kernel_gid_t); | ||
| 1076 | |||
| 1077 | #if SANITIZER_USES_UID16_SYSCALLS | ||
| 1078 | CHECK_TYPE_SIZE(__kernel_old_uid_t); | ||
| 1079 | CHECK_TYPE_SIZE(__kernel_old_gid_t); | ||
| 1080 | #endif | ||
| 1081 | |||
| 1082 | CHECK_TYPE_SIZE(__kernel_off_t); | ||
| 1083 | CHECK_TYPE_SIZE(__kernel_loff_t); | ||
| 1084 | CHECK_TYPE_SIZE(__kernel_fd_set); | ||
| 1085 | #endif | ||
| 1086 | |||
| 1087 | #if !SANITIZER_ANDROID | ||
| 1088 | CHECK_TYPE_SIZE(wordexp_t); | ||
| 1089 | CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); | ||
| 1090 | CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); | ||
| 1091 | CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); | ||
| 1092 | #endif | ||
| 1093 | |||
| 1094 | CHECK_TYPE_SIZE(tm); | ||
| 1095 | CHECK_SIZE_AND_OFFSET(tm, tm_sec); | ||
| 1096 | CHECK_SIZE_AND_OFFSET(tm, tm_min); | ||
| 1097 | CHECK_SIZE_AND_OFFSET(tm, tm_hour); | ||
| 1098 | CHECK_SIZE_AND_OFFSET(tm, tm_mday); | ||
| 1099 | CHECK_SIZE_AND_OFFSET(tm, tm_mon); | ||
| 1100 | CHECK_SIZE_AND_OFFSET(tm, tm_year); | ||
| 1101 | CHECK_SIZE_AND_OFFSET(tm, tm_wday); | ||
| 1102 | CHECK_SIZE_AND_OFFSET(tm, tm_yday); | ||
| 1103 | CHECK_SIZE_AND_OFFSET(tm, tm_isdst); | ||
| 1104 | CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); | ||
| 1105 | CHECK_SIZE_AND_OFFSET(tm, tm_zone); | ||
| 1106 | |||
| 1107 | #if SANITIZER_LINUX | ||
| 1108 | CHECK_TYPE_SIZE(mntent); | ||
| 1109 | CHECK_SIZE_AND_OFFSET(mntent, mnt_fsname); | ||
| 1110 | CHECK_SIZE_AND_OFFSET(mntent, mnt_dir); | ||
| 1111 | CHECK_SIZE_AND_OFFSET(mntent, mnt_type); | ||
| 1112 | CHECK_SIZE_AND_OFFSET(mntent, mnt_opts); | ||
| 1113 | CHECK_SIZE_AND_OFFSET(mntent, mnt_freq); | ||
| 1114 | CHECK_SIZE_AND_OFFSET(mntent, mnt_passno); | ||
| 1115 | #endif | ||
| 1116 | |||
| 1117 | CHECK_TYPE_SIZE(ether_addr); | ||
| 1118 | |||
| 1119 | #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID | ||
| 1120 | CHECK_TYPE_SIZE(ipc_perm); | ||
| 1121 | # if SANITIZER_FREEBSD | ||
| 1122 | CHECK_SIZE_AND_OFFSET(ipc_perm, key); | ||
| 1123 | CHECK_SIZE_AND_OFFSET(ipc_perm, seq); | ||
| 1124 | # else | ||
| 1125 | CHECK_SIZE_AND_OFFSET(ipc_perm, __key); | ||
| 1126 | CHECK_SIZE_AND_OFFSET(ipc_perm, __seq); | ||
| 1127 | # endif | ||
| 1128 | CHECK_SIZE_AND_OFFSET(ipc_perm, uid); | ||
| 1129 | CHECK_SIZE_AND_OFFSET(ipc_perm, gid); | ||
| 1130 | CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); | ||
| 1131 | CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); | ||
| 1132 | #if !SANITIZER_LINUX || __GLIBC_PREREQ (2, 31) | ||
| 1133 | /* glibc 2.30 and earlier provided 16-bit mode field instead of 32-bit | ||
| 1134 | on many architectures. */ | ||
| 1135 | CHECK_SIZE_AND_OFFSET(ipc_perm, mode); | ||
| 1136 | #endif | ||
| 1137 | |||
| 1138 | CHECK_TYPE_SIZE(shmid_ds); | ||
| 1139 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); | ||
| 1140 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); | ||
| 1141 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); | ||
| 1142 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); | ||
| 1143 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); | ||
| 1144 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); | ||
| 1145 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); | ||
| 1146 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); | ||
| 1147 | #endif | ||
| 1148 | |||
| 1149 | CHECK_TYPE_SIZE(clock_t); | ||
| 1150 | |||
| 1151 | #if SANITIZER_LINUX | ||
| 1152 | CHECK_TYPE_SIZE(clockid_t); | ||
| 1153 | #endif | ||
| 1154 | |||
| 1155 | #if !SANITIZER_ANDROID | ||
| 1156 | CHECK_TYPE_SIZE(ifaddrs); | ||
| 1157 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); | ||
| 1158 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); | ||
| 1159 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); | ||
| 1160 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); | ||
| 1161 | #if SANITIZER_LINUX || SANITIZER_FREEBSD | ||
| 1162 | // Compare against the union, because we can't reach into the union in a | ||
| 1163 | // compliant way. | ||
| 1164 | #ifdef ifa_dstaddr | ||
| 1165 | #undef ifa_dstaddr | ||
| 1166 | #endif | ||
| 1167 | # if SANITIZER_FREEBSD | ||
| 1168 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); | ||
| 1169 | # else | ||
| 1170 | COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)nullptr)->ifa_dstaddr) == | ||
| 1171 | sizeof(((ifaddrs *)nullptr)->ifa_ifu)); | ||
| 1172 | COMPILER_CHECK(offsetof(__sanitizer_ifaddrs, ifa_dstaddr) == | ||
| 1173 | offsetof(ifaddrs, ifa_ifu)); | ||
| 1174 | # endif // SANITIZER_FREEBSD | ||
| 1175 | #else | ||
| 1176 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); | ||
| 1177 | #endif // SANITIZER_LINUX | ||
| 1178 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); | ||
| 1179 | #endif | ||
| 1180 | |||
| 1181 | #if SANITIZER_LINUX | ||
| 1182 | COMPILER_CHECK(sizeof(__sanitizer_struct_mallinfo) == sizeof(struct mallinfo)); | ||
| 1183 | #endif | ||
| 1184 | |||
| 1185 | #if !SANITIZER_ANDROID | ||
| 1186 | CHECK_TYPE_SIZE(timeb); | ||
| 1187 | CHECK_SIZE_AND_OFFSET(timeb, time); | ||
| 1188 | CHECK_SIZE_AND_OFFSET(timeb, millitm); | ||
| 1189 | CHECK_SIZE_AND_OFFSET(timeb, timezone); | ||
| 1190 | CHECK_SIZE_AND_OFFSET(timeb, dstflag); | ||
| 1191 | #endif | ||
| 1192 | |||
| 1193 | CHECK_TYPE_SIZE(passwd); | ||
| 1194 | CHECK_SIZE_AND_OFFSET(passwd, pw_name); | ||
| 1195 | CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); | ||
| 1196 | CHECK_SIZE_AND_OFFSET(passwd, pw_uid); | ||
| 1197 | CHECK_SIZE_AND_OFFSET(passwd, pw_gid); | ||
| 1198 | CHECK_SIZE_AND_OFFSET(passwd, pw_dir); | ||
| 1199 | CHECK_SIZE_AND_OFFSET(passwd, pw_shell); | ||
| 1200 | |||
| 1201 | #if !SANITIZER_ANDROID | ||
| 1202 | CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); | ||
| 1203 | #endif | ||
| 1204 | |||
| 1205 | #if SANITIZER_MAC | ||
| 1206 | CHECK_SIZE_AND_OFFSET(passwd, pw_change); | ||
| 1207 | CHECK_SIZE_AND_OFFSET(passwd, pw_expire); | ||
| 1208 | CHECK_SIZE_AND_OFFSET(passwd, pw_class); | ||
| 1209 | #endif | ||
| 1210 | |||
| 1211 | |||
| 1212 | CHECK_TYPE_SIZE(group); | ||
| 1213 | CHECK_SIZE_AND_OFFSET(group, gr_name); | ||
| 1214 | CHECK_SIZE_AND_OFFSET(group, gr_passwd); | ||
| 1215 | CHECK_SIZE_AND_OFFSET(group, gr_gid); | ||
| 1216 | CHECK_SIZE_AND_OFFSET(group, gr_mem); | ||
| 1217 | |||
| 1218 | #if HAVE_RPC_XDR_H | ||
| 1219 | CHECK_TYPE_SIZE(XDR); | ||
| 1220 | CHECK_SIZE_AND_OFFSET(XDR, x_op); | ||
| 1221 | CHECK_SIZE_AND_OFFSET(XDR, x_ops); | ||
| 1222 | CHECK_SIZE_AND_OFFSET(XDR, x_public); | ||
| 1223 | CHECK_SIZE_AND_OFFSET(XDR, x_private); | ||
| 1224 | CHECK_SIZE_AND_OFFSET(XDR, x_base); | ||
| 1225 | CHECK_SIZE_AND_OFFSET(XDR, x_handy); | ||
| 1226 | COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE); | ||
| 1227 | COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); | ||
| 1228 | COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); | ||
| 1229 | #endif | ||
| 1230 | |||
| 1231 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 1232 | COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE)); | ||
| 1233 | CHECK_SIZE_AND_OFFSET(FILE, _flags); | ||
| 1234 | CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr); | ||
| 1235 | CHECK_SIZE_AND_OFFSET(FILE, _IO_read_end); | ||
| 1236 | CHECK_SIZE_AND_OFFSET(FILE, _IO_read_base); | ||
| 1237 | CHECK_SIZE_AND_OFFSET(FILE, _IO_write_ptr); | ||
| 1238 | CHECK_SIZE_AND_OFFSET(FILE, _IO_write_end); | ||
| 1239 | CHECK_SIZE_AND_OFFSET(FILE, _IO_write_base); | ||
| 1240 | CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_base); | ||
| 1241 | CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_end); | ||
| 1242 | CHECK_SIZE_AND_OFFSET(FILE, _IO_save_base); | ||
| 1243 | CHECK_SIZE_AND_OFFSET(FILE, _IO_backup_base); | ||
| 1244 | CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end); | ||
| 1245 | CHECK_SIZE_AND_OFFSET(FILE, _markers); | ||
| 1246 | CHECK_SIZE_AND_OFFSET(FILE, _chain); | ||
| 1247 | CHECK_SIZE_AND_OFFSET(FILE, _fileno); | ||
| 1248 | #endif | ||
| 1249 | |||
| 1250 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 1251 | COMPILER_CHECK(sizeof(__sanitizer__obstack_chunk) <= sizeof(_obstack_chunk)); | ||
| 1252 | CHECK_SIZE_AND_OFFSET(_obstack_chunk, limit); | ||
| 1253 | CHECK_SIZE_AND_OFFSET(_obstack_chunk, prev); | ||
| 1254 | CHECK_TYPE_SIZE(obstack); | ||
| 1255 | CHECK_SIZE_AND_OFFSET(obstack, chunk_size); | ||
| 1256 | CHECK_SIZE_AND_OFFSET(obstack, chunk); | ||
| 1257 | CHECK_SIZE_AND_OFFSET(obstack, object_base); | ||
| 1258 | CHECK_SIZE_AND_OFFSET(obstack, next_free); | ||
| 1259 | |||
| 1260 | CHECK_TYPE_SIZE(cookie_io_functions_t); | ||
| 1261 | CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, read); | ||
| 1262 | CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, write); | ||
| 1263 | CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, seek); | ||
| 1264 | CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, close); | ||
| 1265 | #endif | ||
| 1266 | |||
| 1267 | #if SANITIZER_LINUX || SANITIZER_FREEBSD | ||
| 1268 | CHECK_TYPE_SIZE(sem_t); | ||
| 1269 | #endif | ||
| 1270 | |||
| 1271 | #if SANITIZER_LINUX && defined(__arm__) | ||
| 1272 | COMPILER_CHECK(ARM_VFPREGS_SIZE == ARM_VFPREGS_SIZE_ASAN); | ||
| 1273 | #endif | ||
| 1274 | |||
| 1275 | #endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC | ||
lib/tsan/sanitizer_common/sanitizer_platform_limits_posix.h created+1453| ... | @@ -0,0 +1,1453 @@ | ||
| 1 | //===-- sanitizer_platform_limits_posix.h ---------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer common code. | ||
| 10 | // | ||
| 11 | // Sizes and layouts of platform-specific POSIX data structures. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H | ||
| 15 | #define SANITIZER_PLATFORM_LIMITS_POSIX_H | ||
| 16 | |||
| 17 | #if SANITIZER_LINUX || SANITIZER_MAC | ||
| 18 | |||
| 19 | #include "sanitizer_internal_defs.h" | ||
| 20 | #include "sanitizer_platform.h" | ||
| 21 | |||
| 22 | #if defined(__sparc__) | ||
| 23 | // FIXME: This can't be included from tsan which does not support sparc yet. | ||
| 24 | #include "sanitizer_glibc_version.h" | ||
| 25 | #endif | ||
| 26 | |||
| 27 | # define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) ((link_map*)(handle)) | ||
| 28 | |||
| 29 | namespace __sanitizer { | ||
| 30 | extern unsigned struct_utsname_sz; | ||
| 31 | extern unsigned struct_stat_sz; | ||
| 32 | #if !SANITIZER_IOS | ||
| 33 | extern unsigned struct_stat64_sz; | ||
| 34 | #endif | ||
| 35 | extern unsigned struct_rusage_sz; | ||
| 36 | extern unsigned siginfo_t_sz; | ||
| 37 | extern unsigned struct_itimerval_sz; | ||
| 38 | extern unsigned pthread_t_sz; | ||
| 39 | extern unsigned pthread_mutex_t_sz; | ||
| 40 | extern unsigned pthread_cond_t_sz; | ||
| 41 | extern unsigned pid_t_sz; | ||
| 42 | extern unsigned timeval_sz; | ||
| 43 | extern unsigned uid_t_sz; | ||
| 44 | extern unsigned gid_t_sz; | ||
| 45 | extern unsigned mbstate_t_sz; | ||
| 46 | extern unsigned struct_timezone_sz; | ||
| 47 | extern unsigned struct_tms_sz; | ||
| 48 | extern unsigned struct_itimerspec_sz; | ||
| 49 | extern unsigned struct_sigevent_sz; | ||
| 50 | extern unsigned struct_stack_t_sz; | ||
| 51 | extern unsigned struct_sched_param_sz; | ||
| 52 | extern unsigned struct_statfs64_sz; | ||
| 53 | extern unsigned struct_regex_sz; | ||
| 54 | extern unsigned struct_regmatch_sz; | ||
| 55 | |||
| 56 | #if !SANITIZER_ANDROID | ||
| 57 | extern unsigned struct_fstab_sz; | ||
| 58 | extern unsigned struct_statfs_sz; | ||
| 59 | extern unsigned struct_sockaddr_sz; | ||
| 60 | extern unsigned ucontext_t_sz; | ||
| 61 | #endif // !SANITIZER_ANDROID | ||
| 62 | |||
| 63 | #if SANITIZER_LINUX | ||
| 64 | |||
| 65 | #if defined(__x86_64__) | ||
| 66 | const unsigned struct_kernel_stat_sz = 144; | ||
| 67 | const unsigned struct_kernel_stat64_sz = 0; | ||
| 68 | #elif defined(__i386__) | ||
| 69 | const unsigned struct_kernel_stat_sz = 64; | ||
| 70 | const unsigned struct_kernel_stat64_sz = 96; | ||
| 71 | #elif defined(__arm__) | ||
| 72 | const unsigned struct_kernel_stat_sz = 64; | ||
| 73 | const unsigned struct_kernel_stat64_sz = 104; | ||
| 74 | #elif defined(__aarch64__) | ||
| 75 | const unsigned struct_kernel_stat_sz = 128; | ||
| 76 | const unsigned struct_kernel_stat64_sz = 104; | ||
| 77 | #elif defined(__powerpc__) && !defined(__powerpc64__) | ||
| 78 | const unsigned struct_kernel_stat_sz = 72; | ||
| 79 | const unsigned struct_kernel_stat64_sz = 104; | ||
| 80 | #elif defined(__powerpc64__) | ||
| 81 | const unsigned struct_kernel_stat_sz = 144; | ||
| 82 | const unsigned struct_kernel_stat64_sz = 104; | ||
| 83 | #elif defined(__mips__) | ||
| 84 | const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID | ||
| 85 | ? FIRST_32_SECOND_64(104, 128) | ||
| 86 | : FIRST_32_SECOND_64(160, 216); | ||
| 87 | const unsigned struct_kernel_stat64_sz = 104; | ||
| 88 | #elif defined(__s390__) && !defined(__s390x__) | ||
| 89 | const unsigned struct_kernel_stat_sz = 64; | ||
| 90 | const unsigned struct_kernel_stat64_sz = 104; | ||
| 91 | #elif defined(__s390x__) | ||
| 92 | const unsigned struct_kernel_stat_sz = 144; | ||
| 93 | const unsigned struct_kernel_stat64_sz = 0; | ||
| 94 | #elif defined(__sparc__) && defined(__arch64__) | ||
| 95 | const unsigned struct___old_kernel_stat_sz = 0; | ||
| 96 | const unsigned struct_kernel_stat_sz = 104; | ||
| 97 | const unsigned struct_kernel_stat64_sz = 144; | ||
| 98 | #elif defined(__sparc__) && !defined(__arch64__) | ||
| 99 | const unsigned struct___old_kernel_stat_sz = 0; | ||
| 100 | const unsigned struct_kernel_stat_sz = 64; | ||
| 101 | const unsigned struct_kernel_stat64_sz = 104; | ||
| 102 | #elif defined(__riscv) && __riscv_xlen == 64 | ||
| 103 | const unsigned struct_kernel_stat_sz = 128; | ||
| 104 | const unsigned struct_kernel_stat64_sz = 104; | ||
| 105 | #endif | ||
| 106 | struct __sanitizer_perf_event_attr { | ||
| 107 | unsigned type; | ||
| 108 | unsigned size; | ||
| 109 | // More fields that vary with the kernel version. | ||
| 110 | }; | ||
| 111 | |||
| 112 | extern unsigned struct_epoll_event_sz; | ||
| 113 | extern unsigned struct_sysinfo_sz; | ||
| 114 | extern unsigned __user_cap_header_struct_sz; | ||
| 115 | extern unsigned __user_cap_data_struct_sz; | ||
| 116 | extern unsigned struct_new_utsname_sz; | ||
| 117 | extern unsigned struct_old_utsname_sz; | ||
| 118 | extern unsigned struct_oldold_utsname_sz; | ||
| 119 | |||
| 120 | const unsigned struct_kexec_segment_sz = 4 * sizeof(unsigned long); | ||
| 121 | #endif // SANITIZER_LINUX | ||
| 122 | |||
| 123 | #if SANITIZER_LINUX | ||
| 124 | |||
| 125 | #if defined(__powerpc64__) || defined(__s390__) | ||
| 126 | const unsigned struct___old_kernel_stat_sz = 0; | ||
| 127 | #elif !defined(__sparc__) | ||
| 128 | const unsigned struct___old_kernel_stat_sz = 32; | ||
| 129 | #endif | ||
| 130 | |||
| 131 | extern unsigned struct_rlimit_sz; | ||
| 132 | extern unsigned struct_utimbuf_sz; | ||
| 133 | extern unsigned struct_timespec_sz; | ||
| 134 | |||
| 135 | struct __sanitizer_iocb { | ||
| 136 | u64 aio_data; | ||
| 137 | u32 aio_key_or_aio_reserved1; // Simply crazy. | ||
| 138 | u32 aio_reserved1_or_aio_key; // Luckily, we don't need these. | ||
| 139 | u16 aio_lio_opcode; | ||
| 140 | s16 aio_reqprio; | ||
| 141 | u32 aio_fildes; | ||
| 142 | u64 aio_buf; | ||
| 143 | u64 aio_nbytes; | ||
| 144 | s64 aio_offset; | ||
| 145 | u64 aio_reserved2; | ||
| 146 | u64 aio_reserved3; | ||
| 147 | }; | ||
| 148 | |||
| 149 | struct __sanitizer_io_event { | ||
| 150 | u64 data; | ||
| 151 | u64 obj; | ||
| 152 | u64 res; | ||
| 153 | u64 res2; | ||
| 154 | }; | ||
| 155 | |||
| 156 | const unsigned iocb_cmd_pread = 0; | ||
| 157 | const unsigned iocb_cmd_pwrite = 1; | ||
| 158 | const unsigned iocb_cmd_preadv = 7; | ||
| 159 | const unsigned iocb_cmd_pwritev = 8; | ||
| 160 | |||
| 161 | struct __sanitizer___sysctl_args { | ||
| 162 | int *name; | ||
| 163 | int nlen; | ||
| 164 | void *oldval; | ||
| 165 | uptr *oldlenp; | ||
| 166 | void *newval; | ||
| 167 | uptr newlen; | ||
| 168 | unsigned long ___unused[4]; | ||
| 169 | }; | ||
| 170 | |||
| 171 | const unsigned old_sigset_t_sz = sizeof(unsigned long); | ||
| 172 | |||
| 173 | struct __sanitizer_sem_t { | ||
| 174 | #if SANITIZER_ANDROID && defined(_LP64) | ||
| 175 | int data[4]; | ||
| 176 | #elif SANITIZER_ANDROID && !defined(_LP64) | ||
| 177 | int data; | ||
| 178 | #elif SANITIZER_LINUX | ||
| 179 | uptr data[4]; | ||
| 180 | #endif | ||
| 181 | }; | ||
| 182 | #endif // SANITIZER_LINUX | ||
| 183 | |||
| 184 | #if SANITIZER_ANDROID | ||
| 185 | struct __sanitizer_struct_mallinfo { | ||
| 186 | uptr v[10]; | ||
| 187 | }; | ||
| 188 | #endif | ||
| 189 | |||
| 190 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 191 | struct __sanitizer_struct_mallinfo { | ||
| 192 | int v[10]; | ||
| 193 | }; | ||
| 194 | |||
| 195 | extern unsigned struct_ustat_sz; | ||
| 196 | extern unsigned struct_rlimit64_sz; | ||
| 197 | extern unsigned struct_statvfs64_sz; | ||
| 198 | |||
| 199 | struct __sanitizer_ipc_perm { | ||
| 200 | int __key; | ||
| 201 | int uid; | ||
| 202 | int gid; | ||
| 203 | int cuid; | ||
| 204 | int cgid; | ||
| 205 | #ifdef __powerpc__ | ||
| 206 | unsigned mode; | ||
| 207 | unsigned __seq; | ||
| 208 | u64 __unused1; | ||
| 209 | u64 __unused2; | ||
| 210 | #elif defined(__sparc__) | ||
| 211 | unsigned mode; | ||
| 212 | unsigned short __pad2; | ||
| 213 | unsigned short __seq; | ||
| 214 | unsigned long long __unused1; | ||
| 215 | unsigned long long __unused2; | ||
| 216 | #else | ||
| 217 | unsigned int mode; | ||
| 218 | unsigned short __seq; | ||
| 219 | unsigned short __pad2; | ||
| 220 | #if defined(__x86_64__) && !defined(_LP64) | ||
| 221 | u64 __unused1; | ||
| 222 | u64 __unused2; | ||
| 223 | #else | ||
| 224 | unsigned long __unused1; | ||
| 225 | unsigned long __unused2; | ||
| 226 | #endif | ||
| 227 | #endif | ||
| 228 | }; | ||
| 229 | |||
| 230 | struct __sanitizer_shmid_ds { | ||
| 231 | __sanitizer_ipc_perm shm_perm; | ||
| 232 | #if defined(__sparc__) | ||
| 233 | #if !defined(__arch64__) | ||
| 234 | u32 __pad1; | ||
| 235 | #endif | ||
| 236 | long shm_atime; | ||
| 237 | #if !defined(__arch64__) | ||
| 238 | u32 __pad2; | ||
| 239 | #endif | ||
| 240 | long shm_dtime; | ||
| 241 | #if !defined(__arch64__) | ||
| 242 | u32 __pad3; | ||
| 243 | #endif | ||
| 244 | long shm_ctime; | ||
| 245 | uptr shm_segsz; | ||
| 246 | int shm_cpid; | ||
| 247 | int shm_lpid; | ||
| 248 | unsigned long shm_nattch; | ||
| 249 | unsigned long __glibc_reserved1; | ||
| 250 | unsigned long __glibc_reserved2; | ||
| 251 | #else | ||
| 252 | #ifndef __powerpc__ | ||
| 253 | uptr shm_segsz; | ||
| 254 | #elif !defined(__powerpc64__) | ||
| 255 | uptr __unused0; | ||
| 256 | #endif | ||
| 257 | #if defined(__x86_64__) && !defined(_LP64) | ||
| 258 | u64 shm_atime; | ||
| 259 | u64 shm_dtime; | ||
| 260 | u64 shm_ctime; | ||
| 261 | #else | ||
| 262 | uptr shm_atime; | ||
| 263 | #if !defined(_LP64) && !defined(__mips__) | ||
| 264 | uptr __unused1; | ||
| 265 | #endif | ||
| 266 | uptr shm_dtime; | ||
| 267 | #if !defined(_LP64) && !defined(__mips__) | ||
| 268 | uptr __unused2; | ||
| 269 | #endif | ||
| 270 | uptr shm_ctime; | ||
| 271 | #if !defined(_LP64) && !defined(__mips__) | ||
| 272 | uptr __unused3; | ||
| 273 | #endif | ||
| 274 | #endif | ||
| 275 | #ifdef __powerpc__ | ||
| 276 | uptr shm_segsz; | ||
| 277 | #endif | ||
| 278 | int shm_cpid; | ||
| 279 | int shm_lpid; | ||
| 280 | #if defined(__x86_64__) && !defined(_LP64) | ||
| 281 | u64 shm_nattch; | ||
| 282 | u64 __unused4; | ||
| 283 | u64 __unused5; | ||
| 284 | #else | ||
| 285 | uptr shm_nattch; | ||
| 286 | uptr __unused4; | ||
| 287 | uptr __unused5; | ||
| 288 | #endif | ||
| 289 | #endif | ||
| 290 | }; | ||
| 291 | #endif | ||
| 292 | |||
| 293 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 294 | extern unsigned struct_msqid_ds_sz; | ||
| 295 | extern unsigned struct_mq_attr_sz; | ||
| 296 | extern unsigned struct_timex_sz; | ||
| 297 | extern unsigned struct_statvfs_sz; | ||
| 298 | extern unsigned struct_crypt_data_sz; | ||
| 299 | #endif // SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 300 | |||
| 301 | struct __sanitizer_iovec { | ||
| 302 | void *iov_base; | ||
| 303 | uptr iov_len; | ||
| 304 | }; | ||
| 305 | |||
| 306 | #if !SANITIZER_ANDROID | ||
| 307 | struct __sanitizer_ifaddrs { | ||
| 308 | struct __sanitizer_ifaddrs *ifa_next; | ||
| 309 | char *ifa_name; | ||
| 310 | unsigned int ifa_flags; | ||
| 311 | void *ifa_addr; // (struct sockaddr *) | ||
| 312 | void *ifa_netmask; // (struct sockaddr *) | ||
| 313 | // This is a union on Linux. | ||
| 314 | # ifdef ifa_dstaddr | ||
| 315 | # undef ifa_dstaddr | ||
| 316 | # endif | ||
| 317 | void *ifa_dstaddr; // (struct sockaddr *) | ||
| 318 | void *ifa_data; | ||
| 319 | }; | ||
| 320 | #endif // !SANITIZER_ANDROID | ||
| 321 | |||
| 322 | #if SANITIZER_MAC | ||
| 323 | typedef unsigned long __sanitizer_pthread_key_t; | ||
| 324 | #else | ||
| 325 | typedef unsigned __sanitizer_pthread_key_t; | ||
| 326 | #endif | ||
| 327 | |||
| 328 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 329 | |||
| 330 | struct __sanitizer_XDR { | ||
| 331 | int x_op; | ||
| 332 | void *x_ops; | ||
| 333 | uptr x_public; | ||
| 334 | uptr x_private; | ||
| 335 | uptr x_base; | ||
| 336 | unsigned x_handy; | ||
| 337 | }; | ||
| 338 | |||
| 339 | const int __sanitizer_XDR_ENCODE = 0; | ||
| 340 | const int __sanitizer_XDR_DECODE = 1; | ||
| 341 | const int __sanitizer_XDR_FREE = 2; | ||
| 342 | #endif | ||
| 343 | |||
| 344 | struct __sanitizer_passwd { | ||
| 345 | char *pw_name; | ||
| 346 | char *pw_passwd; | ||
| 347 | int pw_uid; | ||
| 348 | int pw_gid; | ||
| 349 | #if SANITIZER_MAC | ||
| 350 | long pw_change; | ||
| 351 | char *pw_class; | ||
| 352 | #endif | ||
| 353 | #if !(SANITIZER_ANDROID && (SANITIZER_WORDSIZE == 32)) | ||
| 354 | char *pw_gecos; | ||
| 355 | #endif | ||
| 356 | char *pw_dir; | ||
| 357 | char *pw_shell; | ||
| 358 | #if SANITIZER_MAC | ||
| 359 | long pw_expire; | ||
| 360 | #endif | ||
| 361 | }; | ||
| 362 | |||
| 363 | struct __sanitizer_group { | ||
| 364 | char *gr_name; | ||
| 365 | char *gr_passwd; | ||
| 366 | int gr_gid; | ||
| 367 | char **gr_mem; | ||
| 368 | }; | ||
| 369 | |||
| 370 | #if defined(__x86_64__) && !defined(_LP64) | ||
| 371 | typedef long long __sanitizer_time_t; | ||
| 372 | #else | ||
| 373 | typedef long __sanitizer_time_t; | ||
| 374 | #endif | ||
| 375 | |||
| 376 | typedef long __sanitizer_suseconds_t; | ||
| 377 | |||
| 378 | struct __sanitizer_timeval { | ||
| 379 | __sanitizer_time_t tv_sec; | ||
| 380 | __sanitizer_suseconds_t tv_usec; | ||
| 381 | }; | ||
| 382 | |||
| 383 | struct __sanitizer_itimerval { | ||
| 384 | struct __sanitizer_timeval it_interval; | ||
| 385 | struct __sanitizer_timeval it_value; | ||
| 386 | }; | ||
| 387 | |||
| 388 | struct __sanitizer_timeb { | ||
| 389 | __sanitizer_time_t time; | ||
| 390 | unsigned short millitm; | ||
| 391 | short timezone; | ||
| 392 | short dstflag; | ||
| 393 | }; | ||
| 394 | |||
| 395 | struct __sanitizer_ether_addr { | ||
| 396 | u8 octet[6]; | ||
| 397 | }; | ||
| 398 | |||
| 399 | struct __sanitizer_tm { | ||
| 400 | int tm_sec; | ||
| 401 | int tm_min; | ||
| 402 | int tm_hour; | ||
| 403 | int tm_mday; | ||
| 404 | int tm_mon; | ||
| 405 | int tm_year; | ||
| 406 | int tm_wday; | ||
| 407 | int tm_yday; | ||
| 408 | int tm_isdst; | ||
| 409 | long int tm_gmtoff; | ||
| 410 | const char *tm_zone; | ||
| 411 | }; | ||
| 412 | |||
| 413 | #if SANITIZER_LINUX | ||
| 414 | struct __sanitizer_mntent { | ||
| 415 | char *mnt_fsname; | ||
| 416 | char *mnt_dir; | ||
| 417 | char *mnt_type; | ||
| 418 | char *mnt_opts; | ||
| 419 | int mnt_freq; | ||
| 420 | int mnt_passno; | ||
| 421 | }; | ||
| 422 | |||
| 423 | struct __sanitizer_file_handle { | ||
| 424 | unsigned int handle_bytes; | ||
| 425 | int handle_type; | ||
| 426 | unsigned char f_handle[1]; // variable sized | ||
| 427 | }; | ||
| 428 | #endif | ||
| 429 | |||
| 430 | #if SANITIZER_MAC | ||
| 431 | struct __sanitizer_msghdr { | ||
| 432 | void *msg_name; | ||
| 433 | unsigned msg_namelen; | ||
| 434 | struct __sanitizer_iovec *msg_iov; | ||
| 435 | unsigned msg_iovlen; | ||
| 436 | void *msg_control; | ||
| 437 | unsigned msg_controllen; | ||
| 438 | int msg_flags; | ||
| 439 | }; | ||
| 440 | struct __sanitizer_cmsghdr { | ||
| 441 | unsigned cmsg_len; | ||
| 442 | int cmsg_level; | ||
| 443 | int cmsg_type; | ||
| 444 | }; | ||
| 445 | #else | ||
| 446 | struct __sanitizer_msghdr { | ||
| 447 | void *msg_name; | ||
| 448 | unsigned msg_namelen; | ||
| 449 | struct __sanitizer_iovec *msg_iov; | ||
| 450 | uptr msg_iovlen; | ||
| 451 | void *msg_control; | ||
| 452 | uptr msg_controllen; | ||
| 453 | int msg_flags; | ||
| 454 | }; | ||
| 455 | struct __sanitizer_cmsghdr { | ||
| 456 | uptr cmsg_len; | ||
| 457 | int cmsg_level; | ||
| 458 | int cmsg_type; | ||
| 459 | }; | ||
| 460 | #endif | ||
| 461 | |||
| 462 | #if SANITIZER_LINUX | ||
| 463 | struct __sanitizer_mmsghdr { | ||
| 464 | __sanitizer_msghdr msg_hdr; | ||
| 465 | unsigned int msg_len; | ||
| 466 | }; | ||
| 467 | #endif | ||
| 468 | |||
| 469 | #if SANITIZER_MAC | ||
| 470 | struct __sanitizer_dirent { | ||
| 471 | unsigned long long d_ino; | ||
| 472 | unsigned long long d_seekoff; | ||
| 473 | unsigned short d_reclen; | ||
| 474 | // more fields that we don't care about | ||
| 475 | }; | ||
| 476 | #elif SANITIZER_ANDROID || defined(__x86_64__) | ||
| 477 | struct __sanitizer_dirent { | ||
| 478 | unsigned long long d_ino; | ||
| 479 | unsigned long long d_off; | ||
| 480 | unsigned short d_reclen; | ||
| 481 | // more fields that we don't care about | ||
| 482 | }; | ||
| 483 | #else | ||
| 484 | struct __sanitizer_dirent { | ||
| 485 | uptr d_ino; | ||
| 486 | uptr d_off; | ||
| 487 | unsigned short d_reclen; | ||
| 488 | // more fields that we don't care about | ||
| 489 | }; | ||
| 490 | #endif | ||
| 491 | |||
| 492 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 493 | struct __sanitizer_dirent64 { | ||
| 494 | unsigned long long d_ino; | ||
| 495 | unsigned long long d_off; | ||
| 496 | unsigned short d_reclen; | ||
| 497 | // more fields that we don't care about | ||
| 498 | }; | ||
| 499 | #endif | ||
| 500 | |||
| 501 | #if defined(__x86_64__) && !defined(_LP64) | ||
| 502 | typedef long long __sanitizer_clock_t; | ||
| 503 | #else | ||
| 504 | typedef long __sanitizer_clock_t; | ||
| 505 | #endif | ||
| 506 | |||
| 507 | #if SANITIZER_LINUX | ||
| 508 | typedef int __sanitizer_clockid_t; | ||
| 509 | #endif | ||
| 510 | |||
| 511 | #if SANITIZER_LINUX | ||
| 512 | #if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__) || \ | ||
| 513 | defined(__mips__) | ||
| 514 | typedef unsigned __sanitizer___kernel_uid_t; | ||
| 515 | typedef unsigned __sanitizer___kernel_gid_t; | ||
| 516 | #else | ||
| 517 | typedef unsigned short __sanitizer___kernel_uid_t; | ||
| 518 | typedef unsigned short __sanitizer___kernel_gid_t; | ||
| 519 | #endif | ||
| 520 | #if defined(__x86_64__) && !defined(_LP64) | ||
| 521 | typedef long long __sanitizer___kernel_off_t; | ||
| 522 | #else | ||
| 523 | typedef long __sanitizer___kernel_off_t; | ||
| 524 | #endif | ||
| 525 | |||
| 526 | #if defined(__powerpc__) || defined(__mips__) | ||
| 527 | typedef unsigned int __sanitizer___kernel_old_uid_t; | ||
| 528 | typedef unsigned int __sanitizer___kernel_old_gid_t; | ||
| 529 | #else | ||
| 530 | typedef unsigned short __sanitizer___kernel_old_uid_t; | ||
| 531 | typedef unsigned short __sanitizer___kernel_old_gid_t; | ||
| 532 | #endif | ||
| 533 | |||
| 534 | typedef long long __sanitizer___kernel_loff_t; | ||
| 535 | typedef struct { | ||
| 536 | unsigned long fds_bits[1024 / (8 * sizeof(long))]; | ||
| 537 | } __sanitizer___kernel_fd_set; | ||
| 538 | #endif | ||
| 539 | |||
| 540 | // This thing depends on the platform. We are only interested in the upper | ||
| 541 | // limit. Verified with a compiler assert in .cpp. | ||
| 542 | union __sanitizer_pthread_attr_t { | ||
| 543 | char size[128]; | ||
| 544 | void *align; | ||
| 545 | }; | ||
| 546 | |||
| 547 | #if SANITIZER_ANDROID | ||
| 548 | # if SANITIZER_MIPS | ||
| 549 | typedef unsigned long __sanitizer_sigset_t[16 / sizeof(unsigned long)]; | ||
| 550 | # else | ||
| 551 | typedef unsigned long __sanitizer_sigset_t; | ||
| 552 | # endif | ||
| 553 | #elif SANITIZER_MAC | ||
| 554 | typedef unsigned __sanitizer_sigset_t; | ||
| 555 | #elif SANITIZER_LINUX | ||
| 556 | struct __sanitizer_sigset_t { | ||
| 557 | // The size is determined by looking at sizeof of real sigset_t on linux. | ||
| 558 | uptr val[128 / sizeof(uptr)]; | ||
| 559 | }; | ||
| 560 | #endif | ||
| 561 | |||
| 562 | struct __sanitizer_siginfo { | ||
| 563 | // The size is determined by looking at sizeof of real siginfo_t on linux. | ||
| 564 | u64 opaque[128 / sizeof(u64)]; | ||
| 565 | }; | ||
| 566 | |||
| 567 | using __sanitizer_sighandler_ptr = void (*)(int sig); | ||
| 568 | using __sanitizer_sigactionhandler_ptr = void (*)(int sig, | ||
| 569 | __sanitizer_siginfo *siginfo, | ||
| 570 | void *uctx); | ||
| 571 | |||
| 572 | // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. | ||
| 573 | #if SANITIZER_ANDROID && (SANITIZER_WORDSIZE == 64) | ||
| 574 | struct __sanitizer_sigaction { | ||
| 575 | unsigned sa_flags; | ||
| 576 | union { | ||
| 577 | __sanitizer_sigactionhandler_ptr sigaction; | ||
| 578 | __sanitizer_sighandler_ptr handler; | ||
| 579 | }; | ||
| 580 | __sanitizer_sigset_t sa_mask; | ||
| 581 | void (*sa_restorer)(); | ||
| 582 | }; | ||
| 583 | #elif SANITIZER_ANDROID && SANITIZER_MIPS32 // check this before WORDSIZE == 32 | ||
| 584 | struct __sanitizer_sigaction { | ||
| 585 | unsigned sa_flags; | ||
| 586 | union { | ||
| 587 | __sanitizer_sigactionhandler_ptr sigaction; | ||
| 588 | __sanitizer_sighandler_ptr handler; | ||
| 589 | }; | ||
| 590 | __sanitizer_sigset_t sa_mask; | ||
| 591 | }; | ||
| 592 | #elif SANITIZER_ANDROID && (SANITIZER_WORDSIZE == 32) | ||
| 593 | struct __sanitizer_sigaction { | ||
| 594 | union { | ||
| 595 | __sanitizer_sigactionhandler_ptr sigaction; | ||
| 596 | __sanitizer_sighandler_ptr handler; | ||
| 597 | }; | ||
| 598 | __sanitizer_sigset_t sa_mask; | ||
| 599 | uptr sa_flags; | ||
| 600 | void (*sa_restorer)(); | ||
| 601 | }; | ||
| 602 | #else // !SANITIZER_ANDROID | ||
| 603 | struct __sanitizer_sigaction { | ||
| 604 | #if defined(__mips__) && !SANITIZER_FREEBSD | ||
| 605 | unsigned int sa_flags; | ||
| 606 | #endif | ||
| 607 | union { | ||
| 608 | __sanitizer_sigactionhandler_ptr sigaction; | ||
| 609 | __sanitizer_sighandler_ptr handler; | ||
| 610 | }; | ||
| 611 | #if SANITIZER_FREEBSD | ||
| 612 | int sa_flags; | ||
| 613 | __sanitizer_sigset_t sa_mask; | ||
| 614 | #else | ||
| 615 | #if defined(__s390x__) | ||
| 616 | int sa_resv; | ||
| 617 | #else | ||
| 618 | __sanitizer_sigset_t sa_mask; | ||
| 619 | #endif | ||
| 620 | #ifndef __mips__ | ||
| 621 | #if defined(__sparc__) | ||
| 622 | #if __GLIBC_PREREQ (2, 20) | ||
| 623 | // On sparc glibc 2.19 and earlier sa_flags was unsigned long. | ||
| 624 | #if defined(__arch64__) | ||
| 625 | // To maintain ABI compatibility on sparc64 when switching to an int, | ||
| 626 | // __glibc_reserved0 was added. | ||
| 627 | int __glibc_reserved0; | ||
| 628 | #endif | ||
| 629 | int sa_flags; | ||
| 630 | #else | ||
| 631 | unsigned long sa_flags; | ||
| 632 | #endif | ||
| 633 | #else | ||
| 634 | int sa_flags; | ||
| 635 | #endif | ||
| 636 | #endif | ||
| 637 | #endif | ||
| 638 | #if SANITIZER_LINUX | ||
| 639 | void (*sa_restorer)(); | ||
| 640 | #endif | ||
| 641 | #if defined(__mips__) && (SANITIZER_WORDSIZE == 32) | ||
| 642 | int sa_resv[1]; | ||
| 643 | #endif | ||
| 644 | #if defined(__s390x__) | ||
| 645 | __sanitizer_sigset_t sa_mask; | ||
| 646 | #endif | ||
| 647 | }; | ||
| 648 | #endif // !SANITIZER_ANDROID | ||
| 649 | |||
| 650 | #if defined(__mips__) | ||
| 651 | struct __sanitizer_kernel_sigset_t { | ||
| 652 | uptr sig[2]; | ||
| 653 | }; | ||
| 654 | #else | ||
| 655 | struct __sanitizer_kernel_sigset_t { | ||
| 656 | u8 sig[8]; | ||
| 657 | }; | ||
| 658 | #endif | ||
| 659 | |||
| 660 | // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. | ||
| 661 | #if SANITIZER_MIPS | ||
| 662 | struct __sanitizer_kernel_sigaction_t { | ||
| 663 | unsigned int sa_flags; | ||
| 664 | union { | ||
| 665 | void (*handler)(int signo); | ||
| 666 | void (*sigaction)(int signo, __sanitizer_siginfo *info, void *ctx); | ||
| 667 | }; | ||
| 668 | __sanitizer_kernel_sigset_t sa_mask; | ||
| 669 | void (*sa_restorer)(void); | ||
| 670 | }; | ||
| 671 | #else | ||
| 672 | struct __sanitizer_kernel_sigaction_t { | ||
| 673 | union { | ||
| 674 | void (*handler)(int signo); | ||
| 675 | void (*sigaction)(int signo, __sanitizer_siginfo *info, void *ctx); | ||
| 676 | }; | ||
| 677 | unsigned long sa_flags; | ||
| 678 | void (*sa_restorer)(void); | ||
| 679 | __sanitizer_kernel_sigset_t sa_mask; | ||
| 680 | }; | ||
| 681 | #endif | ||
| 682 | |||
| 683 | extern const uptr sig_ign; | ||
| 684 | extern const uptr sig_dfl; | ||
| 685 | extern const uptr sig_err; | ||
| 686 | extern const uptr sa_siginfo; | ||
| 687 | |||
| 688 | #if SANITIZER_LINUX | ||
| 689 | extern int e_tabsz; | ||
| 690 | #endif | ||
| 691 | |||
| 692 | extern int af_inet; | ||
| 693 | extern int af_inet6; | ||
| 694 | uptr __sanitizer_in_addr_sz(int af); | ||
| 695 | |||
| 696 | #if SANITIZER_LINUX | ||
| 697 | struct __sanitizer_dl_phdr_info { | ||
| 698 | uptr dlpi_addr; | ||
| 699 | const char *dlpi_name; | ||
| 700 | const void *dlpi_phdr; | ||
| 701 | short dlpi_phnum; | ||
| 702 | }; | ||
| 703 | |||
| 704 | extern unsigned struct_ElfW_Phdr_sz; | ||
| 705 | #endif | ||
| 706 | |||
| 707 | struct __sanitizer_protoent { | ||
| 708 | char *p_name; | ||
| 709 | char **p_aliases; | ||
| 710 | int p_proto; | ||
| 711 | }; | ||
| 712 | |||
| 713 | struct __sanitizer_addrinfo { | ||
| 714 | int ai_flags; | ||
| 715 | int ai_family; | ||
| 716 | int ai_socktype; | ||
| 717 | int ai_protocol; | ||
| 718 | #if SANITIZER_ANDROID || SANITIZER_MAC | ||
| 719 | unsigned ai_addrlen; | ||
| 720 | char *ai_canonname; | ||
| 721 | void *ai_addr; | ||
| 722 | #else // LINUX | ||
| 723 | unsigned ai_addrlen; | ||
| 724 | void *ai_addr; | ||
| 725 | char *ai_canonname; | ||
| 726 | #endif | ||
| 727 | struct __sanitizer_addrinfo *ai_next; | ||
| 728 | }; | ||
| 729 | |||
| 730 | struct __sanitizer_hostent { | ||
| 731 | char *h_name; | ||
| 732 | char **h_aliases; | ||
| 733 | int h_addrtype; | ||
| 734 | int h_length; | ||
| 735 | char **h_addr_list; | ||
| 736 | }; | ||
| 737 | |||
| 738 | struct __sanitizer_pollfd { | ||
| 739 | int fd; | ||
| 740 | short events; | ||
| 741 | short revents; | ||
| 742 | }; | ||
| 743 | |||
| 744 | #if SANITIZER_ANDROID || SANITIZER_MAC | ||
| 745 | typedef unsigned __sanitizer_nfds_t; | ||
| 746 | #else | ||
| 747 | typedef unsigned long __sanitizer_nfds_t; | ||
| 748 | #endif | ||
| 749 | |||
| 750 | #if !SANITIZER_ANDROID | ||
| 751 | # if SANITIZER_LINUX | ||
| 752 | struct __sanitizer_glob_t { | ||
| 753 | uptr gl_pathc; | ||
| 754 | char **gl_pathv; | ||
| 755 | uptr gl_offs; | ||
| 756 | int gl_flags; | ||
| 757 | |||
| 758 | void (*gl_closedir)(void *dirp); | ||
| 759 | void *(*gl_readdir)(void *dirp); | ||
| 760 | void *(*gl_opendir)(const char *); | ||
| 761 | int (*gl_lstat)(const char *, void *); | ||
| 762 | int (*gl_stat)(const char *, void *); | ||
| 763 | }; | ||
| 764 | # endif // SANITIZER_LINUX | ||
| 765 | |||
| 766 | # if SANITIZER_LINUX | ||
| 767 | extern int glob_nomatch; | ||
| 768 | extern int glob_altdirfunc; | ||
| 769 | # endif | ||
| 770 | #endif // !SANITIZER_ANDROID | ||
| 771 | |||
| 772 | extern unsigned path_max; | ||
| 773 | |||
| 774 | struct __sanitizer_wordexp_t { | ||
| 775 | uptr we_wordc; | ||
| 776 | char **we_wordv; | ||
| 777 | uptr we_offs; | ||
| 778 | }; | ||
| 779 | |||
| 780 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 781 | struct __sanitizer_FILE { | ||
| 782 | int _flags; | ||
| 783 | char *_IO_read_ptr; | ||
| 784 | char *_IO_read_end; | ||
| 785 | char *_IO_read_base; | ||
| 786 | char *_IO_write_base; | ||
| 787 | char *_IO_write_ptr; | ||
| 788 | char *_IO_write_end; | ||
| 789 | char *_IO_buf_base; | ||
| 790 | char *_IO_buf_end; | ||
| 791 | char *_IO_save_base; | ||
| 792 | char *_IO_backup_base; | ||
| 793 | char *_IO_save_end; | ||
| 794 | void *_markers; | ||
| 795 | __sanitizer_FILE *_chain; | ||
| 796 | int _fileno; | ||
| 797 | }; | ||
| 798 | # define SANITIZER_HAS_STRUCT_FILE 1 | ||
| 799 | #else | ||
| 800 | typedef void __sanitizer_FILE; | ||
| 801 | # define SANITIZER_HAS_STRUCT_FILE 0 | ||
| 802 | #endif | ||
| 803 | |||
| 804 | #if SANITIZER_LINUX && !SANITIZER_ANDROID && \ | ||
| 805 | (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ | ||
| 806 | defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ | ||
| 807 | defined(__s390__)) | ||
| 808 | extern unsigned struct_user_regs_struct_sz; | ||
| 809 | extern unsigned struct_user_fpregs_struct_sz; | ||
| 810 | extern unsigned struct_user_fpxregs_struct_sz; | ||
| 811 | extern unsigned struct_user_vfpregs_struct_sz; | ||
| 812 | |||
| 813 | extern int ptrace_peektext; | ||
| 814 | extern int ptrace_peekdata; | ||
| 815 | extern int ptrace_peekuser; | ||
| 816 | extern int ptrace_getregs; | ||
| 817 | extern int ptrace_setregs; | ||
| 818 | extern int ptrace_getfpregs; | ||
| 819 | extern int ptrace_setfpregs; | ||
| 820 | extern int ptrace_getfpxregs; | ||
| 821 | extern int ptrace_setfpxregs; | ||
| 822 | extern int ptrace_getvfpregs; | ||
| 823 | extern int ptrace_setvfpregs; | ||
| 824 | extern int ptrace_getsiginfo; | ||
| 825 | extern int ptrace_setsiginfo; | ||
| 826 | extern int ptrace_getregset; | ||
| 827 | extern int ptrace_setregset; | ||
| 828 | extern int ptrace_geteventmsg; | ||
| 829 | #endif | ||
| 830 | |||
| 831 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 832 | extern unsigned struct_shminfo_sz; | ||
| 833 | extern unsigned struct_shm_info_sz; | ||
| 834 | extern int shmctl_ipc_stat; | ||
| 835 | extern int shmctl_ipc_info; | ||
| 836 | extern int shmctl_shm_info; | ||
| 837 | extern int shmctl_shm_stat; | ||
| 838 | #endif | ||
| 839 | |||
| 840 | #if !SANITIZER_MAC && !SANITIZER_FREEBSD | ||
| 841 | extern unsigned struct_utmp_sz; | ||
| 842 | #endif | ||
| 843 | #if !SANITIZER_ANDROID | ||
| 844 | extern unsigned struct_utmpx_sz; | ||
| 845 | #endif | ||
| 846 | |||
| 847 | extern int map_fixed; | ||
| 848 | |||
| 849 | // ioctl arguments | ||
| 850 | struct __sanitizer_ifconf { | ||
| 851 | int ifc_len; | ||
| 852 | union { | ||
| 853 | void *ifcu_req; | ||
| 854 | } ifc_ifcu; | ||
| 855 | #if SANITIZER_MAC | ||
| 856 | } __attribute__((packed)); | ||
| 857 | #else | ||
| 858 | }; | ||
| 859 | #endif | ||
| 860 | |||
| 861 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 862 | struct __sanitizer__obstack_chunk { | ||
| 863 | char *limit; | ||
| 864 | struct __sanitizer__obstack_chunk *prev; | ||
| 865 | }; | ||
| 866 | |||
| 867 | struct __sanitizer_obstack { | ||
| 868 | long chunk_size; | ||
| 869 | struct __sanitizer__obstack_chunk *chunk; | ||
| 870 | char *object_base; | ||
| 871 | char *next_free; | ||
| 872 | uptr more_fields[7]; | ||
| 873 | }; | ||
| 874 | |||
| 875 | typedef uptr (*__sanitizer_cookie_io_read)(void *cookie, char *buf, uptr size); | ||
| 876 | typedef uptr (*__sanitizer_cookie_io_write)(void *cookie, const char *buf, | ||
| 877 | uptr size); | ||
| 878 | typedef int (*__sanitizer_cookie_io_seek)(void *cookie, u64 *offset, | ||
| 879 | int whence); | ||
| 880 | typedef int (*__sanitizer_cookie_io_close)(void *cookie); | ||
| 881 | |||
| 882 | struct __sanitizer_cookie_io_functions_t { | ||
| 883 | __sanitizer_cookie_io_read read; | ||
| 884 | __sanitizer_cookie_io_write write; | ||
| 885 | __sanitizer_cookie_io_seek seek; | ||
| 886 | __sanitizer_cookie_io_close close; | ||
| 887 | }; | ||
| 888 | #endif | ||
| 889 | |||
| 890 | #define IOC_NRBITS 8 | ||
| 891 | #define IOC_TYPEBITS 8 | ||
| 892 | #if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__) || \ | ||
| 893 | defined(__sparc__) | ||
| 894 | #define IOC_SIZEBITS 13 | ||
| 895 | #define IOC_DIRBITS 3 | ||
| 896 | #define IOC_NONE 1U | ||
| 897 | #define IOC_WRITE 4U | ||
| 898 | #define IOC_READ 2U | ||
| 899 | #else | ||
| 900 | #define IOC_SIZEBITS 14 | ||
| 901 | #define IOC_DIRBITS 2 | ||
| 902 | #define IOC_NONE 0U | ||
| 903 | #define IOC_WRITE 1U | ||
| 904 | #define IOC_READ 2U | ||
| 905 | #endif | ||
| 906 | #define IOC_NRMASK ((1 << IOC_NRBITS) - 1) | ||
| 907 | #define IOC_TYPEMASK ((1 << IOC_TYPEBITS) - 1) | ||
| 908 | #define IOC_SIZEMASK ((1 << IOC_SIZEBITS) - 1) | ||
| 909 | #if defined(IOC_DIRMASK) | ||
| 910 | #undef IOC_DIRMASK | ||
| 911 | #endif | ||
| 912 | #define IOC_DIRMASK ((1 << IOC_DIRBITS) - 1) | ||
| 913 | #define IOC_NRSHIFT 0 | ||
| 914 | #define IOC_TYPESHIFT (IOC_NRSHIFT + IOC_NRBITS) | ||
| 915 | #define IOC_SIZESHIFT (IOC_TYPESHIFT + IOC_TYPEBITS) | ||
| 916 | #define IOC_DIRSHIFT (IOC_SIZESHIFT + IOC_SIZEBITS) | ||
| 917 | #define EVIOC_EV_MAX 0x1f | ||
| 918 | #define EVIOC_ABS_MAX 0x3f | ||
| 919 | |||
| 920 | #define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK) | ||
| 921 | #define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK) | ||
| 922 | #define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK) | ||
| 923 | |||
| 924 | #if defined(__sparc__) | ||
| 925 | // In sparc the 14 bits SIZE field overlaps with the | ||
| 926 | // least significant bit of DIR, so either IOC_READ or | ||
| 927 | // IOC_WRITE shall be 1 in order to get a non-zero SIZE. | ||
| 928 | #define IOC_SIZE(nr) \ | ||
| 929 | ((((((nr) >> 29) & 0x7) & (4U | 2U)) == 0) ? 0 : (((nr) >> 16) & 0x3fff)) | ||
| 930 | #else | ||
| 931 | #define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) | ||
| 932 | #endif | ||
| 933 | |||
| 934 | extern unsigned struct_ifreq_sz; | ||
| 935 | extern unsigned struct_termios_sz; | ||
| 936 | extern unsigned struct_winsize_sz; | ||
| 937 | |||
| 938 | #if SANITIZER_LINUX | ||
| 939 | extern unsigned struct_arpreq_sz; | ||
| 940 | extern unsigned struct_cdrom_msf_sz; | ||
| 941 | extern unsigned struct_cdrom_multisession_sz; | ||
| 942 | extern unsigned struct_cdrom_read_audio_sz; | ||
| 943 | extern unsigned struct_cdrom_subchnl_sz; | ||
| 944 | extern unsigned struct_cdrom_ti_sz; | ||
| 945 | extern unsigned struct_cdrom_tocentry_sz; | ||
| 946 | extern unsigned struct_cdrom_tochdr_sz; | ||
| 947 | extern unsigned struct_cdrom_volctrl_sz; | ||
| 948 | extern unsigned struct_ff_effect_sz; | ||
| 949 | extern unsigned struct_floppy_drive_params_sz; | ||
| 950 | extern unsigned struct_floppy_drive_struct_sz; | ||
| 951 | extern unsigned struct_floppy_fdc_state_sz; | ||
| 952 | extern unsigned struct_floppy_max_errors_sz; | ||
| 953 | extern unsigned struct_floppy_raw_cmd_sz; | ||
| 954 | extern unsigned struct_floppy_struct_sz; | ||
| 955 | extern unsigned struct_floppy_write_errors_sz; | ||
| 956 | extern unsigned struct_format_descr_sz; | ||
| 957 | extern unsigned struct_hd_driveid_sz; | ||
| 958 | extern unsigned struct_hd_geometry_sz; | ||
| 959 | extern unsigned struct_input_absinfo_sz; | ||
| 960 | extern unsigned struct_input_id_sz; | ||
| 961 | extern unsigned struct_mtpos_sz; | ||
| 962 | extern unsigned struct_termio_sz; | ||
| 963 | extern unsigned struct_vt_consize_sz; | ||
| 964 | extern unsigned struct_vt_sizes_sz; | ||
| 965 | extern unsigned struct_vt_stat_sz; | ||
| 966 | #endif // SANITIZER_LINUX | ||
| 967 | |||
| 968 | #if SANITIZER_LINUX | ||
| 969 | extern unsigned struct_copr_buffer_sz; | ||
| 970 | extern unsigned struct_copr_debug_buf_sz; | ||
| 971 | extern unsigned struct_copr_msg_sz; | ||
| 972 | extern unsigned struct_midi_info_sz; | ||
| 973 | extern unsigned struct_mtget_sz; | ||
| 974 | extern unsigned struct_mtop_sz; | ||
| 975 | extern unsigned struct_rtentry_sz; | ||
| 976 | extern unsigned struct_sbi_instrument_sz; | ||
| 977 | extern unsigned struct_seq_event_rec_sz; | ||
| 978 | extern unsigned struct_synth_info_sz; | ||
| 979 | extern unsigned struct_vt_mode_sz; | ||
| 980 | #endif // SANITIZER_LINUX | ||
| 981 | |||
| 982 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 983 | extern unsigned struct_ax25_parms_struct_sz; | ||
| 984 | extern unsigned struct_cyclades_monitor_sz; | ||
| 985 | extern unsigned struct_input_keymap_entry_sz; | ||
| 986 | extern unsigned struct_ipx_config_data_sz; | ||
| 987 | extern unsigned struct_kbdiacrs_sz; | ||
| 988 | extern unsigned struct_kbentry_sz; | ||
| 989 | extern unsigned struct_kbkeycode_sz; | ||
| 990 | extern unsigned struct_kbsentry_sz; | ||
| 991 | extern unsigned struct_mtconfiginfo_sz; | ||
| 992 | extern unsigned struct_nr_parms_struct_sz; | ||
| 993 | extern unsigned struct_scc_modem_sz; | ||
| 994 | extern unsigned struct_scc_stat_sz; | ||
| 995 | extern unsigned struct_serial_multiport_struct_sz; | ||
| 996 | extern unsigned struct_serial_struct_sz; | ||
| 997 | extern unsigned struct_sockaddr_ax25_sz; | ||
| 998 | extern unsigned struct_unimapdesc_sz; | ||
| 999 | extern unsigned struct_unimapinit_sz; | ||
| 1000 | #endif // SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 1001 | |||
| 1002 | extern const unsigned long __sanitizer_bufsiz; | ||
| 1003 | |||
| 1004 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 1005 | extern unsigned struct_audio_buf_info_sz; | ||
| 1006 | extern unsigned struct_ppp_stats_sz; | ||
| 1007 | #endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID | ||
| 1008 | |||
| 1009 | #if !SANITIZER_ANDROID && !SANITIZER_MAC | ||
| 1010 | extern unsigned struct_sioc_sg_req_sz; | ||
| 1011 | extern unsigned struct_sioc_vif_req_sz; | ||
| 1012 | #endif | ||
| 1013 | |||
| 1014 | // ioctl request identifiers | ||
| 1015 | |||
| 1016 | // A special value to mark ioctls that are not present on the target platform, | ||
| 1017 | // when it can not be determined without including any system headers. | ||
| 1018 | extern const unsigned IOCTL_NOT_PRESENT; | ||
| 1019 | |||
| 1020 | extern unsigned IOCTL_FIOASYNC; | ||
| 1021 | extern unsigned IOCTL_FIOCLEX; | ||
| 1022 | extern unsigned IOCTL_FIOGETOWN; | ||
| 1023 | extern unsigned IOCTL_FIONBIO; | ||
| 1024 | extern unsigned IOCTL_FIONCLEX; | ||
| 1025 | extern unsigned IOCTL_FIOSETOWN; | ||
| 1026 | extern unsigned IOCTL_SIOCADDMULTI; | ||
| 1027 | extern unsigned IOCTL_SIOCATMARK; | ||
| 1028 | extern unsigned IOCTL_SIOCDELMULTI; | ||
| 1029 | extern unsigned IOCTL_SIOCGIFADDR; | ||
| 1030 | extern unsigned IOCTL_SIOCGIFBRDADDR; | ||
| 1031 | extern unsigned IOCTL_SIOCGIFCONF; | ||
| 1032 | extern unsigned IOCTL_SIOCGIFDSTADDR; | ||
| 1033 | extern unsigned IOCTL_SIOCGIFFLAGS; | ||
| 1034 | extern unsigned IOCTL_SIOCGIFMETRIC; | ||
| 1035 | extern unsigned IOCTL_SIOCGIFMTU; | ||
| 1036 | extern unsigned IOCTL_SIOCGIFNETMASK; | ||
| 1037 | extern unsigned IOCTL_SIOCGPGRP; | ||
| 1038 | extern unsigned IOCTL_SIOCSIFADDR; | ||
| 1039 | extern unsigned IOCTL_SIOCSIFBRDADDR; | ||
| 1040 | extern unsigned IOCTL_SIOCSIFDSTADDR; | ||
| 1041 | extern unsigned IOCTL_SIOCSIFFLAGS; | ||
| 1042 | extern unsigned IOCTL_SIOCSIFMETRIC; | ||
| 1043 | extern unsigned IOCTL_SIOCSIFMTU; | ||
| 1044 | extern unsigned IOCTL_SIOCSIFNETMASK; | ||
| 1045 | extern unsigned IOCTL_SIOCSPGRP; | ||
| 1046 | extern unsigned IOCTL_TIOCCONS; | ||
| 1047 | extern unsigned IOCTL_TIOCEXCL; | ||
| 1048 | extern unsigned IOCTL_TIOCGETD; | ||
| 1049 | extern unsigned IOCTL_TIOCGPGRP; | ||
| 1050 | extern unsigned IOCTL_TIOCGWINSZ; | ||
| 1051 | extern unsigned IOCTL_TIOCMBIC; | ||
| 1052 | extern unsigned IOCTL_TIOCMBIS; | ||
| 1053 | extern unsigned IOCTL_TIOCMGET; | ||
| 1054 | extern unsigned IOCTL_TIOCMSET; | ||
| 1055 | extern unsigned IOCTL_TIOCNOTTY; | ||
| 1056 | extern unsigned IOCTL_TIOCNXCL; | ||
| 1057 | extern unsigned IOCTL_TIOCOUTQ; | ||
| 1058 | extern unsigned IOCTL_TIOCPKT; | ||
| 1059 | extern unsigned IOCTL_TIOCSCTTY; | ||
| 1060 | extern unsigned IOCTL_TIOCSETD; | ||
| 1061 | extern unsigned IOCTL_TIOCSPGRP; | ||
| 1062 | extern unsigned IOCTL_TIOCSTI; | ||
| 1063 | extern unsigned IOCTL_TIOCSWINSZ; | ||
| 1064 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 1065 | extern unsigned IOCTL_SIOCGETSGCNT; | ||
| 1066 | extern unsigned IOCTL_SIOCGETVIFCNT; | ||
| 1067 | #endif | ||
| 1068 | #if SANITIZER_LINUX | ||
| 1069 | extern unsigned IOCTL_EVIOCGABS; | ||
| 1070 | extern unsigned IOCTL_EVIOCGBIT; | ||
| 1071 | extern unsigned IOCTL_EVIOCGEFFECTS; | ||
| 1072 | extern unsigned IOCTL_EVIOCGID; | ||
| 1073 | extern unsigned IOCTL_EVIOCGKEY; | ||
| 1074 | extern unsigned IOCTL_EVIOCGKEYCODE; | ||
| 1075 | extern unsigned IOCTL_EVIOCGLED; | ||
| 1076 | extern unsigned IOCTL_EVIOCGNAME; | ||
| 1077 | extern unsigned IOCTL_EVIOCGPHYS; | ||
| 1078 | extern unsigned IOCTL_EVIOCGRAB; | ||
| 1079 | extern unsigned IOCTL_EVIOCGREP; | ||
| 1080 | extern unsigned IOCTL_EVIOCGSND; | ||
| 1081 | extern unsigned IOCTL_EVIOCGSW; | ||
| 1082 | extern unsigned IOCTL_EVIOCGUNIQ; | ||
| 1083 | extern unsigned IOCTL_EVIOCGVERSION; | ||
| 1084 | extern unsigned IOCTL_EVIOCRMFF; | ||
| 1085 | extern unsigned IOCTL_EVIOCSABS; | ||
| 1086 | extern unsigned IOCTL_EVIOCSFF; | ||
| 1087 | extern unsigned IOCTL_EVIOCSKEYCODE; | ||
| 1088 | extern unsigned IOCTL_EVIOCSREP; | ||
| 1089 | extern unsigned IOCTL_BLKFLSBUF; | ||
| 1090 | extern unsigned IOCTL_BLKGETSIZE; | ||
| 1091 | extern unsigned IOCTL_BLKRAGET; | ||
| 1092 | extern unsigned IOCTL_BLKRASET; | ||
| 1093 | extern unsigned IOCTL_BLKROGET; | ||
| 1094 | extern unsigned IOCTL_BLKROSET; | ||
| 1095 | extern unsigned IOCTL_BLKRRPART; | ||
| 1096 | extern unsigned IOCTL_CDROMAUDIOBUFSIZ; | ||
| 1097 | extern unsigned IOCTL_CDROMEJECT; | ||
| 1098 | extern unsigned IOCTL_CDROMEJECT_SW; | ||
| 1099 | extern unsigned IOCTL_CDROMMULTISESSION; | ||
| 1100 | extern unsigned IOCTL_CDROMPAUSE; | ||
| 1101 | extern unsigned IOCTL_CDROMPLAYMSF; | ||
| 1102 | extern unsigned IOCTL_CDROMPLAYTRKIND; | ||
| 1103 | extern unsigned IOCTL_CDROMREADAUDIO; | ||
| 1104 | extern unsigned IOCTL_CDROMREADCOOKED; | ||
| 1105 | extern unsigned IOCTL_CDROMREADMODE1; | ||
| 1106 | extern unsigned IOCTL_CDROMREADMODE2; | ||
| 1107 | extern unsigned IOCTL_CDROMREADRAW; | ||
| 1108 | extern unsigned IOCTL_CDROMREADTOCENTRY; | ||
| 1109 | extern unsigned IOCTL_CDROMREADTOCHDR; | ||
| 1110 | extern unsigned IOCTL_CDROMRESET; | ||
| 1111 | extern unsigned IOCTL_CDROMRESUME; | ||
| 1112 | extern unsigned IOCTL_CDROMSEEK; | ||
| 1113 | extern unsigned IOCTL_CDROMSTART; | ||
| 1114 | extern unsigned IOCTL_CDROMSTOP; | ||
| 1115 | extern unsigned IOCTL_CDROMSUBCHNL; | ||
| 1116 | extern unsigned IOCTL_CDROMVOLCTRL; | ||
| 1117 | extern unsigned IOCTL_CDROMVOLREAD; | ||
| 1118 | extern unsigned IOCTL_CDROM_GET_UPC; | ||
| 1119 | extern unsigned IOCTL_FDCLRPRM; | ||
| 1120 | extern unsigned IOCTL_FDDEFPRM; | ||
| 1121 | extern unsigned IOCTL_FDFLUSH; | ||
| 1122 | extern unsigned IOCTL_FDFMTBEG; | ||
| 1123 | extern unsigned IOCTL_FDFMTEND; | ||
| 1124 | extern unsigned IOCTL_FDFMTTRK; | ||
| 1125 | extern unsigned IOCTL_FDGETDRVPRM; | ||
| 1126 | extern unsigned IOCTL_FDGETDRVSTAT; | ||
| 1127 | extern unsigned IOCTL_FDGETDRVTYP; | ||
| 1128 | extern unsigned IOCTL_FDGETFDCSTAT; | ||
| 1129 | extern unsigned IOCTL_FDGETMAXERRS; | ||
| 1130 | extern unsigned IOCTL_FDGETPRM; | ||
| 1131 | extern unsigned IOCTL_FDMSGOFF; | ||
| 1132 | extern unsigned IOCTL_FDMSGON; | ||
| 1133 | extern unsigned IOCTL_FDPOLLDRVSTAT; | ||
| 1134 | extern unsigned IOCTL_FDRAWCMD; | ||
| 1135 | extern unsigned IOCTL_FDRESET; | ||
| 1136 | extern unsigned IOCTL_FDSETDRVPRM; | ||
| 1137 | extern unsigned IOCTL_FDSETEMSGTRESH; | ||
| 1138 | extern unsigned IOCTL_FDSETMAXERRS; | ||
| 1139 | extern unsigned IOCTL_FDSETPRM; | ||
| 1140 | extern unsigned IOCTL_FDTWADDLE; | ||
| 1141 | extern unsigned IOCTL_FDWERRORCLR; | ||
| 1142 | extern unsigned IOCTL_FDWERRORGET; | ||
| 1143 | extern unsigned IOCTL_HDIO_DRIVE_CMD; | ||
| 1144 | extern unsigned IOCTL_HDIO_GETGEO; | ||
| 1145 | extern unsigned IOCTL_HDIO_GET_32BIT; | ||
| 1146 | extern unsigned IOCTL_HDIO_GET_DMA; | ||
| 1147 | extern unsigned IOCTL_HDIO_GET_IDENTITY; | ||
| 1148 | extern unsigned IOCTL_HDIO_GET_KEEPSETTINGS; | ||
| 1149 | extern unsigned IOCTL_HDIO_GET_MULTCOUNT; | ||
| 1150 | extern unsigned IOCTL_HDIO_GET_NOWERR; | ||
| 1151 | extern unsigned IOCTL_HDIO_GET_UNMASKINTR; | ||
| 1152 | extern unsigned IOCTL_HDIO_SET_32BIT; | ||
| 1153 | extern unsigned IOCTL_HDIO_SET_DMA; | ||
| 1154 | extern unsigned IOCTL_HDIO_SET_KEEPSETTINGS; | ||
| 1155 | extern unsigned IOCTL_HDIO_SET_MULTCOUNT; | ||
| 1156 | extern unsigned IOCTL_HDIO_SET_NOWERR; | ||
| 1157 | extern unsigned IOCTL_HDIO_SET_UNMASKINTR; | ||
| 1158 | extern unsigned IOCTL_MTIOCPOS; | ||
| 1159 | extern unsigned IOCTL_PPPIOCGASYNCMAP; | ||
| 1160 | extern unsigned IOCTL_PPPIOCGDEBUG; | ||
| 1161 | extern unsigned IOCTL_PPPIOCGFLAGS; | ||
| 1162 | extern unsigned IOCTL_PPPIOCGUNIT; | ||
| 1163 | extern unsigned IOCTL_PPPIOCGXASYNCMAP; | ||
| 1164 | extern unsigned IOCTL_PPPIOCSASYNCMAP; | ||
| 1165 | extern unsigned IOCTL_PPPIOCSDEBUG; | ||
| 1166 | extern unsigned IOCTL_PPPIOCSFLAGS; | ||
| 1167 | extern unsigned IOCTL_PPPIOCSMAXCID; | ||
| 1168 | extern unsigned IOCTL_PPPIOCSMRU; | ||
| 1169 | extern unsigned IOCTL_PPPIOCSXASYNCMAP; | ||
| 1170 | extern unsigned IOCTL_SIOCDARP; | ||
| 1171 | extern unsigned IOCTL_SIOCDRARP; | ||
| 1172 | extern unsigned IOCTL_SIOCGARP; | ||
| 1173 | extern unsigned IOCTL_SIOCGIFENCAP; | ||
| 1174 | extern unsigned IOCTL_SIOCGIFHWADDR; | ||
| 1175 | extern unsigned IOCTL_SIOCGIFMAP; | ||
| 1176 | extern unsigned IOCTL_SIOCGIFMEM; | ||
| 1177 | extern unsigned IOCTL_SIOCGIFNAME; | ||
| 1178 | extern unsigned IOCTL_SIOCGIFSLAVE; | ||
| 1179 | extern unsigned IOCTL_SIOCGRARP; | ||
| 1180 | extern unsigned IOCTL_SIOCGSTAMP; | ||
| 1181 | extern unsigned IOCTL_SIOCSARP; | ||
| 1182 | extern unsigned IOCTL_SIOCSIFENCAP; | ||
| 1183 | extern unsigned IOCTL_SIOCSIFHWADDR; | ||
| 1184 | extern unsigned IOCTL_SIOCSIFLINK; | ||
| 1185 | extern unsigned IOCTL_SIOCSIFMAP; | ||
| 1186 | extern unsigned IOCTL_SIOCSIFMEM; | ||
| 1187 | extern unsigned IOCTL_SIOCSIFSLAVE; | ||
| 1188 | extern unsigned IOCTL_SIOCSRARP; | ||
| 1189 | extern unsigned IOCTL_SNDCTL_COPR_HALT; | ||
| 1190 | extern unsigned IOCTL_SNDCTL_COPR_LOAD; | ||
| 1191 | extern unsigned IOCTL_SNDCTL_COPR_RCODE; | ||
| 1192 | extern unsigned IOCTL_SNDCTL_COPR_RCVMSG; | ||
| 1193 | extern unsigned IOCTL_SNDCTL_COPR_RDATA; | ||
| 1194 | extern unsigned IOCTL_SNDCTL_COPR_RESET; | ||
| 1195 | extern unsigned IOCTL_SNDCTL_COPR_RUN; | ||
| 1196 | extern unsigned IOCTL_SNDCTL_COPR_SENDMSG; | ||
| 1197 | extern unsigned IOCTL_SNDCTL_COPR_WCODE; | ||
| 1198 | extern unsigned IOCTL_SNDCTL_COPR_WDATA; | ||
| 1199 | extern unsigned IOCTL_TCFLSH; | ||
| 1200 | extern unsigned IOCTL_TCGETA; | ||
| 1201 | extern unsigned IOCTL_TCGETS; | ||
| 1202 | extern unsigned IOCTL_TCSBRK; | ||
| 1203 | extern unsigned IOCTL_TCSBRKP; | ||
| 1204 | extern unsigned IOCTL_TCSETA; | ||
| 1205 | extern unsigned IOCTL_TCSETAF; | ||
| 1206 | extern unsigned IOCTL_TCSETAW; | ||
| 1207 | extern unsigned IOCTL_TCSETS; | ||
| 1208 | extern unsigned IOCTL_TCSETSF; | ||
| 1209 | extern unsigned IOCTL_TCSETSW; | ||
| 1210 | extern unsigned IOCTL_TCXONC; | ||
| 1211 | extern unsigned IOCTL_TIOCGLCKTRMIOS; | ||
| 1212 | extern unsigned IOCTL_TIOCGSOFTCAR; | ||
| 1213 | extern unsigned IOCTL_TIOCINQ; | ||
| 1214 | extern unsigned IOCTL_TIOCLINUX; | ||
| 1215 | extern unsigned IOCTL_TIOCSERCONFIG; | ||
| 1216 | extern unsigned IOCTL_TIOCSERGETLSR; | ||
| 1217 | extern unsigned IOCTL_TIOCSERGWILD; | ||
| 1218 | extern unsigned IOCTL_TIOCSERSWILD; | ||
| 1219 | extern unsigned IOCTL_TIOCSLCKTRMIOS; | ||
| 1220 | extern unsigned IOCTL_TIOCSSOFTCAR; | ||
| 1221 | extern unsigned IOCTL_VT_DISALLOCATE; | ||
| 1222 | extern unsigned IOCTL_VT_GETSTATE; | ||
| 1223 | extern unsigned IOCTL_VT_RESIZE; | ||
| 1224 | extern unsigned IOCTL_VT_RESIZEX; | ||
| 1225 | extern unsigned IOCTL_VT_SENDSIG; | ||
| 1226 | extern unsigned IOCTL_MTIOCGET; | ||
| 1227 | extern unsigned IOCTL_MTIOCTOP; | ||
| 1228 | extern unsigned IOCTL_SIOCADDRT; | ||
| 1229 | extern unsigned IOCTL_SIOCDELRT; | ||
| 1230 | extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; | ||
| 1231 | extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; | ||
| 1232 | extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; | ||
| 1233 | extern unsigned IOCTL_SNDCTL_DSP_POST; | ||
| 1234 | extern unsigned IOCTL_SNDCTL_DSP_RESET; | ||
| 1235 | extern unsigned IOCTL_SNDCTL_DSP_SETFMT; | ||
| 1236 | extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; | ||
| 1237 | extern unsigned IOCTL_SNDCTL_DSP_SPEED; | ||
| 1238 | extern unsigned IOCTL_SNDCTL_DSP_STEREO; | ||
| 1239 | extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; | ||
| 1240 | extern unsigned IOCTL_SNDCTL_DSP_SYNC; | ||
| 1241 | extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE; | ||
| 1242 | extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR; | ||
| 1243 | extern unsigned IOCTL_SNDCTL_MIDI_INFO; | ||
| 1244 | extern unsigned IOCTL_SNDCTL_MIDI_PRETIME; | ||
| 1245 | extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE; | ||
| 1246 | extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT; | ||
| 1247 | extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT; | ||
| 1248 | extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS; | ||
| 1249 | extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS; | ||
| 1250 | extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND; | ||
| 1251 | extern unsigned IOCTL_SNDCTL_SEQ_PANIC; | ||
| 1252 | extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE; | ||
| 1253 | extern unsigned IOCTL_SNDCTL_SEQ_RESET; | ||
| 1254 | extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES; | ||
| 1255 | extern unsigned IOCTL_SNDCTL_SEQ_SYNC; | ||
| 1256 | extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI; | ||
| 1257 | extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD; | ||
| 1258 | extern unsigned IOCTL_SNDCTL_SYNTH_INFO; | ||
| 1259 | extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL; | ||
| 1260 | extern unsigned IOCTL_SNDCTL_TMR_CONTINUE; | ||
| 1261 | extern unsigned IOCTL_SNDCTL_TMR_METRONOME; | ||
| 1262 | extern unsigned IOCTL_SNDCTL_TMR_SELECT; | ||
| 1263 | extern unsigned IOCTL_SNDCTL_TMR_SOURCE; | ||
| 1264 | extern unsigned IOCTL_SNDCTL_TMR_START; | ||
| 1265 | extern unsigned IOCTL_SNDCTL_TMR_STOP; | ||
| 1266 | extern unsigned IOCTL_SNDCTL_TMR_TEMPO; | ||
| 1267 | extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE; | ||
| 1268 | extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM; | ||
| 1269 | extern unsigned IOCTL_SOUND_MIXER_READ_BASS; | ||
| 1270 | extern unsigned IOCTL_SOUND_MIXER_READ_CAPS; | ||
| 1271 | extern unsigned IOCTL_SOUND_MIXER_READ_CD; | ||
| 1272 | extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK; | ||
| 1273 | extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE; | ||
| 1274 | extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN; | ||
| 1275 | extern unsigned IOCTL_SOUND_MIXER_READ_IMIX; | ||
| 1276 | extern unsigned IOCTL_SOUND_MIXER_READ_LINE1; | ||
| 1277 | extern unsigned IOCTL_SOUND_MIXER_READ_LINE2; | ||
| 1278 | extern unsigned IOCTL_SOUND_MIXER_READ_LINE3; | ||
| 1279 | extern unsigned IOCTL_SOUND_MIXER_READ_LINE; | ||
| 1280 | extern unsigned IOCTL_SOUND_MIXER_READ_LOUD; | ||
| 1281 | extern unsigned IOCTL_SOUND_MIXER_READ_MIC; | ||
| 1282 | extern unsigned IOCTL_SOUND_MIXER_READ_MUTE; | ||
| 1283 | extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN; | ||
| 1284 | extern unsigned IOCTL_SOUND_MIXER_READ_PCM; | ||
| 1285 | extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV; | ||
| 1286 | extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK; | ||
| 1287 | extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC; | ||
| 1288 | extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER; | ||
| 1289 | extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS; | ||
| 1290 | extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH; | ||
| 1291 | extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE; | ||
| 1292 | extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME; | ||
| 1293 | extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM; | ||
| 1294 | extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS; | ||
| 1295 | extern unsigned IOCTL_SOUND_MIXER_WRITE_CD; | ||
| 1296 | extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE; | ||
| 1297 | extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN; | ||
| 1298 | extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX; | ||
| 1299 | extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1; | ||
| 1300 | extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2; | ||
| 1301 | extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3; | ||
| 1302 | extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE; | ||
| 1303 | extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD; | ||
| 1304 | extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC; | ||
| 1305 | extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE; | ||
| 1306 | extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN; | ||
| 1307 | extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM; | ||
| 1308 | extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV; | ||
| 1309 | extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC; | ||
| 1310 | extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER; | ||
| 1311 | extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH; | ||
| 1312 | extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE; | ||
| 1313 | extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME; | ||
| 1314 | extern unsigned IOCTL_SOUND_PCM_READ_BITS; | ||
| 1315 | extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; | ||
| 1316 | extern unsigned IOCTL_SOUND_PCM_READ_FILTER; | ||
| 1317 | extern unsigned IOCTL_SOUND_PCM_READ_RATE; | ||
| 1318 | extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS; | ||
| 1319 | extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; | ||
| 1320 | extern unsigned IOCTL_VT_ACTIVATE; | ||
| 1321 | extern unsigned IOCTL_VT_GETMODE; | ||
| 1322 | extern unsigned IOCTL_VT_OPENQRY; | ||
| 1323 | extern unsigned IOCTL_VT_RELDISP; | ||
| 1324 | extern unsigned IOCTL_VT_SETMODE; | ||
| 1325 | extern unsigned IOCTL_VT_WAITACTIVE; | ||
| 1326 | #endif // SANITIZER_LINUX | ||
| 1327 | |||
| 1328 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 1329 | extern unsigned IOCTL_CYGETDEFTHRESH; | ||
| 1330 | extern unsigned IOCTL_CYGETDEFTIMEOUT; | ||
| 1331 | extern unsigned IOCTL_CYGETMON; | ||
| 1332 | extern unsigned IOCTL_CYGETTHRESH; | ||
| 1333 | extern unsigned IOCTL_CYGETTIMEOUT; | ||
| 1334 | extern unsigned IOCTL_CYSETDEFTHRESH; | ||
| 1335 | extern unsigned IOCTL_CYSETDEFTIMEOUT; | ||
| 1336 | extern unsigned IOCTL_CYSETTHRESH; | ||
| 1337 | extern unsigned IOCTL_CYSETTIMEOUT; | ||
| 1338 | extern unsigned IOCTL_EQL_EMANCIPATE; | ||
| 1339 | extern unsigned IOCTL_EQL_ENSLAVE; | ||
| 1340 | extern unsigned IOCTL_EQL_GETMASTRCFG; | ||
| 1341 | extern unsigned IOCTL_EQL_GETSLAVECFG; | ||
| 1342 | extern unsigned IOCTL_EQL_SETMASTRCFG; | ||
| 1343 | extern unsigned IOCTL_EQL_SETSLAVECFG; | ||
| 1344 | extern unsigned IOCTL_EVIOCGKEYCODE_V2; | ||
| 1345 | extern unsigned IOCTL_EVIOCGPROP; | ||
| 1346 | extern unsigned IOCTL_EVIOCSKEYCODE_V2; | ||
| 1347 | extern unsigned IOCTL_FS_IOC_GETFLAGS; | ||
| 1348 | extern unsigned IOCTL_FS_IOC_GETVERSION; | ||
| 1349 | extern unsigned IOCTL_FS_IOC_SETFLAGS; | ||
| 1350 | extern unsigned IOCTL_FS_IOC_SETVERSION; | ||
| 1351 | extern unsigned IOCTL_GIO_CMAP; | ||
| 1352 | extern unsigned IOCTL_GIO_FONT; | ||
| 1353 | extern unsigned IOCTL_GIO_UNIMAP; | ||
| 1354 | extern unsigned IOCTL_GIO_UNISCRNMAP; | ||
| 1355 | extern unsigned IOCTL_KDADDIO; | ||
| 1356 | extern unsigned IOCTL_KDDELIO; | ||
| 1357 | extern unsigned IOCTL_KDGETKEYCODE; | ||
| 1358 | extern unsigned IOCTL_KDGKBDIACR; | ||
| 1359 | extern unsigned IOCTL_KDGKBENT; | ||
| 1360 | extern unsigned IOCTL_KDGKBLED; | ||
| 1361 | extern unsigned IOCTL_KDGKBMETA; | ||
| 1362 | extern unsigned IOCTL_KDGKBSENT; | ||
| 1363 | extern unsigned IOCTL_KDMAPDISP; | ||
| 1364 | extern unsigned IOCTL_KDSETKEYCODE; | ||
| 1365 | extern unsigned IOCTL_KDSIGACCEPT; | ||
| 1366 | extern unsigned IOCTL_KDSKBDIACR; | ||
| 1367 | extern unsigned IOCTL_KDSKBENT; | ||
| 1368 | extern unsigned IOCTL_KDSKBLED; | ||
| 1369 | extern unsigned IOCTL_KDSKBMETA; | ||
| 1370 | extern unsigned IOCTL_KDSKBSENT; | ||
| 1371 | extern unsigned IOCTL_KDUNMAPDISP; | ||
| 1372 | extern unsigned IOCTL_LPABORT; | ||
| 1373 | extern unsigned IOCTL_LPABORTOPEN; | ||
| 1374 | extern unsigned IOCTL_LPCAREFUL; | ||
| 1375 | extern unsigned IOCTL_LPCHAR; | ||
| 1376 | extern unsigned IOCTL_LPGETIRQ; | ||
| 1377 | extern unsigned IOCTL_LPGETSTATUS; | ||
| 1378 | extern unsigned IOCTL_LPRESET; | ||
| 1379 | extern unsigned IOCTL_LPSETIRQ; | ||
| 1380 | extern unsigned IOCTL_LPTIME; | ||
| 1381 | extern unsigned IOCTL_LPWAIT; | ||
| 1382 | extern unsigned IOCTL_MTIOCGETCONFIG; | ||
| 1383 | extern unsigned IOCTL_MTIOCSETCONFIG; | ||
| 1384 | extern unsigned IOCTL_PIO_CMAP; | ||
| 1385 | extern unsigned IOCTL_PIO_FONT; | ||
| 1386 | extern unsigned IOCTL_PIO_UNIMAP; | ||
| 1387 | extern unsigned IOCTL_PIO_UNIMAPCLR; | ||
| 1388 | extern unsigned IOCTL_PIO_UNISCRNMAP; | ||
| 1389 | extern unsigned IOCTL_SCSI_IOCTL_GET_IDLUN; | ||
| 1390 | extern unsigned IOCTL_SCSI_IOCTL_PROBE_HOST; | ||
| 1391 | extern unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE; | ||
| 1392 | extern unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE; | ||
| 1393 | extern unsigned IOCTL_SIOCAIPXITFCRT; | ||
| 1394 | extern unsigned IOCTL_SIOCAIPXPRISLT; | ||
| 1395 | extern unsigned IOCTL_SIOCAX25ADDUID; | ||
| 1396 | extern unsigned IOCTL_SIOCAX25DELUID; | ||
| 1397 | extern unsigned IOCTL_SIOCAX25GETPARMS; | ||
| 1398 | extern unsigned IOCTL_SIOCAX25GETUID; | ||
| 1399 | extern unsigned IOCTL_SIOCAX25NOUID; | ||
| 1400 | extern unsigned IOCTL_SIOCAX25SETPARMS; | ||
| 1401 | extern unsigned IOCTL_SIOCDEVPLIP; | ||
| 1402 | extern unsigned IOCTL_SIOCIPXCFGDATA; | ||
| 1403 | extern unsigned IOCTL_SIOCNRDECOBS; | ||
| 1404 | extern unsigned IOCTL_SIOCNRGETPARMS; | ||
| 1405 | extern unsigned IOCTL_SIOCNRRTCTL; | ||
| 1406 | extern unsigned IOCTL_SIOCNRSETPARMS; | ||
| 1407 | extern unsigned IOCTL_SNDCTL_DSP_GETISPACE; | ||
| 1408 | extern unsigned IOCTL_SNDCTL_DSP_GETOSPACE; | ||
| 1409 | extern unsigned IOCTL_TIOCGSERIAL; | ||
| 1410 | extern unsigned IOCTL_TIOCSERGETMULTI; | ||
| 1411 | extern unsigned IOCTL_TIOCSERSETMULTI; | ||
| 1412 | extern unsigned IOCTL_TIOCSSERIAL; | ||
| 1413 | extern unsigned IOCTL_GIO_SCRNMAP; | ||
| 1414 | extern unsigned IOCTL_KDDISABIO; | ||
| 1415 | extern unsigned IOCTL_KDENABIO; | ||
| 1416 | extern unsigned IOCTL_KDGETLED; | ||
| 1417 | extern unsigned IOCTL_KDGETMODE; | ||
| 1418 | extern unsigned IOCTL_KDGKBMODE; | ||
| 1419 | extern unsigned IOCTL_KDGKBTYPE; | ||
| 1420 | extern unsigned IOCTL_KDMKTONE; | ||
| 1421 | extern unsigned IOCTL_KDSETLED; | ||
| 1422 | extern unsigned IOCTL_KDSETMODE; | ||
| 1423 | extern unsigned IOCTL_KDSKBMODE; | ||
| 1424 | extern unsigned IOCTL_KIOCSOUND; | ||
| 1425 | extern unsigned IOCTL_PIO_SCRNMAP; | ||
| 1426 | #endif | ||
| 1427 | |||
| 1428 | extern const int si_SEGV_MAPERR; | ||
| 1429 | extern const int si_SEGV_ACCERR; | ||
| 1430 | } // namespace __sanitizer | ||
| 1431 | |||
| 1432 | #define CHECK_TYPE_SIZE(TYPE) \ | ||
| 1433 | COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) | ||
| 1434 | |||
| 1435 | #define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ | ||
| 1436 | COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \ | ||
| 1437 | sizeof(((CLASS *)NULL)->MEMBER)); \ | ||
| 1438 | COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ | ||
| 1439 | offsetof(CLASS, MEMBER)) | ||
| 1440 | |||
| 1441 | // For sigaction, which is a function and struct at the same time, | ||
| 1442 | // and thus requires explicit "struct" in sizeof() expression. | ||
| 1443 | #define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ | ||
| 1444 | COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \ | ||
| 1445 | sizeof(((struct CLASS *)NULL)->MEMBER)); \ | ||
| 1446 | COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ | ||
| 1447 | offsetof(struct CLASS, MEMBER)) | ||
| 1448 | |||
| 1449 | #define SIGACTION_SYMNAME sigaction | ||
| 1450 | |||
| 1451 | #endif // SANITIZER_LINUX || SANITIZER_MAC | ||
| 1452 | |||
| 1453 | #endif | ||
lib/tsan/sanitizer_common/sanitizer_platform_limits_solaris.cpp created+366| ... | @@ -0,0 +1,366 @@ | ||
| 1 | //===-- sanitizer_platform_limits_solaris.cpp -----------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer common code. | ||
| 10 | // | ||
| 11 | // Sizes and layouts of platform-specific Solaris data structures. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_platform.h" | ||
| 15 | |||
| 16 | #if SANITIZER_SOLARIS | ||
| 17 | #include <arpa/inet.h> | ||
| 18 | #include <dirent.h> | ||
| 19 | #include <glob.h> | ||
| 20 | #include <grp.h> | ||
| 21 | #include <ifaddrs.h> | ||
| 22 | #include <limits.h> | ||
| 23 | #include <link.h> | ||
| 24 | #include <net/if.h> | ||
| 25 | #include <net/route.h> | ||
| 26 | #include <netdb.h> | ||
| 27 | #include <netinet/ip_mroute.h> | ||
| 28 | #include <poll.h> | ||
| 29 | #include <pthread.h> | ||
| 30 | #include <pwd.h> | ||
| 31 | #include <rpc/xdr.h> | ||
| 32 | #include <semaphore.h> | ||
| 33 | #include <signal.h> | ||
| 34 | #include <stddef.h> | ||
| 35 | #include <sys/ethernet.h> | ||
| 36 | #include <sys/filio.h> | ||
| 37 | #include <sys/ipc.h> | ||
| 38 | #include <sys/mman.h> | ||
| 39 | #include <sys/mount.h> | ||
| 40 | #include <sys/mtio.h> | ||
| 41 | #include <sys/ptyvar.h> | ||
| 42 | #include <sys/resource.h> | ||
| 43 | #include <sys/shm.h> | ||
| 44 | #include <sys/socket.h> | ||
| 45 | #include <sys/sockio.h> | ||
| 46 | #include <sys/stat.h> | ||
| 47 | #include <sys/statfs.h> | ||
| 48 | #include <sys/statvfs.h> | ||
| 49 | #include <sys/time.h> | ||
| 50 | #include <sys/timeb.h> | ||
| 51 | #include <sys/times.h> | ||
| 52 | #include <sys/types.h> | ||
| 53 | #include <sys/utsname.h> | ||
| 54 | #include <termios.h> | ||
| 55 | #include <time.h> | ||
| 56 | #include <utmp.h> | ||
| 57 | #include <utmpx.h> | ||
| 58 | #include <wchar.h> | ||
| 59 | #include <wordexp.h> | ||
| 60 | |||
| 61 | // Include these after system headers to avoid name clashes and ambiguities. | ||
| 62 | #include "sanitizer_internal_defs.h" | ||
| 63 | #include "sanitizer_platform_limits_solaris.h" | ||
| 64 | |||
| 65 | namespace __sanitizer { | ||
| 66 | unsigned struct_utsname_sz = sizeof(struct utsname); | ||
| 67 | unsigned struct_stat_sz = sizeof(struct stat); | ||
| 68 | unsigned struct_stat64_sz = sizeof(struct stat64); | ||
| 69 | unsigned struct_rusage_sz = sizeof(struct rusage); | ||
| 70 | unsigned struct_tm_sz = sizeof(struct tm); | ||
| 71 | unsigned struct_passwd_sz = sizeof(struct passwd); | ||
| 72 | unsigned struct_group_sz = sizeof(struct group); | ||
| 73 | unsigned siginfo_t_sz = sizeof(siginfo_t); | ||
| 74 | unsigned struct_sigaction_sz = sizeof(struct sigaction); | ||
| 75 | unsigned struct_stack_t_sz = sizeof(stack_t); | ||
| 76 | unsigned struct_itimerval_sz = sizeof(struct itimerval); | ||
| 77 | unsigned pthread_t_sz = sizeof(pthread_t); | ||
| 78 | unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); | ||
| 79 | unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); | ||
| 80 | unsigned pid_t_sz = sizeof(pid_t); | ||
| 81 | unsigned timeval_sz = sizeof(timeval); | ||
| 82 | unsigned uid_t_sz = sizeof(uid_t); | ||
| 83 | unsigned gid_t_sz = sizeof(gid_t); | ||
| 84 | unsigned mbstate_t_sz = sizeof(mbstate_t); | ||
| 85 | unsigned sigset_t_sz = sizeof(sigset_t); | ||
| 86 | unsigned struct_timezone_sz = sizeof(struct timezone); | ||
| 87 | unsigned struct_tms_sz = sizeof(struct tms); | ||
| 88 | unsigned struct_sigevent_sz = sizeof(struct sigevent); | ||
| 89 | unsigned struct_sched_param_sz = sizeof(struct sched_param); | ||
| 90 | unsigned struct_statfs_sz = sizeof(struct statfs); | ||
| 91 | unsigned struct_sockaddr_sz = sizeof(struct sockaddr); | ||
| 92 | unsigned ucontext_t_sz = sizeof(ucontext_t); | ||
| 93 | unsigned struct_timespec_sz = sizeof(struct timespec); | ||
| 94 | #if SANITIZER_SOLARIS32 | ||
| 95 | unsigned struct_statvfs64_sz = sizeof(struct statvfs64); | ||
| 96 | #endif | ||
| 97 | unsigned struct_statvfs_sz = sizeof(struct statvfs); | ||
| 98 | |||
| 99 | const uptr sig_ign = (uptr)SIG_IGN; | ||
| 100 | const uptr sig_dfl = (uptr)SIG_DFL; | ||
| 101 | const uptr sig_err = (uptr)SIG_ERR; | ||
| 102 | const uptr sa_siginfo = (uptr)SA_SIGINFO; | ||
| 103 | |||
| 104 | int shmctl_ipc_stat = (int)IPC_STAT; | ||
| 105 | |||
| 106 | unsigned struct_utmp_sz = sizeof(struct utmp); | ||
| 107 | unsigned struct_utmpx_sz = sizeof(struct utmpx); | ||
| 108 | |||
| 109 | int map_fixed = MAP_FIXED; | ||
| 110 | |||
| 111 | int af_inet = (int)AF_INET; | ||
| 112 | int af_inet6 = (int)AF_INET6; | ||
| 113 | |||
| 114 | uptr __sanitizer_in_addr_sz(int af) { | ||
| 115 | if (af == AF_INET) | ||
| 116 | return sizeof(struct in_addr); | ||
| 117 | else if (af == AF_INET6) | ||
| 118 | return sizeof(struct in6_addr); | ||
| 119 | else | ||
| 120 | return 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr)); | ||
| 124 | |||
| 125 | int glob_nomatch = GLOB_NOMATCH; | ||
| 126 | |||
| 127 | unsigned path_max = PATH_MAX; | ||
| 128 | |||
| 129 | // ioctl arguments | ||
| 130 | unsigned struct_ifreq_sz = sizeof(struct ifreq); | ||
| 131 | unsigned struct_termios_sz = sizeof(struct termios); | ||
| 132 | unsigned struct_winsize_sz = sizeof(struct winsize); | ||
| 133 | |||
| 134 | unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); | ||
| 135 | unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); | ||
| 136 | |||
| 137 | const unsigned IOCTL_NOT_PRESENT = 0; | ||
| 138 | |||
| 139 | unsigned IOCTL_FIOASYNC = FIOASYNC; | ||
| 140 | unsigned IOCTL_FIOCLEX = FIOCLEX; | ||
| 141 | unsigned IOCTL_FIOGETOWN = FIOGETOWN; | ||
| 142 | unsigned IOCTL_FIONBIO = FIONBIO; | ||
| 143 | unsigned IOCTL_FIONCLEX = FIONCLEX; | ||
| 144 | unsigned IOCTL_FIOSETOWN = FIOSETOWN; | ||
| 145 | unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; | ||
| 146 | unsigned IOCTL_SIOCATMARK = SIOCATMARK; | ||
| 147 | unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; | ||
| 148 | unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; | ||
| 149 | unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; | ||
| 150 | unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; | ||
| 151 | unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; | ||
| 152 | unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; | ||
| 153 | unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; | ||
| 154 | unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; | ||
| 155 | unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; | ||
| 156 | unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; | ||
| 157 | unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; | ||
| 158 | unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; | ||
| 159 | unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; | ||
| 160 | unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; | ||
| 161 | unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; | ||
| 162 | unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; | ||
| 163 | unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; | ||
| 164 | unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; | ||
| 165 | unsigned IOCTL_TIOCEXCL = TIOCEXCL; | ||
| 166 | unsigned IOCTL_TIOCGETD = TIOCGETD; | ||
| 167 | unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; | ||
| 168 | unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; | ||
| 169 | unsigned IOCTL_TIOCMBIC = TIOCMBIC; | ||
| 170 | unsigned IOCTL_TIOCMBIS = TIOCMBIS; | ||
| 171 | unsigned IOCTL_TIOCMGET = TIOCMGET; | ||
| 172 | unsigned IOCTL_TIOCMSET = TIOCMSET; | ||
| 173 | unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; | ||
| 174 | unsigned IOCTL_TIOCNXCL = TIOCNXCL; | ||
| 175 | unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; | ||
| 176 | unsigned IOCTL_TIOCPKT = TIOCPKT; | ||
| 177 | unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; | ||
| 178 | unsigned IOCTL_TIOCSETD = TIOCSETD; | ||
| 179 | unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; | ||
| 180 | unsigned IOCTL_TIOCSTI = TIOCSTI; | ||
| 181 | unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; | ||
| 182 | |||
| 183 | unsigned IOCTL_MTIOCGET = MTIOCGET; | ||
| 184 | unsigned IOCTL_MTIOCTOP = MTIOCTOP; | ||
| 185 | |||
| 186 | const int si_SEGV_MAPERR = SEGV_MAPERR; | ||
| 187 | const int si_SEGV_ACCERR = SEGV_ACCERR; | ||
| 188 | } // namespace __sanitizer | ||
| 189 | |||
| 190 | using namespace __sanitizer; | ||
| 191 | |||
| 192 | COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); | ||
| 193 | |||
| 194 | COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); | ||
| 195 | CHECK_TYPE_SIZE(pthread_key_t); | ||
| 196 | |||
| 197 | // There are more undocumented fields in dl_phdr_info that we are not interested | ||
| 198 | // in. | ||
| 199 | COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); | ||
| 200 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); | ||
| 201 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); | ||
| 202 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); | ||
| 203 | CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); | ||
| 204 | |||
| 205 | CHECK_TYPE_SIZE(glob_t); | ||
| 206 | CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); | ||
| 207 | CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); | ||
| 208 | CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); | ||
| 209 | |||
| 210 | CHECK_TYPE_SIZE(addrinfo); | ||
| 211 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); | ||
| 212 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); | ||
| 213 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); | ||
| 214 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); | ||
| 215 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); | ||
| 216 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); | ||
| 217 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); | ||
| 218 | CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); | ||
| 219 | |||
| 220 | CHECK_TYPE_SIZE(hostent); | ||
| 221 | CHECK_SIZE_AND_OFFSET(hostent, h_name); | ||
| 222 | CHECK_SIZE_AND_OFFSET(hostent, h_aliases); | ||
| 223 | CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); | ||
| 224 | CHECK_SIZE_AND_OFFSET(hostent, h_length); | ||
| 225 | CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); | ||
| 226 | |||
| 227 | CHECK_TYPE_SIZE(iovec); | ||
| 228 | CHECK_SIZE_AND_OFFSET(iovec, iov_base); | ||
| 229 | CHECK_SIZE_AND_OFFSET(iovec, iov_len); | ||
| 230 | |||
| 231 | CHECK_TYPE_SIZE(msghdr); | ||
| 232 | CHECK_SIZE_AND_OFFSET(msghdr, msg_name); | ||
| 233 | CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); | ||
| 234 | CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); | ||
| 235 | CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); | ||
| 236 | CHECK_SIZE_AND_OFFSET(msghdr, msg_control); | ||
| 237 | CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); | ||
| 238 | CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); | ||
| 239 | |||
| 240 | CHECK_TYPE_SIZE(cmsghdr); | ||
| 241 | CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); | ||
| 242 | CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); | ||
| 243 | CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); | ||
| 244 | |||
| 245 | COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); | ||
| 246 | CHECK_SIZE_AND_OFFSET(dirent, d_ino); | ||
| 247 | CHECK_SIZE_AND_OFFSET(dirent, d_off); | ||
| 248 | CHECK_SIZE_AND_OFFSET(dirent, d_reclen); | ||
| 249 | |||
| 250 | #if SANITIZER_SOLARIS32 | ||
| 251 | COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64)); | ||
| 252 | CHECK_SIZE_AND_OFFSET(dirent64, d_ino); | ||
| 253 | CHECK_SIZE_AND_OFFSET(dirent64, d_off); | ||
| 254 | CHECK_SIZE_AND_OFFSET(dirent64, d_reclen); | ||
| 255 | #endif | ||
| 256 | |||
| 257 | CHECK_TYPE_SIZE(ifconf); | ||
| 258 | CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); | ||
| 259 | CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); | ||
| 260 | |||
| 261 | CHECK_TYPE_SIZE(pollfd); | ||
| 262 | CHECK_SIZE_AND_OFFSET(pollfd, fd); | ||
| 263 | CHECK_SIZE_AND_OFFSET(pollfd, events); | ||
| 264 | CHECK_SIZE_AND_OFFSET(pollfd, revents); | ||
| 265 | |||
| 266 | CHECK_TYPE_SIZE(nfds_t); | ||
| 267 | |||
| 268 | CHECK_TYPE_SIZE(sigset_t); | ||
| 269 | |||
| 270 | COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); | ||
| 271 | // Can't write checks for sa_handler and sa_sigaction due to them being | ||
| 272 | // preprocessor macros. | ||
| 273 | CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); | ||
| 274 | CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags); | ||
| 275 | |||
| 276 | CHECK_TYPE_SIZE(wordexp_t); | ||
| 277 | CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); | ||
| 278 | CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); | ||
| 279 | CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); | ||
| 280 | |||
| 281 | CHECK_TYPE_SIZE(tm); | ||
| 282 | CHECK_SIZE_AND_OFFSET(tm, tm_sec); | ||
| 283 | CHECK_SIZE_AND_OFFSET(tm, tm_min); | ||
| 284 | CHECK_SIZE_AND_OFFSET(tm, tm_hour); | ||
| 285 | CHECK_SIZE_AND_OFFSET(tm, tm_mday); | ||
| 286 | CHECK_SIZE_AND_OFFSET(tm, tm_mon); | ||
| 287 | CHECK_SIZE_AND_OFFSET(tm, tm_year); | ||
| 288 | CHECK_SIZE_AND_OFFSET(tm, tm_wday); | ||
| 289 | CHECK_SIZE_AND_OFFSET(tm, tm_yday); | ||
| 290 | CHECK_SIZE_AND_OFFSET(tm, tm_isdst); | ||
| 291 | |||
| 292 | CHECK_TYPE_SIZE(ether_addr); | ||
| 293 | |||
| 294 | CHECK_TYPE_SIZE(ipc_perm); | ||
| 295 | CHECK_SIZE_AND_OFFSET(ipc_perm, key); | ||
| 296 | CHECK_SIZE_AND_OFFSET(ipc_perm, seq); | ||
| 297 | CHECK_SIZE_AND_OFFSET(ipc_perm, uid); | ||
| 298 | CHECK_SIZE_AND_OFFSET(ipc_perm, gid); | ||
| 299 | CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); | ||
| 300 | CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); | ||
| 301 | CHECK_SIZE_AND_OFFSET(ipc_perm, mode); | ||
| 302 | |||
| 303 | CHECK_TYPE_SIZE(shmid_ds); | ||
| 304 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); | ||
| 305 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); | ||
| 306 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); | ||
| 307 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); | ||
| 308 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); | ||
| 309 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); | ||
| 310 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); | ||
| 311 | CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); | ||
| 312 | |||
| 313 | CHECK_TYPE_SIZE(clock_t); | ||
| 314 | |||
| 315 | CHECK_TYPE_SIZE(ifaddrs); | ||
| 316 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); | ||
| 317 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); | ||
| 318 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); | ||
| 319 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); | ||
| 320 | // Compare against the union, because we can't reach into the union in a | ||
| 321 | // compliant way. | ||
| 322 | #ifdef ifa_dstaddr | ||
| 323 | #undef ifa_dstaddr | ||
| 324 | #endif | ||
| 325 | COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)nullptr)->ifa_dstaddr) == | ||
| 326 | sizeof(((ifaddrs *)nullptr)->ifa_ifu)); | ||
| 327 | COMPILER_CHECK(offsetof(__sanitizer_ifaddrs, ifa_dstaddr) == | ||
| 328 | offsetof(ifaddrs, ifa_ifu)); | ||
| 329 | CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); | ||
| 330 | |||
| 331 | CHECK_TYPE_SIZE(timeb); | ||
| 332 | CHECK_SIZE_AND_OFFSET(timeb, time); | ||
| 333 | CHECK_SIZE_AND_OFFSET(timeb, millitm); | ||
| 334 | CHECK_SIZE_AND_OFFSET(timeb, timezone); | ||
| 335 | CHECK_SIZE_AND_OFFSET(timeb, dstflag); | ||
| 336 | |||
| 337 | CHECK_TYPE_SIZE(passwd); | ||
| 338 | CHECK_SIZE_AND_OFFSET(passwd, pw_name); | ||
| 339 | CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); | ||
| 340 | CHECK_SIZE_AND_OFFSET(passwd, pw_uid); | ||
| 341 | CHECK_SIZE_AND_OFFSET(passwd, pw_gid); | ||
| 342 | CHECK_SIZE_AND_OFFSET(passwd, pw_dir); | ||
| 343 | CHECK_SIZE_AND_OFFSET(passwd, pw_shell); | ||
| 344 | |||
| 345 | CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); | ||
| 346 | |||
| 347 | CHECK_TYPE_SIZE(group); | ||
| 348 | CHECK_SIZE_AND_OFFSET(group, gr_name); | ||
| 349 | CHECK_SIZE_AND_OFFSET(group, gr_passwd); | ||
| 350 | CHECK_SIZE_AND_OFFSET(group, gr_gid); | ||
| 351 | CHECK_SIZE_AND_OFFSET(group, gr_mem); | ||
| 352 | |||
| 353 | CHECK_TYPE_SIZE(XDR); | ||
| 354 | CHECK_SIZE_AND_OFFSET(XDR, x_op); | ||
| 355 | CHECK_SIZE_AND_OFFSET(XDR, x_ops); | ||
| 356 | CHECK_SIZE_AND_OFFSET(XDR, x_public); | ||
| 357 | CHECK_SIZE_AND_OFFSET(XDR, x_private); | ||
| 358 | CHECK_SIZE_AND_OFFSET(XDR, x_base); | ||
| 359 | CHECK_SIZE_AND_OFFSET(XDR, x_handy); | ||
| 360 | COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE); | ||
| 361 | COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); | ||
| 362 | COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); | ||
| 363 | |||
| 364 | CHECK_TYPE_SIZE(sem_t); | ||
| 365 | |||
| 366 | #endif // SANITIZER_SOLARIS | ||
lib/tsan/sanitizer_common/sanitizer_platform_limits_solaris.h created+495| ... | @@ -0,0 +1,495 @@ | ||
| 1 | //===-- sanitizer_platform_limits_solaris.h -------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of Sanitizer common code. | ||
| 10 | // | ||
| 11 | // Sizes and layouts of platform-specific Solaris data structures. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_PLATFORM_LIMITS_SOLARIS_H | ||
| 15 | #define SANITIZER_PLATFORM_LIMITS_SOLARIS_H | ||
| 16 | |||
| 17 | #if SANITIZER_SOLARIS | ||
| 18 | |||
| 19 | #include "sanitizer_internal_defs.h" | ||
| 20 | #include "sanitizer_platform.h" | ||
| 21 | |||
| 22 | namespace __sanitizer { | ||
| 23 | extern unsigned struct_utsname_sz; | ||
| 24 | extern unsigned struct_stat_sz; | ||
| 25 | extern unsigned struct_stat64_sz; | ||
| 26 | extern unsigned struct_rusage_sz; | ||
| 27 | extern unsigned siginfo_t_sz; | ||
| 28 | extern unsigned struct_itimerval_sz; | ||
| 29 | extern unsigned pthread_t_sz; | ||
| 30 | extern unsigned pthread_mutex_t_sz; | ||
| 31 | extern unsigned pthread_cond_t_sz; | ||
| 32 | extern unsigned pid_t_sz; | ||
| 33 | extern unsigned timeval_sz; | ||
| 34 | extern unsigned uid_t_sz; | ||
| 35 | extern unsigned gid_t_sz; | ||
| 36 | extern unsigned mbstate_t_sz; | ||
| 37 | extern unsigned struct_timezone_sz; | ||
| 38 | extern unsigned struct_tms_sz; | ||
| 39 | extern unsigned struct_itimerspec_sz; | ||
| 40 | extern unsigned struct_sigevent_sz; | ||
| 41 | extern unsigned struct_stack_t_sz; | ||
| 42 | extern unsigned struct_sched_param_sz; | ||
| 43 | extern unsigned struct_statfs64_sz; | ||
| 44 | extern unsigned struct_statfs_sz; | ||
| 45 | extern unsigned struct_sockaddr_sz; | ||
| 46 | extern unsigned ucontext_t_sz; | ||
| 47 | |||
| 48 | extern unsigned struct_timespec_sz; | ||
| 49 | extern unsigned struct_rlimit_sz; | ||
| 50 | extern unsigned struct_utimbuf_sz; | ||
| 51 | |||
| 52 | struct __sanitizer_sem_t { | ||
| 53 | //u64 data[6]; | ||
| 54 | u32 sem_count; | ||
| 55 | u16 sem_type; | ||
| 56 | u16 sem_magic; | ||
| 57 | u64 sem_pad1[3]; | ||
| 58 | u64 sem_pad2[2]; | ||
| 59 | }; | ||
| 60 | |||
| 61 | struct __sanitizer_ipc_perm { | ||
| 62 | unsigned int uid; // uid_t | ||
| 63 | unsigned int gid; // gid_t | ||
| 64 | unsigned int cuid; // uid_t | ||
| 65 | unsigned int cgid; // gid_t | ||
| 66 | unsigned int mode; // mode_t | ||
| 67 | unsigned int seq; // uint_t | ||
| 68 | int key; // key_t | ||
| 69 | #if !defined(_LP64) | ||
| 70 | int pad[4]; | ||
| 71 | #endif | ||
| 72 | }; | ||
| 73 | |||
| 74 | struct __sanitizer_shmid_ds { | ||
| 75 | __sanitizer_ipc_perm shm_perm; | ||
| 76 | unsigned long shm_segsz; // size_t | ||
| 77 | unsigned long shm_flags; // uintptr_t | ||
| 78 | unsigned short shm_lkcnt; // ushort_t | ||
| 79 | int shm_lpid; // pid_t | ||
| 80 | int shm_cpid; // pid_t | ||
| 81 | unsigned long shm_nattch; // shmatt_t | ||
| 82 | unsigned long shm_cnattch; // ulong_t | ||
| 83 | #if defined(_LP64) | ||
| 84 | long shm_atime; // time_t | ||
| 85 | long shm_dtime; | ||
| 86 | long shm_ctime; | ||
| 87 | void *shm_amp; | ||
| 88 | u64 shm_gransize; // uint64_t | ||
| 89 | u64 shm_allocated; // uint64_t | ||
| 90 | u64 shm_pad4[1]; // int64_t | ||
| 91 | #else | ||
| 92 | long shm_atime; // time_t | ||
| 93 | int shm_pad1; // int32_t | ||
| 94 | long shm_dtime; // time_t | ||
| 95 | int shm_pad2; // int32_t | ||
| 96 | long shm_ctime; // time_t | ||
| 97 | void *shm_amp; | ||
| 98 | u64 shm_gransize; // uint64_t | ||
| 99 | u64 shm_allocated; // uint64_t | ||
| 100 | #endif | ||
| 101 | }; | ||
| 102 | |||
| 103 | extern unsigned struct_statvfs_sz; | ||
| 104 | #if SANITIZER_SOLARIS32 | ||
| 105 | extern unsigned struct_statvfs64_sz; | ||
| 106 | #endif | ||
| 107 | |||
| 108 | struct __sanitizer_iovec { | ||
| 109 | void *iov_base; | ||
| 110 | uptr iov_len; | ||
| 111 | }; | ||
| 112 | |||
| 113 | struct __sanitizer_ifaddrs { | ||
| 114 | struct __sanitizer_ifaddrs *ifa_next; | ||
| 115 | char *ifa_name; | ||
| 116 | u64 ifa_flags; // uint64_t | ||
| 117 | void *ifa_addr; // (struct sockaddr *) | ||
| 118 | void *ifa_netmask; // (struct sockaddr *) | ||
| 119 | // This is a union on Linux. | ||
| 120 | # ifdef ifa_dstaddr | ||
| 121 | # undef ifa_dstaddr | ||
| 122 | # endif | ||
| 123 | void *ifa_dstaddr; // (struct sockaddr *) | ||
| 124 | void *ifa_data; | ||
| 125 | }; | ||
| 126 | |||
| 127 | typedef unsigned __sanitizer_pthread_key_t; | ||
| 128 | |||
| 129 | struct __sanitizer_XDR { | ||
| 130 | int x_op; | ||
| 131 | void *x_ops; | ||
| 132 | uptr x_public; | ||
| 133 | uptr x_private; | ||
| 134 | uptr x_base; | ||
| 135 | unsigned x_handy; | ||
| 136 | }; | ||
| 137 | |||
| 138 | const int __sanitizer_XDR_ENCODE = 0; | ||
| 139 | const int __sanitizer_XDR_DECODE = 1; | ||
| 140 | const int __sanitizer_XDR_FREE = 2; | ||
| 141 | |||
| 142 | struct __sanitizer_passwd { | ||
| 143 | char *pw_name; | ||
| 144 | char *pw_passwd; | ||
| 145 | unsigned int pw_uid; // uid_t | ||
| 146 | unsigned int pw_gid; // gid_t | ||
| 147 | char *pw_age; | ||
| 148 | char *pw_comment; | ||
| 149 | char *pw_gecos; | ||
| 150 | char *pw_dir; | ||
| 151 | char *pw_shell; | ||
| 152 | }; | ||
| 153 | |||
| 154 | struct __sanitizer_group { | ||
| 155 | char *gr_name; | ||
| 156 | char *gr_passwd; | ||
| 157 | int gr_gid; | ||
| 158 | char **gr_mem; | ||
| 159 | }; | ||
| 160 | |||
| 161 | typedef long __sanitizer_time_t; | ||
| 162 | |||
| 163 | typedef long __sanitizer_suseconds_t; | ||
| 164 | |||
| 165 | struct __sanitizer_timeval { | ||
| 166 | __sanitizer_time_t tv_sec; | ||
| 167 | __sanitizer_suseconds_t tv_usec; | ||
| 168 | }; | ||
| 169 | |||
| 170 | struct __sanitizer_itimerval { | ||
| 171 | struct __sanitizer_timeval it_interval; | ||
| 172 | struct __sanitizer_timeval it_value; | ||
| 173 | }; | ||
| 174 | |||
| 175 | struct __sanitizer_timeb { | ||
| 176 | __sanitizer_time_t time; | ||
| 177 | unsigned short millitm; | ||
| 178 | short timezone; | ||
| 179 | short dstflag; | ||
| 180 | }; | ||
| 181 | |||
| 182 | struct __sanitizer_ether_addr { | ||
| 183 | u8 octet[6]; | ||
| 184 | }; | ||
| 185 | |||
| 186 | struct __sanitizer_tm { | ||
| 187 | int tm_sec; | ||
| 188 | int tm_min; | ||
| 189 | int tm_hour; | ||
| 190 | int tm_mday; | ||
| 191 | int tm_mon; | ||
| 192 | int tm_year; | ||
| 193 | int tm_wday; | ||
| 194 | int tm_yday; | ||
| 195 | int tm_isdst; | ||
| 196 | }; | ||
| 197 | |||
| 198 | struct __sanitizer_msghdr { | ||
| 199 | void *msg_name; | ||
| 200 | unsigned msg_namelen; | ||
| 201 | struct __sanitizer_iovec *msg_iov; | ||
| 202 | unsigned msg_iovlen; | ||
| 203 | void *msg_control; | ||
| 204 | unsigned msg_controllen; | ||
| 205 | int msg_flags; | ||
| 206 | }; | ||
| 207 | struct __sanitizer_cmsghdr { | ||
| 208 | unsigned cmsg_len; | ||
| 209 | int cmsg_level; | ||
| 210 | int cmsg_type; | ||
| 211 | }; | ||
| 212 | |||
| 213 | #if SANITIZER_SOLARIS && (defined(_LP64) || _FILE_OFFSET_BITS == 64) | ||
| 214 | struct __sanitizer_dirent { | ||
| 215 | unsigned long long d_ino; | ||
| 216 | long long d_off; | ||
| 217 | unsigned short d_reclen; | ||
| 218 | // more fields that we don't care about | ||
| 219 | }; | ||
| 220 | #else | ||
| 221 | struct __sanitizer_dirent { | ||
| 222 | unsigned long d_ino; | ||
| 223 | long d_off; | ||
| 224 | unsigned short d_reclen; | ||
| 225 | // more fields that we don't care about | ||
| 226 | }; | ||
| 227 | #endif | ||
| 228 | |||
| 229 | struct __sanitizer_dirent64 { | ||
| 230 | unsigned long long d_ino; | ||
| 231 | unsigned long long d_off; | ||
| 232 | unsigned short d_reclen; | ||
| 233 | // more fields that we don't care about | ||
| 234 | }; | ||
| 235 | |||
| 236 | typedef long __sanitizer_clock_t; | ||
| 237 | typedef int __sanitizer_clockid_t; | ||
| 238 | |||
| 239 | // This thing depends on the platform. We are only interested in the upper | ||
| 240 | // limit. Verified with a compiler assert in .cpp. | ||
| 241 | union __sanitizer_pthread_attr_t { | ||
| 242 | char size[128]; | ||
| 243 | void *align; | ||
| 244 | }; | ||
| 245 | |||
| 246 | struct __sanitizer_sigset_t { | ||
| 247 | // uint32_t * 4 | ||
| 248 | unsigned int __bits[4]; | ||
| 249 | }; | ||
| 250 | |||
| 251 | struct __sanitizer_siginfo { | ||
| 252 | // The size is determined by looking at sizeof of real siginfo_t on linux. | ||
| 253 | u64 opaque[128 / sizeof(u64)]; | ||
| 254 | }; | ||
| 255 | |||
| 256 | using __sanitizer_sighandler_ptr = void (*)(int sig); | ||
| 257 | using __sanitizer_sigactionhandler_ptr = | ||
| 258 | void (*)(int sig, __sanitizer_siginfo *siginfo, void *uctx); | ||
| 259 | |||
| 260 | struct __sanitizer_sigaction { | ||
| 261 | int sa_flags; | ||
| 262 | union { | ||
| 263 | __sanitizer_sigactionhandler_ptr sigaction; | ||
| 264 | __sanitizer_sighandler_ptr handler; | ||
| 265 | }; | ||
| 266 | __sanitizer_sigset_t sa_mask; | ||
| 267 | #if !defined(_LP64) | ||
| 268 | int sa_resv[2]; | ||
| 269 | #endif | ||
| 270 | }; | ||
| 271 | |||
| 272 | struct __sanitizer_kernel_sigset_t { | ||
| 273 | u8 sig[8]; | ||
| 274 | }; | ||
| 275 | |||
| 276 | struct __sanitizer_kernel_sigaction_t { | ||
| 277 | union { | ||
| 278 | void (*handler)(int signo); | ||
| 279 | void (*sigaction)(int signo, __sanitizer_siginfo *info, void *ctx); | ||
| 280 | }; | ||
| 281 | unsigned long sa_flags; | ||
| 282 | void (*sa_restorer)(void); | ||
| 283 | __sanitizer_kernel_sigset_t sa_mask; | ||
| 284 | }; | ||
| 285 | |||
| 286 | extern const uptr sig_ign; | ||
| 287 | extern const uptr sig_dfl; | ||
| 288 | extern const uptr sig_err; | ||
| 289 | extern const uptr sa_siginfo; | ||
| 290 | |||
| 291 | extern int af_inet; | ||
| 292 | extern int af_inet6; | ||
| 293 | uptr __sanitizer_in_addr_sz(int af); | ||
| 294 | |||
| 295 | struct __sanitizer_dl_phdr_info { | ||
| 296 | uptr dlpi_addr; | ||
| 297 | const char *dlpi_name; | ||
| 298 | const void *dlpi_phdr; | ||
| 299 | short dlpi_phnum; | ||
| 300 | }; | ||
| 301 | |||
| 302 | extern unsigned struct_ElfW_Phdr_sz; | ||
| 303 | |||
| 304 | struct __sanitizer_addrinfo { | ||
| 305 | int ai_flags; | ||
| 306 | int ai_family; | ||
| 307 | int ai_socktype; | ||
| 308 | int ai_protocol; | ||
| 309 | #if defined(__sparcv9) | ||
| 310 | int _ai_pad; | ||
| 311 | #endif | ||
| 312 | unsigned ai_addrlen; | ||
| 313 | char *ai_canonname; | ||
| 314 | void *ai_addr; | ||
| 315 | struct __sanitizer_addrinfo *ai_next; | ||
| 316 | }; | ||
| 317 | |||
| 318 | struct __sanitizer_hostent { | ||
| 319 | char *h_name; | ||
| 320 | char **h_aliases; | ||
| 321 | int h_addrtype; | ||
| 322 | int h_length; | ||
| 323 | char **h_addr_list; | ||
| 324 | }; | ||
| 325 | |||
| 326 | struct __sanitizer_pollfd { | ||
| 327 | int fd; | ||
| 328 | short events; | ||
| 329 | short revents; | ||
| 330 | }; | ||
| 331 | |||
| 332 | typedef unsigned long __sanitizer_nfds_t; | ||
| 333 | |||
| 334 | struct __sanitizer_glob_t { | ||
| 335 | uptr gl_pathc; | ||
| 336 | char **gl_pathv; | ||
| 337 | uptr gl_offs; | ||
| 338 | char **gl_pathp; | ||
| 339 | int gl_pathn; | ||
| 340 | }; | ||
| 341 | |||
| 342 | extern int glob_nomatch; | ||
| 343 | extern int glob_altdirfunc; | ||
| 344 | |||
| 345 | extern unsigned path_max; | ||
| 346 | |||
| 347 | struct __sanitizer_wordexp_t { | ||
| 348 | uptr we_wordc; | ||
| 349 | char **we_wordv; | ||
| 350 | uptr we_offs; | ||
| 351 | char **we_wordp; | ||
| 352 | int we_wordn; | ||
| 353 | }; | ||
| 354 | |||
| 355 | typedef void __sanitizer_FILE; | ||
| 356 | #define SANITIZER_HAS_STRUCT_FILE 0 | ||
| 357 | |||
| 358 | // This simplifies generic code | ||
| 359 | #define struct_shminfo_sz -1 | ||
| 360 | #define struct_shm_info_sz -1 | ||
| 361 | #define shmctl_shm_stat -1 | ||
| 362 | #define shmctl_ipc_info -1 | ||
| 363 | #define shmctl_shm_info -1 | ||
| 364 | |||
| 365 | extern int shmctl_ipc_stat; | ||
| 366 | |||
| 367 | extern unsigned struct_utmp_sz; | ||
| 368 | extern unsigned struct_utmpx_sz; | ||
| 369 | |||
| 370 | extern int map_fixed; | ||
| 371 | |||
| 372 | // ioctl arguments | ||
| 373 | struct __sanitizer_ifconf { | ||
| 374 | int ifc_len; | ||
| 375 | union { | ||
| 376 | void *ifcu_req; | ||
| 377 | } ifc_ifcu; | ||
| 378 | }; | ||
| 379 | |||
| 380 | // <sys/ioccom.h> | ||
| 381 | #define IOC_NRBITS 8 | ||
| 382 | #define IOC_TYPEBITS 8 | ||
| 383 | #define IOC_SIZEBITS 12 | ||
| 384 | #define IOC_DIRBITS 4 | ||
| 385 | #undef IOC_NONE | ||
| 386 | #define IOC_NONE 2U // IOC_VOID | ||
| 387 | #define IOC_READ 4U // IOC_OUT | ||
| 388 | #define IOC_WRITE 8U // IOC_IN | ||
| 389 | |||
| 390 | #define IOC_NRMASK ((1 << IOC_NRBITS) - 1) | ||
| 391 | #define IOC_TYPEMASK ((1 << IOC_TYPEBITS) - 1) | ||
| 392 | #define IOC_SIZEMASK ((1 << IOC_SIZEBITS) - 1) | ||
| 393 | #define IOC_DIRMASK ((1 << IOC_DIRBITS) - 1) | ||
| 394 | #define IOC_NRSHIFT 0 | ||
| 395 | #define IOC_TYPESHIFT (IOC_NRSHIFT + IOC_NRBITS) | ||
| 396 | #define IOC_SIZESHIFT (IOC_TYPESHIFT + IOC_TYPEBITS) | ||
| 397 | #define IOC_DIRSHIFT (IOC_SIZESHIFT + IOC_SIZEBITS) | ||
| 398 | |||
| 399 | #define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK) | ||
| 400 | #define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK) | ||
| 401 | #define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK) | ||
| 402 | |||
| 403 | #if defined(__sparc__) | ||
| 404 | // In sparc the 14 bits SIZE field overlaps with the | ||
| 405 | // least significant bit of DIR, so either IOC_READ or | ||
| 406 | // IOC_WRITE shall be 1 in order to get a non-zero SIZE. | ||
| 407 | #define IOC_SIZE(nr) \ | ||
| 408 | ((((((nr) >> 29) & 0x7) & (4U | 2U)) == 0) ? 0 : (((nr) >> 16) & 0x3fff)) | ||
| 409 | #else | ||
| 410 | #define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) | ||
| 411 | #endif | ||
| 412 | |||
| 413 | extern unsigned struct_ifreq_sz; | ||
| 414 | extern unsigned struct_termios_sz; | ||
| 415 | extern unsigned struct_winsize_sz; | ||
| 416 | |||
| 417 | extern unsigned struct_sioc_sg_req_sz; | ||
| 418 | extern unsigned struct_sioc_vif_req_sz; | ||
| 419 | |||
| 420 | // ioctl request identifiers | ||
| 421 | |||
| 422 | // A special value to mark ioctls that are not present on the target platform, | ||
| 423 | // when it can not be determined without including any system headers. | ||
| 424 | extern const unsigned IOCTL_NOT_PRESENT; | ||
| 425 | |||
| 426 | extern unsigned IOCTL_FIOASYNC; | ||
| 427 | extern unsigned IOCTL_FIOCLEX; | ||
| 428 | extern unsigned IOCTL_FIOGETOWN; | ||
| 429 | extern unsigned IOCTL_FIONBIO; | ||
| 430 | extern unsigned IOCTL_FIONCLEX; | ||
| 431 | extern unsigned IOCTL_FIOSETOWN; | ||
| 432 | extern unsigned IOCTL_SIOCADDMULTI; | ||
| 433 | extern unsigned IOCTL_SIOCATMARK; | ||
| 434 | extern unsigned IOCTL_SIOCDELMULTI; | ||
| 435 | extern unsigned IOCTL_SIOCGIFADDR; | ||
| 436 | extern unsigned IOCTL_SIOCGIFBRDADDR; | ||
| 437 | extern unsigned IOCTL_SIOCGIFCONF; | ||
| 438 | extern unsigned IOCTL_SIOCGIFDSTADDR; | ||
| 439 | extern unsigned IOCTL_SIOCGIFFLAGS; | ||
| 440 | extern unsigned IOCTL_SIOCGIFMETRIC; | ||
| 441 | extern unsigned IOCTL_SIOCGIFMTU; | ||
| 442 | extern unsigned IOCTL_SIOCGIFNETMASK; | ||
| 443 | extern unsigned IOCTL_SIOCGPGRP; | ||
| 444 | extern unsigned IOCTL_SIOCSIFADDR; | ||
| 445 | extern unsigned IOCTL_SIOCSIFBRDADDR; | ||
| 446 | extern unsigned IOCTL_SIOCSIFDSTADDR; | ||
| 447 | extern unsigned IOCTL_SIOCSIFFLAGS; | ||
| 448 | extern unsigned IOCTL_SIOCSIFMETRIC; | ||
| 449 | extern unsigned IOCTL_SIOCSIFMTU; | ||
| 450 | extern unsigned IOCTL_SIOCSIFNETMASK; | ||
| 451 | extern unsigned IOCTL_SIOCSPGRP; | ||
| 452 | extern unsigned IOCTL_TIOCEXCL; | ||
| 453 | extern unsigned IOCTL_TIOCGETD; | ||
| 454 | extern unsigned IOCTL_TIOCGPGRP; | ||
| 455 | extern unsigned IOCTL_TIOCGWINSZ; | ||
| 456 | extern unsigned IOCTL_TIOCMBIC; | ||
| 457 | extern unsigned IOCTL_TIOCMBIS; | ||
| 458 | extern unsigned IOCTL_TIOCMGET; | ||
| 459 | extern unsigned IOCTL_TIOCMSET; | ||
| 460 | extern unsigned IOCTL_TIOCNOTTY; | ||
| 461 | extern unsigned IOCTL_TIOCNXCL; | ||
| 462 | extern unsigned IOCTL_TIOCOUTQ; | ||
| 463 | extern unsigned IOCTL_TIOCPKT; | ||
| 464 | extern unsigned IOCTL_TIOCSCTTY; | ||
| 465 | extern unsigned IOCTL_TIOCSETD; | ||
| 466 | extern unsigned IOCTL_TIOCSPGRP; | ||
| 467 | extern unsigned IOCTL_TIOCSTI; | ||
| 468 | extern unsigned IOCTL_TIOCSWINSZ; | ||
| 469 | extern unsigned IOCTL_MTIOCGET; | ||
| 470 | extern unsigned IOCTL_MTIOCTOP; | ||
| 471 | |||
| 472 | extern const int si_SEGV_MAPERR; | ||
| 473 | extern const int si_SEGV_ACCERR; | ||
| 474 | } // namespace __sanitizer | ||
| 475 | |||
| 476 | #define CHECK_TYPE_SIZE(TYPE) \ | ||
| 477 | COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) | ||
| 478 | |||
| 479 | #define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ | ||
| 480 | COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *) NULL)->MEMBER) == \ | ||
| 481 | sizeof(((CLASS *) NULL)->MEMBER)); \ | ||
| 482 | COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ | ||
| 483 | offsetof(CLASS, MEMBER)) | ||
| 484 | |||
| 485 | // For sigaction, which is a function and struct at the same time, | ||
| 486 | // and thus requires explicit "struct" in sizeof() expression. | ||
| 487 | #define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ | ||
| 488 | COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *) NULL)->MEMBER) == \ | ||
| 489 | sizeof(((struct CLASS *) NULL)->MEMBER)); \ | ||
| 490 | COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ | ||
| 491 | offsetof(struct CLASS, MEMBER)) | ||
| 492 | |||
| 493 | #endif // SANITIZER_SOLARIS | ||
| 494 | |||
| 495 | #endif | ||
lib/tsan/sanitizer_common/sanitizer_posix.cpp created+398| ... | @@ -0,0 +1,398 @@ | ||
| 1 | //===-- sanitizer_posix.cpp -----------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer | ||
| 10 | // run-time libraries and implements POSIX-specific functions from | ||
| 11 | // sanitizer_posix.h. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_platform.h" | ||
| 15 | |||
| 16 | #if SANITIZER_POSIX | ||
| 17 | |||
| 18 | #include "sanitizer_common.h" | ||
| 19 | #include "sanitizer_file.h" | ||
| 20 | #include "sanitizer_flags.h" | ||
| 21 | #include "sanitizer_libc.h" | ||
| 22 | #include "sanitizer_posix.h" | ||
| 23 | #include "sanitizer_procmaps.h" | ||
| 24 | |||
| 25 | #include <errno.h> | ||
| 26 | #include <fcntl.h> | ||
| 27 | #include <signal.h> | ||
| 28 | #include <sys/mman.h> | ||
| 29 | |||
| 30 | #if SANITIZER_FREEBSD | ||
| 31 | // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before | ||
| 32 | // that, it was never implemented. So just define it to zero. | ||
| 33 | #undef MAP_NORESERVE | ||
| 34 | #define MAP_NORESERVE 0 | ||
| 35 | #endif | ||
| 36 | |||
| 37 | namespace __sanitizer { | ||
| 38 | |||
| 39 | // ------------- sanitizer_common.h | ||
| 40 | uptr GetMmapGranularity() { | ||
| 41 | return GetPageSize(); | ||
| 42 | } | ||
| 43 | |||
| 44 | void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { | ||
| 45 | size = RoundUpTo(size, GetPageSizeCached()); | ||
| 46 | uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE, | ||
| 47 | MAP_PRIVATE | MAP_ANON, mem_type); | ||
| 48 | int reserrno; | ||
| 49 | if (UNLIKELY(internal_iserror(res, &reserrno))) | ||
| 50 | ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report); | ||
| 51 | IncreaseTotalMmap(size); | ||
| 52 | return (void *)res; | ||
| 53 | } | ||
| 54 | |||
| 55 | void UnmapOrDie(void *addr, uptr size) { | ||
| 56 | if (!addr || !size) return; | ||
| 57 | uptr res = internal_munmap(addr, size); | ||
| 58 | if (UNLIKELY(internal_iserror(res))) { | ||
| 59 | Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", | ||
| 60 | SanitizerToolName, size, size, addr); | ||
| 61 | CHECK("unable to unmap" && 0); | ||
| 62 | } | ||
| 63 | DecreaseTotalMmap(size); | ||
| 64 | } | ||
| 65 | |||
| 66 | void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { | ||
| 67 | size = RoundUpTo(size, GetPageSizeCached()); | ||
| 68 | uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE, | ||
| 69 | MAP_PRIVATE | MAP_ANON, mem_type); | ||
| 70 | int reserrno; | ||
| 71 | if (UNLIKELY(internal_iserror(res, &reserrno))) { | ||
| 72 | if (reserrno == ENOMEM) | ||
| 73 | return nullptr; | ||
| 74 | ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); | ||
| 75 | } | ||
| 76 | IncreaseTotalMmap(size); | ||
| 77 | return (void *)res; | ||
| 78 | } | ||
| 79 | |||
| 80 | // We want to map a chunk of address space aligned to 'alignment'. | ||
| 81 | // We do it by mapping a bit more and then unmapping redundant pieces. | ||
| 82 | // We probably can do it with fewer syscalls in some OS-dependent way. | ||
| 83 | void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, | ||
| 84 | const char *mem_type) { | ||
| 85 | CHECK(IsPowerOfTwo(size)); | ||
| 86 | CHECK(IsPowerOfTwo(alignment)); | ||
| 87 | uptr map_size = size + alignment; | ||
| 88 | uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type); | ||
| 89 | if (UNLIKELY(!map_res)) | ||
| 90 | return nullptr; | ||
| 91 | uptr map_end = map_res + map_size; | ||
| 92 | uptr res = map_res; | ||
| 93 | if (!IsAligned(res, alignment)) { | ||
| 94 | res = (map_res + alignment - 1) & ~(alignment - 1); | ||
| 95 | UnmapOrDie((void*)map_res, res - map_res); | ||
| 96 | } | ||
| 97 | uptr end = res + size; | ||
| 98 | if (end != map_end) | ||
| 99 | UnmapOrDie((void*)end, map_end - end); | ||
| 100 | return (void*)res; | ||
| 101 | } | ||
| 102 | |||
| 103 | void *MmapNoReserveOrDie(uptr size, const char *mem_type) { | ||
| 104 | size = RoundUpTo(size, GetPageSizeCached()); | ||
| 105 | uptr p = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE, | ||
| 106 | MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, mem_type); | ||
| 107 | int reserrno; | ||
| 108 | if (UNLIKELY(internal_iserror(p, &reserrno))) | ||
| 109 | ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno); | ||
| 110 | IncreaseTotalMmap(size); | ||
| 111 | return (void *)p; | ||
| 112 | } | ||
| 113 | |||
| 114 | static void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem, | ||
| 115 | const char *name) { | ||
| 116 | size = RoundUpTo(size, GetPageSizeCached()); | ||
| 117 | fixed_addr = RoundDownTo(fixed_addr, GetPageSizeCached()); | ||
| 118 | uptr p = MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE, | ||
| 119 | MAP_PRIVATE | MAP_ANON | MAP_FIXED, name); | ||
| 120 | int reserrno; | ||
| 121 | if (UNLIKELY(internal_iserror(p, &reserrno))) { | ||
| 122 | if (tolerate_enomem && reserrno == ENOMEM) | ||
| 123 | return nullptr; | ||
| 124 | char mem_type[40]; | ||
| 125 | internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", | ||
| 126 | fixed_addr); | ||
| 127 | ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); | ||
| 128 | } | ||
| 129 | IncreaseTotalMmap(size); | ||
| 130 | return (void *)p; | ||
| 131 | } | ||
| 132 | |||
| 133 | void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) { | ||
| 134 | return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/, name); | ||
| 135 | } | ||
| 136 | |||
| 137 | void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) { | ||
| 138 | return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/, name); | ||
| 139 | } | ||
| 140 | |||
| 141 | bool MprotectNoAccess(uptr addr, uptr size) { | ||
| 142 | return 0 == internal_mprotect((void*)addr, size, PROT_NONE); | ||
| 143 | } | ||
| 144 | |||
| 145 | bool MprotectReadOnly(uptr addr, uptr size) { | ||
| 146 | return 0 == internal_mprotect((void *)addr, size, PROT_READ); | ||
| 147 | } | ||
| 148 | |||
| 149 | #if !SANITIZER_MAC | ||
| 150 | void MprotectMallocZones(void *addr, int prot) {} | ||
| 151 | #endif | ||
| 152 | |||
| 153 | fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) { | ||
| 154 | if (ShouldMockFailureToOpen(filename)) | ||
| 155 | return kInvalidFd; | ||
| 156 | int flags; | ||
| 157 | switch (mode) { | ||
| 158 | case RdOnly: flags = O_RDONLY; break; | ||
| 159 | case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break; | ||
| 160 | case RdWr: flags = O_RDWR | O_CREAT; break; | ||
| 161 | } | ||
| 162 | fd_t res = internal_open(filename, flags, 0660); | ||
| 163 | if (internal_iserror(res, errno_p)) | ||
| 164 | return kInvalidFd; | ||
| 165 | return ReserveStandardFds(res); | ||
| 166 | } | ||
| 167 | |||
| 168 | void CloseFile(fd_t fd) { | ||
| 169 | internal_close(fd); | ||
| 170 | } | ||
| 171 | |||
| 172 | bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, | ||
| 173 | error_t *error_p) { | ||
| 174 | uptr res = internal_read(fd, buff, buff_size); | ||
| 175 | if (internal_iserror(res, error_p)) | ||
| 176 | return false; | ||
| 177 | if (bytes_read) | ||
| 178 | *bytes_read = res; | ||
| 179 | return true; | ||
| 180 | } | ||
| 181 | |||
| 182 | bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, | ||
| 183 | error_t *error_p) { | ||
| 184 | uptr res = internal_write(fd, buff, buff_size); | ||
| 185 | if (internal_iserror(res, error_p)) | ||
| 186 | return false; | ||
| 187 | if (bytes_written) | ||
| 188 | *bytes_written = res; | ||
| 189 | return true; | ||
| 190 | } | ||
| 191 | |||
| 192 | void *MapFileToMemory(const char *file_name, uptr *buff_size) { | ||
| 193 | fd_t fd = OpenFile(file_name, RdOnly); | ||
| 194 | CHECK(fd != kInvalidFd); | ||
| 195 | uptr fsize = internal_filesize(fd); | ||
| 196 | CHECK_NE(fsize, (uptr)-1); | ||
| 197 | CHECK_GT(fsize, 0); | ||
| 198 | *buff_size = RoundUpTo(fsize, GetPageSizeCached()); | ||
| 199 | uptr map = internal_mmap(nullptr, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0); | ||
| 200 | return internal_iserror(map) ? nullptr : (void *)map; | ||
| 201 | } | ||
| 202 | |||
| 203 | void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { | ||
| 204 | uptr flags = MAP_SHARED; | ||
| 205 | if (addr) flags |= MAP_FIXED; | ||
| 206 | uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset); | ||
| 207 | int mmap_errno = 0; | ||
| 208 | if (internal_iserror(p, &mmap_errno)) { | ||
| 209 | Printf("could not map writable file (%d, %lld, %zu): %zd, errno: %d\n", | ||
| 210 | fd, (long long)offset, size, p, mmap_errno); | ||
| 211 | return nullptr; | ||
| 212 | } | ||
| 213 | return (void *)p; | ||
| 214 | } | ||
| 215 | |||
| 216 | static inline bool IntervalsAreSeparate(uptr start1, uptr end1, | ||
| 217 | uptr start2, uptr end2) { | ||
| 218 | CHECK(start1 <= end1); | ||
| 219 | CHECK(start2 <= end2); | ||
| 220 | return (end1 < start2) || (end2 < start1); | ||
| 221 | } | ||
| 222 | |||
| 223 | // FIXME: this is thread-unsafe, but should not cause problems most of the time. | ||
| 224 | // When the shadow is mapped only a single thread usually exists (plus maybe | ||
| 225 | // several worker threads on Mac, which aren't expected to map big chunks of | ||
| 226 | // memory). | ||
| 227 | bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { | ||
| 228 | MemoryMappingLayout proc_maps(/*cache_enabled*/true); | ||
| 229 | if (proc_maps.Error()) | ||
| 230 | return true; // and hope for the best | ||
| 231 | MemoryMappedSegment segment; | ||
| 232 | while (proc_maps.Next(&segment)) { | ||
| 233 | if (segment.start == segment.end) continue; // Empty range. | ||
| 234 | CHECK_NE(0, segment.end); | ||
| 235 | if (!IntervalsAreSeparate(segment.start, segment.end - 1, range_start, | ||
| 236 | range_end)) | ||
| 237 | return false; | ||
| 238 | } | ||
| 239 | return true; | ||
| 240 | } | ||
| 241 | |||
| 242 | void DumpProcessMap() { | ||
| 243 | MemoryMappingLayout proc_maps(/*cache_enabled*/true); | ||
| 244 | const sptr kBufSize = 4095; | ||
| 245 | char *filename = (char*)MmapOrDie(kBufSize, __func__); | ||
| 246 | MemoryMappedSegment segment(filename, kBufSize); | ||
| 247 | Report("Process memory map follows:\n"); | ||
| 248 | while (proc_maps.Next(&segment)) { | ||
| 249 | Printf("\t%p-%p\t%s\n", (void *)segment.start, (void *)segment.end, | ||
| 250 | segment.filename); | ||
| 251 | } | ||
| 252 | Report("End of process memory map.\n"); | ||
| 253 | UnmapOrDie(filename, kBufSize); | ||
| 254 | } | ||
| 255 | |||
| 256 | const char *GetPwd() { | ||
| 257 | return GetEnv("PWD"); | ||
| 258 | } | ||
| 259 | |||
| 260 | bool IsPathSeparator(const char c) { | ||
| 261 | return c == '/'; | ||
| 262 | } | ||
| 263 | |||
| 264 | bool IsAbsolutePath(const char *path) { | ||
| 265 | return path != nullptr && IsPathSeparator(path[0]); | ||
| 266 | } | ||
| 267 | |||
| 268 | void ReportFile::Write(const char *buffer, uptr length) { | ||
| 269 | SpinMutexLock l(mu); | ||
| 270 | ReopenIfNecessary(); | ||
| 271 | internal_write(fd, buffer, length); | ||
| 272 | } | ||
| 273 | |||
| 274 | bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { | ||
| 275 | MemoryMappingLayout proc_maps(/*cache_enabled*/false); | ||
| 276 | InternalScopedString buff(kMaxPathLength); | ||
| 277 | MemoryMappedSegment segment(buff.data(), kMaxPathLength); | ||
| 278 | while (proc_maps.Next(&segment)) { | ||
| 279 | if (segment.IsExecutable() && | ||
| 280 | internal_strcmp(module, segment.filename) == 0) { | ||
| 281 | *start = segment.start; | ||
| 282 | *end = segment.end; | ||
| 283 | return true; | ||
| 284 | } | ||
| 285 | } | ||
| 286 | return false; | ||
| 287 | } | ||
| 288 | |||
| 289 | uptr SignalContext::GetAddress() const { | ||
| 290 | auto si = static_cast<const siginfo_t *>(siginfo); | ||
| 291 | return (uptr)si->si_addr; | ||
| 292 | } | ||
| 293 | |||
| 294 | bool SignalContext::IsMemoryAccess() const { | ||
| 295 | auto si = static_cast<const siginfo_t *>(siginfo); | ||
| 296 | return si->si_signo == SIGSEGV; | ||
| 297 | } | ||
| 298 | |||
| 299 | int SignalContext::GetType() const { | ||
| 300 | return static_cast<const siginfo_t *>(siginfo)->si_signo; | ||
| 301 | } | ||
| 302 | |||
| 303 | const char *SignalContext::Describe() const { | ||
| 304 | switch (GetType()) { | ||
| 305 | case SIGFPE: | ||
| 306 | return "FPE"; | ||
| 307 | case SIGILL: | ||
| 308 | return "ILL"; | ||
| 309 | case SIGABRT: | ||
| 310 | return "ABRT"; | ||
| 311 | case SIGSEGV: | ||
| 312 | return "SEGV"; | ||
| 313 | case SIGBUS: | ||
| 314 | return "BUS"; | ||
| 315 | case SIGTRAP: | ||
| 316 | return "TRAP"; | ||
| 317 | } | ||
| 318 | return "UNKNOWN SIGNAL"; | ||
| 319 | } | ||
| 320 | |||
| 321 | fd_t ReserveStandardFds(fd_t fd) { | ||
| 322 | CHECK_GE(fd, 0); | ||
| 323 | if (fd > 2) | ||
| 324 | return fd; | ||
| 325 | bool used[3]; | ||
| 326 | internal_memset(used, 0, sizeof(used)); | ||
| 327 | while (fd <= 2) { | ||
| 328 | used[fd] = true; | ||
| 329 | fd = internal_dup(fd); | ||
| 330 | } | ||
| 331 | for (int i = 0; i <= 2; ++i) | ||
| 332 | if (used[i]) | ||
| 333 | internal_close(i); | ||
| 334 | return fd; | ||
| 335 | } | ||
| 336 | |||
| 337 | bool ShouldMockFailureToOpen(const char *path) { | ||
| 338 | return common_flags()->test_only_emulate_no_memorymap && | ||
| 339 | internal_strncmp(path, "/proc/", 6) == 0; | ||
| 340 | } | ||
| 341 | |||
| 342 | #if SANITIZER_LINUX && !SANITIZER_ANDROID && !SANITIZER_GO | ||
| 343 | int GetNamedMappingFd(const char *name, uptr size, int *flags) { | ||
| 344 | if (!common_flags()->decorate_proc_maps || !name) | ||
| 345 | return -1; | ||
| 346 | char shmname[200]; | ||
| 347 | CHECK(internal_strlen(name) < sizeof(shmname) - 10); | ||
| 348 | internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]", | ||
| 349 | internal_getpid(), name); | ||
| 350 | int o_cloexec = 0; | ||
| 351 | #if defined(O_CLOEXEC) | ||
| 352 | o_cloexec = O_CLOEXEC; | ||
| 353 | #endif | ||
| 354 | int fd = ReserveStandardFds( | ||
| 355 | internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | o_cloexec, S_IRWXU)); | ||
| 356 | CHECK_GE(fd, 0); | ||
| 357 | if (!o_cloexec) { | ||
| 358 | int res = fcntl(fd, F_SETFD, FD_CLOEXEC); | ||
| 359 | CHECK_EQ(0, res); | ||
| 360 | } | ||
| 361 | int res = internal_ftruncate(fd, size); | ||
| 362 | CHECK_EQ(0, res); | ||
| 363 | res = internal_unlink(shmname); | ||
| 364 | CHECK_EQ(0, res); | ||
| 365 | *flags &= ~(MAP_ANON | MAP_ANONYMOUS); | ||
| 366 | return fd; | ||
| 367 | } | ||
| 368 | #else | ||
| 369 | int GetNamedMappingFd(const char *name, uptr size, int *flags) { | ||
| 370 | return -1; | ||
| 371 | } | ||
| 372 | #endif | ||
| 373 | |||
| 374 | #if SANITIZER_ANDROID | ||
| 375 | #define PR_SET_VMA 0x53564d41 | ||
| 376 | #define PR_SET_VMA_ANON_NAME 0 | ||
| 377 | void DecorateMapping(uptr addr, uptr size, const char *name) { | ||
| 378 | if (!common_flags()->decorate_proc_maps || !name) | ||
| 379 | return; | ||
| 380 | internal_prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, (uptr)name); | ||
| 381 | } | ||
| 382 | #else | ||
| 383 | void DecorateMapping(uptr addr, uptr size, const char *name) { | ||
| 384 | } | ||
| 385 | #endif | ||
| 386 | |||
| 387 | uptr MmapNamed(void *addr, uptr length, int prot, int flags, const char *name) { | ||
| 388 | int fd = GetNamedMappingFd(name, length, &flags); | ||
| 389 | uptr res = internal_mmap(addr, length, prot, flags, fd, 0); | ||
| 390 | if (!internal_iserror(res)) | ||
| 391 | DecorateMapping(res, length, name); | ||
| 392 | return res; | ||
| 393 | } | ||
| 394 | |||
| 395 | |||
| 396 | } // namespace __sanitizer | ||
| 397 | |||
| 398 | #endif // SANITIZER_POSIX | ||
lib/tsan/sanitizer_common/sanitizer_posix.h created+125| ... | @@ -0,0 +1,125 @@ | ||
| 1 | //===-- sanitizer_posix.h -------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer | ||
| 10 | // run-time libraries and declares some useful POSIX-specific functions. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_POSIX_H | ||
| 13 | #define SANITIZER_POSIX_H | ||
| 14 | |||
| 15 | // ----------- ATTENTION ------------- | ||
| 16 | // This header should NOT include any other headers from sanitizer runtime. | ||
| 17 | #include "sanitizer_internal_defs.h" | ||
| 18 | #include "sanitizer_platform_limits_freebsd.h" | ||
| 19 | #include "sanitizer_platform_limits_netbsd.h" | ||
| 20 | #include "sanitizer_platform_limits_openbsd.h" | ||
| 21 | #include "sanitizer_platform_limits_posix.h" | ||
| 22 | #include "sanitizer_platform_limits_solaris.h" | ||
| 23 | |||
| 24 | #if !SANITIZER_POSIX | ||
| 25 | // Make it hard to accidentally use any of functions declared in this file: | ||
| 26 | #error This file should only be included on POSIX | ||
| 27 | #endif | ||
| 28 | |||
| 29 | namespace __sanitizer { | ||
| 30 | |||
| 31 | // I/O | ||
| 32 | // Don't use directly, use __sanitizer::OpenFile() instead. | ||
| 33 | uptr internal_open(const char *filename, int flags); | ||
| 34 | uptr internal_open(const char *filename, int flags, u32 mode); | ||
| 35 | uptr internal_close(fd_t fd); | ||
| 36 | |||
| 37 | uptr internal_read(fd_t fd, void *buf, uptr count); | ||
| 38 | uptr internal_write(fd_t fd, const void *buf, uptr count); | ||
| 39 | |||
| 40 | // Memory | ||
| 41 | uptr internal_mmap(void *addr, uptr length, int prot, int flags, | ||
| 42 | int fd, u64 offset); | ||
| 43 | uptr internal_munmap(void *addr, uptr length); | ||
| 44 | int internal_mprotect(void *addr, uptr length, int prot); | ||
| 45 | |||
| 46 | // OS | ||
| 47 | uptr internal_filesize(fd_t fd); // -1 on error. | ||
| 48 | uptr internal_stat(const char *path, void *buf); | ||
| 49 | uptr internal_lstat(const char *path, void *buf); | ||
| 50 | uptr internal_fstat(fd_t fd, void *buf); | ||
| 51 | uptr internal_dup(int oldfd); | ||
| 52 | uptr internal_dup2(int oldfd, int newfd); | ||
| 53 | uptr internal_readlink(const char *path, char *buf, uptr bufsize); | ||
| 54 | uptr internal_unlink(const char *path); | ||
| 55 | uptr internal_rename(const char *oldpath, const char *newpath); | ||
| 56 | uptr internal_lseek(fd_t fd, OFF_T offset, int whence); | ||
| 57 | |||
| 58 | #if SANITIZER_NETBSD | ||
| 59 | uptr internal_ptrace(int request, int pid, void *addr, int data); | ||
| 60 | #else | ||
| 61 | uptr internal_ptrace(int request, int pid, void *addr, void *data); | ||
| 62 | #endif | ||
| 63 | uptr internal_waitpid(int pid, int *status, int options); | ||
| 64 | |||
| 65 | int internal_fork(); | ||
| 66 | fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid); | ||
| 67 | |||
| 68 | int internal_sysctl(const int *name, unsigned int namelen, void *oldp, | ||
| 69 | uptr *oldlenp, const void *newp, uptr newlen); | ||
| 70 | int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, | ||
| 71 | const void *newp, uptr newlen); | ||
| 72 | |||
| 73 | // These functions call appropriate pthread_ functions directly, bypassing | ||
| 74 | // the interceptor. They are weak and may not be present in some tools. | ||
| 75 | SANITIZER_WEAK_ATTRIBUTE | ||
| 76 | int real_pthread_create(void *th, void *attr, void *(*callback)(void *), | ||
| 77 | void *param); | ||
| 78 | SANITIZER_WEAK_ATTRIBUTE | ||
| 79 | int real_pthread_join(void *th, void **ret); | ||
| 80 | |||
| 81 | #define DEFINE_REAL_PTHREAD_FUNCTIONS \ | ||
| 82 | namespace __sanitizer { \ | ||
| 83 | int real_pthread_create(void *th, void *attr, void *(*callback)(void *), \ | ||
| 84 | void *param) { \ | ||
| 85 | return REAL(pthread_create)(th, attr, callback, param); \ | ||
| 86 | } \ | ||
| 87 | int real_pthread_join(void *th, void **ret) { \ | ||
| 88 | return REAL(pthread_join(th, ret)); \ | ||
| 89 | } \ | ||
| 90 | } // namespace __sanitizer | ||
| 91 | |||
| 92 | int my_pthread_attr_getstack(void *attr, void **addr, uptr *size); | ||
| 93 | |||
| 94 | // A routine named real_sigaction() must be implemented by each sanitizer in | ||
| 95 | // order for internal_sigaction() to bypass interceptors. | ||
| 96 | int internal_sigaction(int signum, const void *act, void *oldact); | ||
| 97 | void internal_sigfillset(__sanitizer_sigset_t *set); | ||
| 98 | void internal_sigemptyset(__sanitizer_sigset_t *set); | ||
| 99 | bool internal_sigismember(__sanitizer_sigset_t *set, int signum); | ||
| 100 | |||
| 101 | uptr internal_execve(const char *filename, char *const argv[], | ||
| 102 | char *const envp[]); | ||
| 103 | |||
| 104 | bool IsStateDetached(int state); | ||
| 105 | |||
| 106 | // Move the fd out of {0, 1, 2} range. | ||
| 107 | fd_t ReserveStandardFds(fd_t fd); | ||
| 108 | |||
| 109 | bool ShouldMockFailureToOpen(const char *path); | ||
| 110 | |||
| 111 | // Create a non-file mapping with a given /proc/self/maps name. | ||
| 112 | uptr MmapNamed(void *addr, uptr length, int prot, int flags, const char *name); | ||
| 113 | |||
| 114 | // Platforms should implement at most one of these. | ||
| 115 | // 1. Provide a pre-decorated file descriptor to use instead of an anonymous | ||
| 116 | // mapping. | ||
| 117 | int GetNamedMappingFd(const char *name, uptr size, int *flags); | ||
| 118 | // 2. Add name to an existing anonymous mapping. The caller must keep *name | ||
| 119 | // alive at least as long as the mapping exists. | ||
| 120 | void DecorateMapping(uptr addr, uptr size, const char *name); | ||
| 121 | |||
| 122 | |||
| 123 | } // namespace __sanitizer | ||
| 124 | |||
| 125 | #endif // SANITIZER_POSIX_H | ||
lib/tsan/sanitizer_common/sanitizer_printf.cpp created+358| ... | @@ -0,0 +1,358 @@ | ||
| 1 | //===-- sanitizer_printf.cpp ----------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer. | ||
| 10 | // | ||
| 11 | // Internal printf function, used inside run-time libraries. | ||
| 12 | // We can't use libc printf because we intercept some of the functions used | ||
| 13 | // inside it. | ||
| 14 | //===----------------------------------------------------------------------===// | ||
| 15 | |||
| 16 | #include "sanitizer_common.h" | ||
| 17 | #include "sanitizer_flags.h" | ||
| 18 | #include "sanitizer_libc.h" | ||
| 19 | |||
| 20 | #include <stdio.h> | ||
| 21 | #include <stdarg.h> | ||
| 22 | |||
| 23 | #if SANITIZER_WINDOWS && defined(_MSC_VER) && _MSC_VER < 1800 && \ | ||
| 24 | !defined(va_copy) | ||
| 25 | # define va_copy(dst, src) ((dst) = (src)) | ||
| 26 | #endif | ||
| 27 | |||
| 28 | namespace __sanitizer { | ||
| 29 | |||
| 30 | static int AppendChar(char **buff, const char *buff_end, char c) { | ||
| 31 | if (*buff < buff_end) { | ||
| 32 | **buff = c; | ||
| 33 | (*buff)++; | ||
| 34 | } | ||
| 35 | return 1; | ||
| 36 | } | ||
| 37 | |||
| 38 | // Appends number in a given base to buffer. If its length is less than | ||
| 39 | // |minimal_num_length|, it is padded with leading zeroes or spaces, depending | ||
| 40 | // on the value of |pad_with_zero|. | ||
| 41 | static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value, | ||
| 42 | u8 base, u8 minimal_num_length, bool pad_with_zero, | ||
| 43 | bool negative, bool uppercase) { | ||
| 44 | uptr const kMaxLen = 30; | ||
| 45 | RAW_CHECK(base == 10 || base == 16); | ||
| 46 | RAW_CHECK(base == 10 || !negative); | ||
| 47 | RAW_CHECK(absolute_value || !negative); | ||
| 48 | RAW_CHECK(minimal_num_length < kMaxLen); | ||
| 49 | int result = 0; | ||
| 50 | if (negative && minimal_num_length) | ||
| 51 | --minimal_num_length; | ||
| 52 | if (negative && pad_with_zero) | ||
| 53 | result += AppendChar(buff, buff_end, '-'); | ||
| 54 | uptr num_buffer[kMaxLen]; | ||
| 55 | int pos = 0; | ||
| 56 | do { | ||
| 57 | RAW_CHECK_MSG((uptr)pos < kMaxLen, "AppendNumber buffer overflow"); | ||
| 58 | num_buffer[pos++] = absolute_value % base; | ||
| 59 | absolute_value /= base; | ||
| 60 | } while (absolute_value > 0); | ||
| 61 | if (pos < minimal_num_length) { | ||
| 62 | // Make sure compiler doesn't insert call to memset here. | ||
| 63 | internal_memset(&num_buffer[pos], 0, | ||
| 64 | sizeof(num_buffer[0]) * (minimal_num_length - pos)); | ||
| 65 | pos = minimal_num_length; | ||
| 66 | } | ||
| 67 | RAW_CHECK(pos > 0); | ||
| 68 | pos--; | ||
| 69 | for (; pos >= 0 && num_buffer[pos] == 0; pos--) { | ||
| 70 | char c = (pad_with_zero || pos == 0) ? '0' : ' '; | ||
| 71 | result += AppendChar(buff, buff_end, c); | ||
| 72 | } | ||
| 73 | if (negative && !pad_with_zero) result += AppendChar(buff, buff_end, '-'); | ||
| 74 | for (; pos >= 0; pos--) { | ||
| 75 | char digit = static_cast<char>(num_buffer[pos]); | ||
| 76 | digit = (digit < 10) ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10; | ||
| 77 | result += AppendChar(buff, buff_end, digit); | ||
| 78 | } | ||
| 79 | return result; | ||
| 80 | } | ||
| 81 | |||
| 82 | static int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base, | ||
| 83 | u8 minimal_num_length, bool pad_with_zero, | ||
| 84 | bool uppercase) { | ||
| 85 | return AppendNumber(buff, buff_end, num, base, minimal_num_length, | ||
| 86 | pad_with_zero, false /* negative */, uppercase); | ||
| 87 | } | ||
| 88 | |||
| 89 | static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num, | ||
| 90 | u8 minimal_num_length, bool pad_with_zero) { | ||
| 91 | bool negative = (num < 0); | ||
| 92 | return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10, | ||
| 93 | minimal_num_length, pad_with_zero, negative, | ||
| 94 | false /* uppercase */); | ||
| 95 | } | ||
| 96 | |||
| 97 | |||
| 98 | // Use the fact that explicitly requesting 0 width (%0s) results in UB and | ||
| 99 | // interpret width == 0 as "no width requested": | ||
| 100 | // width == 0 - no width requested | ||
| 101 | // width < 0 - left-justify s within and pad it to -width chars, if necessary | ||
| 102 | // width > 0 - right-justify s, not implemented yet | ||
| 103 | static int AppendString(char **buff, const char *buff_end, int width, | ||
| 104 | int max_chars, const char *s) { | ||
| 105 | if (!s) | ||
| 106 | s = "<null>"; | ||
| 107 | int result = 0; | ||
| 108 | for (; *s; s++) { | ||
| 109 | if (max_chars >= 0 && result >= max_chars) | ||
| 110 | break; | ||
| 111 | result += AppendChar(buff, buff_end, *s); | ||
| 112 | } | ||
| 113 | // Only the left justified strings are supported. | ||
| 114 | while (width < -result) | ||
| 115 | result += AppendChar(buff, buff_end, ' '); | ||
| 116 | return result; | ||
| 117 | } | ||
| 118 | |||
| 119 | static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) { | ||
| 120 | int result = 0; | ||
| 121 | result += AppendString(buff, buff_end, 0, -1, "0x"); | ||
| 122 | result += AppendUnsigned(buff, buff_end, ptr_value, 16, | ||
| 123 | SANITIZER_POINTER_FORMAT_LENGTH, | ||
| 124 | true /* pad_with_zero */, false /* uppercase */); | ||
| 125 | return result; | ||
| 126 | } | ||
| 127 | |||
| 128 | int VSNPrintf(char *buff, int buff_length, | ||
| 129 | const char *format, va_list args) { | ||
| 130 | static const char *kPrintfFormatsHelp = | ||
| 131 | "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x,X}; %p; " | ||
| 132 | "%[-]([0-9]*)?(\\.\\*)?s; %c\n"; | ||
| 133 | RAW_CHECK(format); | ||
| 134 | RAW_CHECK(buff_length > 0); | ||
| 135 | const char *buff_end = &buff[buff_length - 1]; | ||
| 136 | const char *cur = format; | ||
| 137 | int result = 0; | ||
| 138 | for (; *cur; cur++) { | ||
| 139 | if (*cur != '%') { | ||
| 140 | result += AppendChar(&buff, buff_end, *cur); | ||
| 141 | continue; | ||
| 142 | } | ||
| 143 | cur++; | ||
| 144 | bool left_justified = *cur == '-'; | ||
| 145 | if (left_justified) | ||
| 146 | cur++; | ||
| 147 | bool have_width = (*cur >= '0' && *cur <= '9'); | ||
| 148 | bool pad_with_zero = (*cur == '0'); | ||
| 149 | int width = 0; | ||
| 150 | if (have_width) { | ||
| 151 | while (*cur >= '0' && *cur <= '9') { | ||
| 152 | width = width * 10 + *cur++ - '0'; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | bool have_precision = (cur[0] == '.' && cur[1] == '*'); | ||
| 156 | int precision = -1; | ||
| 157 | if (have_precision) { | ||
| 158 | cur += 2; | ||
| 159 | precision = va_arg(args, int); | ||
| 160 | } | ||
| 161 | bool have_z = (*cur == 'z'); | ||
| 162 | cur += have_z; | ||
| 163 | bool have_ll = !have_z && (cur[0] == 'l' && cur[1] == 'l'); | ||
| 164 | cur += have_ll * 2; | ||
| 165 | s64 dval; | ||
| 166 | u64 uval; | ||
| 167 | const bool have_length = have_z || have_ll; | ||
| 168 | const bool have_flags = have_width || have_length; | ||
| 169 | // At the moment only %s supports precision and left-justification. | ||
| 170 | CHECK(!((precision >= 0 || left_justified) && *cur != 's')); | ||
| 171 | switch (*cur) { | ||
| 172 | case 'd': { | ||
| 173 | dval = have_ll ? va_arg(args, s64) | ||
| 174 | : have_z ? va_arg(args, sptr) | ||
| 175 | : va_arg(args, int); | ||
| 176 | result += AppendSignedDecimal(&buff, buff_end, dval, width, | ||
| 177 | pad_with_zero); | ||
| 178 | break; | ||
| 179 | } | ||
| 180 | case 'u': | ||
| 181 | case 'x': | ||
| 182 | case 'X': { | ||
| 183 | uval = have_ll ? va_arg(args, u64) | ||
| 184 | : have_z ? va_arg(args, uptr) | ||
| 185 | : va_arg(args, unsigned); | ||
| 186 | bool uppercase = (*cur == 'X'); | ||
| 187 | result += AppendUnsigned(&buff, buff_end, uval, (*cur == 'u') ? 10 : 16, | ||
| 188 | width, pad_with_zero, uppercase); | ||
| 189 | break; | ||
| 190 | } | ||
| 191 | case 'p': { | ||
| 192 | RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); | ||
| 193 | result += AppendPointer(&buff, buff_end, va_arg(args, uptr)); | ||
| 194 | break; | ||
| 195 | } | ||
| 196 | case 's': { | ||
| 197 | RAW_CHECK_MSG(!have_length, kPrintfFormatsHelp); | ||
| 198 | // Only left-justified width is supported. | ||
| 199 | CHECK(!have_width || left_justified); | ||
| 200 | result += AppendString(&buff, buff_end, left_justified ? -width : width, | ||
| 201 | precision, va_arg(args, char*)); | ||
| 202 | break; | ||
| 203 | } | ||
| 204 | case 'c': { | ||
| 205 | RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); | ||
| 206 | result += AppendChar(&buff, buff_end, va_arg(args, int)); | ||
| 207 | break; | ||
| 208 | } | ||
| 209 | case '%' : { | ||
| 210 | RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); | ||
| 211 | result += AppendChar(&buff, buff_end, '%'); | ||
| 212 | break; | ||
| 213 | } | ||
| 214 | default: { | ||
| 215 | RAW_CHECK_MSG(false, kPrintfFormatsHelp); | ||
| 216 | } | ||
| 217 | } | ||
| 218 | } | ||
| 219 | RAW_CHECK(buff <= buff_end); | ||
| 220 | AppendChar(&buff, buff_end + 1, '\0'); | ||
| 221 | return result; | ||
| 222 | } | ||
| 223 | |||
| 224 | static void (*PrintfAndReportCallback)(const char *); | ||
| 225 | void SetPrintfAndReportCallback(void (*callback)(const char *)) { | ||
| 226 | PrintfAndReportCallback = callback; | ||
| 227 | } | ||
| 228 | |||
| 229 | // Can be overriden in frontend. | ||
| 230 | #if SANITIZER_GO && defined(TSAN_EXTERNAL_HOOKS) | ||
| 231 | // Implementation must be defined in frontend. | ||
| 232 | extern "C" void __sanitizer_on_print(const char *str); | ||
| 233 | #else | ||
| 234 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_on_print, const char *str) { | ||
| 235 | (void)str; | ||
| 236 | } | ||
| 237 | #endif | ||
| 238 | |||
| 239 | static void CallPrintfAndReportCallback(const char *str) { | ||
| 240 | __sanitizer_on_print(str); | ||
| 241 | if (PrintfAndReportCallback) | ||
| 242 | PrintfAndReportCallback(str); | ||
| 243 | } | ||
| 244 | |||
| 245 | static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid, | ||
| 246 | char *local_buffer, | ||
| 247 | int buffer_size, | ||
| 248 | const char *format, | ||
| 249 | va_list args) { | ||
| 250 | va_list args2; | ||
| 251 | va_copy(args2, args); | ||
| 252 | const int kLen = 16 * 1024; | ||
| 253 | int needed_length; | ||
| 254 | char *buffer = local_buffer; | ||
| 255 | // First try to print a message using a local buffer, and then fall back to | ||
| 256 | // mmaped buffer. | ||
| 257 | for (int use_mmap = 0; use_mmap < 2; use_mmap++) { | ||
| 258 | if (use_mmap) { | ||
| 259 | va_end(args); | ||
| 260 | va_copy(args, args2); | ||
| 261 | buffer = (char*)MmapOrDie(kLen, "Report"); | ||
| 262 | buffer_size = kLen; | ||
| 263 | } | ||
| 264 | needed_length = 0; | ||
| 265 | // Check that data fits into the current buffer. | ||
| 266 | # define CHECK_NEEDED_LENGTH \ | ||
| 267 | if (needed_length >= buffer_size) { \ | ||
| 268 | if (!use_mmap) continue; \ | ||
| 269 | RAW_CHECK_MSG(needed_length < kLen, \ | ||
| 270 | "Buffer in Report is too short!\n"); \ | ||
| 271 | } | ||
| 272 | // Fuchsia's logging infrastructure always keeps track of the logging | ||
| 273 | // process, thread, and timestamp, so never prepend such information. | ||
| 274 | if (!SANITIZER_FUCHSIA && append_pid) { | ||
| 275 | int pid = internal_getpid(); | ||
| 276 | const char *exe_name = GetProcessName(); | ||
| 277 | if (common_flags()->log_exe_name && exe_name) { | ||
| 278 | needed_length += internal_snprintf(buffer, buffer_size, | ||
| 279 | "==%s", exe_name); | ||
| 280 | CHECK_NEEDED_LENGTH | ||
| 281 | } | ||
| 282 | needed_length += internal_snprintf( | ||
| 283 | buffer + needed_length, buffer_size - needed_length, "==%d==", pid); | ||
| 284 | CHECK_NEEDED_LENGTH | ||
| 285 | } | ||
| 286 | needed_length += VSNPrintf(buffer + needed_length, | ||
| 287 | buffer_size - needed_length, format, args); | ||
| 288 | CHECK_NEEDED_LENGTH | ||
| 289 | // If the message fit into the buffer, print it and exit. | ||
| 290 | break; | ||
| 291 | # undef CHECK_NEEDED_LENGTH | ||
| 292 | } | ||
| 293 | RawWrite(buffer); | ||
| 294 | |||
| 295 | // Remove color sequences from the message. | ||
| 296 | RemoveANSIEscapeSequencesFromString(buffer); | ||
| 297 | CallPrintfAndReportCallback(buffer); | ||
| 298 | LogMessageOnPrintf(buffer); | ||
| 299 | |||
| 300 | // If we had mapped any memory, clean up. | ||
| 301 | if (buffer != local_buffer) | ||
| 302 | UnmapOrDie((void *)buffer, buffer_size); | ||
| 303 | va_end(args2); | ||
| 304 | } | ||
| 305 | |||
| 306 | static void NOINLINE SharedPrintfCode(bool append_pid, const char *format, | ||
| 307 | va_list args) { | ||
| 308 | // |local_buffer| is small enough not to overflow the stack and/or violate | ||
| 309 | // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other | ||
| 310 | // hand, the bigger the buffer is, the more the chance the error report will | ||
| 311 | // fit into it. | ||
| 312 | char local_buffer[400]; | ||
| 313 | SharedPrintfCodeNoBuffer(append_pid, local_buffer, ARRAY_SIZE(local_buffer), | ||
| 314 | format, args); | ||
| 315 | } | ||
| 316 | |||
| 317 | FORMAT(1, 2) | ||
| 318 | void Printf(const char *format, ...) { | ||
| 319 | va_list args; | ||
| 320 | va_start(args, format); | ||
| 321 | SharedPrintfCode(false, format, args); | ||
| 322 | va_end(args); | ||
| 323 | } | ||
| 324 | |||
| 325 | // Like Printf, but prints the current PID before the output string. | ||
| 326 | FORMAT(1, 2) | ||
| 327 | void Report(const char *format, ...) { | ||
| 328 | va_list args; | ||
| 329 | va_start(args, format); | ||
| 330 | SharedPrintfCode(true, format, args); | ||
| 331 | va_end(args); | ||
| 332 | } | ||
| 333 | |||
| 334 | // Writes at most "length" symbols to "buffer" (including trailing '\0'). | ||
| 335 | // Returns the number of symbols that should have been written to buffer | ||
| 336 | // (not including trailing '\0'). Thus, the string is truncated | ||
| 337 | // iff return value is not less than "length". | ||
| 338 | FORMAT(3, 4) | ||
| 339 | int internal_snprintf(char *buffer, uptr length, const char *format, ...) { | ||
| 340 | va_list args; | ||
| 341 | va_start(args, format); | ||
| 342 | int needed_length = VSNPrintf(buffer, length, format, args); | ||
| 343 | va_end(args); | ||
| 344 | return needed_length; | ||
| 345 | } | ||
| 346 | |||
| 347 | FORMAT(2, 3) | ||
| 348 | void InternalScopedString::append(const char *format, ...) { | ||
| 349 | CHECK_LT(length_, size()); | ||
| 350 | va_list args; | ||
| 351 | va_start(args, format); | ||
| 352 | VSNPrintf(data() + length_, size() - length_, format, args); | ||
| 353 | va_end(args); | ||
| 354 | length_ += internal_strlen(data() + length_); | ||
| 355 | CHECK_LT(length_, size()); | ||
| 356 | } | ||
| 357 | |||
| 358 | } // namespace __sanitizer | ||
lib/tsan/sanitizer_common/sanitizer_procmaps.h created+100| ... | @@ -0,0 +1,100 @@ | ||
| 1 | //===-- sanitizer_procmaps.h ------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer. | ||
| 10 | // | ||
| 11 | // Information about the process mappings. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | #ifndef SANITIZER_PROCMAPS_H | ||
| 14 | #define SANITIZER_PROCMAPS_H | ||
| 15 | |||
| 16 | #include "sanitizer_platform.h" | ||
| 17 | |||
| 18 | #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ | ||
| 19 | SANITIZER_OPENBSD || SANITIZER_MAC || SANITIZER_SOLARIS || \ | ||
| 20 | SANITIZER_FUCHSIA | ||
| 21 | |||
| 22 | #include "sanitizer_common.h" | ||
| 23 | #include "sanitizer_internal_defs.h" | ||
| 24 | #include "sanitizer_fuchsia.h" | ||
| 25 | #include "sanitizer_linux.h" | ||
| 26 | #include "sanitizer_mac.h" | ||
| 27 | #include "sanitizer_mutex.h" | ||
| 28 | |||
| 29 | namespace __sanitizer { | ||
| 30 | |||
| 31 | // Memory protection masks. | ||
| 32 | static const uptr kProtectionRead = 1; | ||
| 33 | static const uptr kProtectionWrite = 2; | ||
| 34 | static const uptr kProtectionExecute = 4; | ||
| 35 | static const uptr kProtectionShared = 8; | ||
| 36 | |||
| 37 | struct MemoryMappedSegmentData; | ||
| 38 | |||
| 39 | class MemoryMappedSegment { | ||
| 40 | public: | ||
| 41 | explicit MemoryMappedSegment(char *buff = nullptr, uptr size = 0) | ||
| 42 | : filename(buff), filename_size(size), data_(nullptr) {} | ||
| 43 | ~MemoryMappedSegment() {} | ||
| 44 | |||
| 45 | bool IsReadable() const { return protection & kProtectionRead; } | ||
| 46 | bool IsWritable() const { return protection & kProtectionWrite; } | ||
| 47 | bool IsExecutable() const { return protection & kProtectionExecute; } | ||
| 48 | bool IsShared() const { return protection & kProtectionShared; } | ||
| 49 | |||
| 50 | void AddAddressRanges(LoadedModule *module); | ||
| 51 | |||
| 52 | uptr start; | ||
| 53 | uptr end; | ||
| 54 | uptr offset; | ||
| 55 | char *filename; // owned by caller | ||
| 56 | uptr filename_size; | ||
| 57 | uptr protection; | ||
| 58 | ModuleArch arch; | ||
| 59 | u8 uuid[kModuleUUIDSize]; | ||
| 60 | |||
| 61 | private: | ||
| 62 | friend class MemoryMappingLayout; | ||
| 63 | |||
| 64 | // This field is assigned and owned by MemoryMappingLayout if needed | ||
| 65 | MemoryMappedSegmentData *data_; | ||
| 66 | }; | ||
| 67 | |||
| 68 | class MemoryMappingLayout { | ||
| 69 | public: | ||
| 70 | explicit MemoryMappingLayout(bool cache_enabled); | ||
| 71 | ~MemoryMappingLayout(); | ||
| 72 | bool Next(MemoryMappedSegment *segment); | ||
| 73 | bool Error() const; | ||
| 74 | void Reset(); | ||
| 75 | // In some cases, e.g. when running under a sandbox on Linux, ASan is unable | ||
| 76 | // to obtain the memory mappings. It should fall back to pre-cached data | ||
| 77 | // instead of aborting. | ||
| 78 | static void CacheMemoryMappings(); | ||
| 79 | |||
| 80 | // Adds all mapped objects into a vector. | ||
| 81 | void DumpListOfModules(InternalMmapVectorNoCtor<LoadedModule> *modules); | ||
| 82 | |||
| 83 | private: | ||
| 84 | void LoadFromCache(); | ||
| 85 | |||
| 86 | MemoryMappingLayoutData data_; | ||
| 87 | }; | ||
| 88 | |||
| 89 | // Returns code range for the specified module. | ||
| 90 | bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end); | ||
| 91 | |||
| 92 | bool IsDecimal(char c); | ||
| 93 | uptr ParseDecimal(const char **p); | ||
| 94 | bool IsHex(char c); | ||
| 95 | uptr ParseHex(const char **p); | ||
| 96 | |||
| 97 | } // namespace __sanitizer | ||
| 98 | |||
| 99 | #endif | ||
| 100 | #endif // SANITIZER_PROCMAPS_H | ||
lib/tsan/sanitizer_common/sanitizer_procmaps_bsd.cpp created+139| ... | @@ -0,0 +1,139 @@ | ||
| 1 | //===-- sanitizer_procmaps_bsd.cpp ----------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Information about the process mappings | ||
| 10 | // (FreeBSD, OpenBSD and NetBSD-specific parts). | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_platform.h" | ||
| 14 | #if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD | ||
| 15 | #include "sanitizer_common.h" | ||
| 16 | #if SANITIZER_FREEBSD | ||
| 17 | #include "sanitizer_freebsd.h" | ||
| 18 | #endif | ||
| 19 | #include "sanitizer_procmaps.h" | ||
| 20 | |||
| 21 | // clang-format off | ||
| 22 | #include <sys/types.h> | ||
| 23 | #include <sys/sysctl.h> | ||
| 24 | // clang-format on | ||
| 25 | #include <unistd.h> | ||
| 26 | #if SANITIZER_FREEBSD | ||
| 27 | #include <sys/user.h> | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #include <limits.h> | ||
| 31 | #if SANITIZER_OPENBSD | ||
| 32 | #define KVME_PROT_READ KVE_PROT_READ | ||
| 33 | #define KVME_PROT_WRITE KVE_PROT_WRITE | ||
| 34 | #define KVME_PROT_EXEC KVE_PROT_EXEC | ||
| 35 | #endif | ||
| 36 | |||
| 37 | // Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode. | ||
| 38 | #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) | ||
| 39 | #include <osreldate.h> | ||
| 40 | #if __FreeBSD_version <= 902001 // v9.2 | ||
| 41 | #define kinfo_vmentry xkinfo_vmentry | ||
| 42 | #endif | ||
| 43 | #endif | ||
| 44 | |||
| 45 | namespace __sanitizer { | ||
| 46 | |||
| 47 | void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { | ||
| 48 | const int Mib[] = { | ||
| 49 | #if SANITIZER_FREEBSD | ||
| 50 | CTL_KERN, | ||
| 51 | KERN_PROC, | ||
| 52 | KERN_PROC_VMMAP, | ||
| 53 | getpid() | ||
| 54 | #elif SANITIZER_OPENBSD | ||
| 55 | CTL_KERN, | ||
| 56 | KERN_PROC_VMMAP, | ||
| 57 | getpid() | ||
| 58 | #elif SANITIZER_NETBSD | ||
| 59 | CTL_VM, | ||
| 60 | VM_PROC, | ||
| 61 | VM_PROC_MAP, | ||
| 62 | getpid(), | ||
| 63 | sizeof(struct kinfo_vmentry) | ||
| 64 | #else | ||
| 65 | #error "not supported" | ||
| 66 | #endif | ||
| 67 | }; | ||
| 68 | |||
| 69 | uptr Size = 0; | ||
| 70 | int Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), NULL, &Size, NULL, 0); | ||
| 71 | CHECK_EQ(Err, 0); | ||
| 72 | CHECK_GT(Size, 0); | ||
| 73 | |||
| 74 | #if !SANITIZER_OPENBSD | ||
| 75 | size_t MmapedSize = Size * 4 / 3; | ||
| 76 | void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()"); | ||
| 77 | Size = MmapedSize; | ||
| 78 | Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), VmMap, &Size, NULL, 0); | ||
| 79 | CHECK_EQ(Err, 0); | ||
| 80 | proc_maps->data = (char *)VmMap; | ||
| 81 | #else | ||
| 82 | size_t PageSize = GetPageSize(); | ||
| 83 | size_t MmapedSize = Size; | ||
| 84 | MmapedSize = ((MmapedSize - 1) / PageSize + 1) * PageSize; | ||
| 85 | char *Mem = (char *)MmapOrDie(MmapedSize, "ReadProcMaps()"); | ||
| 86 | Size = 2 * Size + 10 * sizeof(struct kinfo_vmentry); | ||
| 87 | if (Size > 0x10000) | ||
| 88 | Size = 0x10000; | ||
| 89 | Size = (Size / sizeof(struct kinfo_vmentry)) * sizeof(struct kinfo_vmentry); | ||
| 90 | Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), Mem, &Size, NULL, 0); | ||
| 91 | CHECK_EQ(Err, 0); | ||
| 92 | MmapedSize = Size; | ||
| 93 | proc_maps->data = Mem; | ||
| 94 | #endif | ||
| 95 | |||
| 96 | proc_maps->mmaped_size = MmapedSize; | ||
| 97 | proc_maps->len = Size; | ||
| 98 | } | ||
| 99 | |||
| 100 | bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { | ||
| 101 | CHECK(!Error()); // can not fail | ||
| 102 | char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; | ||
| 103 | if (data_.current >= last) | ||
| 104 | return false; | ||
| 105 | const struct kinfo_vmentry *VmEntry = | ||
| 106 | (const struct kinfo_vmentry *)data_.current; | ||
| 107 | |||
| 108 | segment->start = (uptr)VmEntry->kve_start; | ||
| 109 | segment->end = (uptr)VmEntry->kve_end; | ||
| 110 | segment->offset = (uptr)VmEntry->kve_offset; | ||
| 111 | |||
| 112 | segment->protection = 0; | ||
| 113 | if ((VmEntry->kve_protection & KVME_PROT_READ) != 0) | ||
| 114 | segment->protection |= kProtectionRead; | ||
| 115 | if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0) | ||
| 116 | segment->protection |= kProtectionWrite; | ||
| 117 | if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0) | ||
| 118 | segment->protection |= kProtectionExecute; | ||
| 119 | |||
| 120 | #if !SANITIZER_OPENBSD | ||
| 121 | if (segment->filename != NULL && segment->filename_size > 0) { | ||
| 122 | internal_snprintf(segment->filename, | ||
| 123 | Min(segment->filename_size, (uptr)PATH_MAX), "%s", | ||
| 124 | VmEntry->kve_path); | ||
| 125 | } | ||
| 126 | #endif | ||
| 127 | |||
| 128 | #if SANITIZER_FREEBSD | ||
| 129 | data_.current += VmEntry->kve_structsize; | ||
| 130 | #else | ||
| 131 | data_.current += sizeof(*VmEntry); | ||
| 132 | #endif | ||
| 133 | |||
| 134 | return true; | ||
| 135 | } | ||
| 136 | |||
| 137 | } // namespace __sanitizer | ||
| 138 | |||
| 139 | #endif | ||
lib/tsan/sanitizer_common/sanitizer_procmaps_common.cpp created+174| ... | @@ -0,0 +1,174 @@ | ||
| 1 | //===-- sanitizer_procmaps_common.cpp -------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Information about the process mappings (common parts). | ||
| 10 | //===----------------------------------------------------------------------===// | ||
| 11 | |||
| 12 | #include "sanitizer_platform.h" | ||
| 13 | |||
| 14 | #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ | ||
| 15 | SANITIZER_OPENBSD || SANITIZER_SOLARIS | ||
| 16 | |||
| 17 | #include "sanitizer_common.h" | ||
| 18 | #include "sanitizer_placement_new.h" | ||
| 19 | #include "sanitizer_procmaps.h" | ||
| 20 | |||
| 21 | namespace __sanitizer { | ||
| 22 | |||
| 23 | static ProcSelfMapsBuff cached_proc_self_maps; | ||
| 24 | static StaticSpinMutex cache_lock; | ||
| 25 | |||
| 26 | static int TranslateDigit(char c) { | ||
| 27 | if (c >= '0' && c <= '9') | ||
| 28 | return c - '0'; | ||
| 29 | if (c >= 'a' && c <= 'f') | ||
| 30 | return c - 'a' + 10; | ||
| 31 | if (c >= 'A' && c <= 'F') | ||
| 32 | return c - 'A' + 10; | ||
| 33 | return -1; | ||
| 34 | } | ||
| 35 | |||
| 36 | // Parse a number and promote 'p' up to the first non-digit character. | ||
| 37 | static uptr ParseNumber(const char **p, int base) { | ||
| 38 | uptr n = 0; | ||
| 39 | int d; | ||
| 40 | CHECK(base >= 2 && base <= 16); | ||
| 41 | while ((d = TranslateDigit(**p)) >= 0 && d < base) { | ||
| 42 | n = n * base + d; | ||
| 43 | (*p)++; | ||
| 44 | } | ||
| 45 | return n; | ||
| 46 | } | ||
| 47 | |||
| 48 | bool IsDecimal(char c) { | ||
| 49 | int d = TranslateDigit(c); | ||
| 50 | return d >= 0 && d < 10; | ||
| 51 | } | ||
| 52 | |||
| 53 | uptr ParseDecimal(const char **p) { | ||
| 54 | return ParseNumber(p, 10); | ||
| 55 | } | ||
| 56 | |||
| 57 | bool IsHex(char c) { | ||
| 58 | int d = TranslateDigit(c); | ||
| 59 | return d >= 0 && d < 16; | ||
| 60 | } | ||
| 61 | |||
| 62 | uptr ParseHex(const char **p) { | ||
| 63 | return ParseNumber(p, 16); | ||
| 64 | } | ||
| 65 | |||
| 66 | void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { | ||
| 67 | // data_ should be unused on this platform | ||
| 68 | CHECK(!data_); | ||
| 69 | module->addAddressRange(start, end, IsExecutable(), IsWritable()); | ||
| 70 | } | ||
| 71 | |||
| 72 | MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { | ||
| 73 | // FIXME: in the future we may want to cache the mappings on demand only. | ||
| 74 | if (cache_enabled) | ||
| 75 | CacheMemoryMappings(); | ||
| 76 | |||
| 77 | // Read maps after the cache update to capture the maps/unmaps happening in | ||
| 78 | // the process of updating. | ||
| 79 | ReadProcMaps(&data_.proc_self_maps); | ||
| 80 | if (cache_enabled && data_.proc_self_maps.mmaped_size == 0) | ||
| 81 | LoadFromCache(); | ||
| 82 | |||
| 83 | Reset(); | ||
| 84 | } | ||
| 85 | |||
| 86 | bool MemoryMappingLayout::Error() const { | ||
| 87 | return data_.current == nullptr; | ||
| 88 | } | ||
| 89 | |||
| 90 | MemoryMappingLayout::~MemoryMappingLayout() { | ||
| 91 | // Only unmap the buffer if it is different from the cached one. Otherwise | ||
| 92 | // it will be unmapped when the cache is refreshed. | ||
| 93 | if (data_.proc_self_maps.data != cached_proc_self_maps.data) | ||
| 94 | UnmapOrDie(data_.proc_self_maps.data, data_.proc_self_maps.mmaped_size); | ||
| 95 | } | ||
| 96 | |||
| 97 | void MemoryMappingLayout::Reset() { | ||
| 98 | data_.current = data_.proc_self_maps.data; | ||
| 99 | } | ||
| 100 | |||
| 101 | // static | ||
| 102 | void MemoryMappingLayout::CacheMemoryMappings() { | ||
| 103 | ProcSelfMapsBuff new_proc_self_maps; | ||
| 104 | ReadProcMaps(&new_proc_self_maps); | ||
| 105 | // Don't invalidate the cache if the mappings are unavailable. | ||
| 106 | if (new_proc_self_maps.mmaped_size == 0) | ||
| 107 | return; | ||
| 108 | SpinMutexLock l(&cache_lock); | ||
| 109 | if (cached_proc_self_maps.mmaped_size) | ||
| 110 | UnmapOrDie(cached_proc_self_maps.data, cached_proc_self_maps.mmaped_size); | ||
| 111 | cached_proc_self_maps = new_proc_self_maps; | ||
| 112 | } | ||
| 113 | |||
| 114 | void MemoryMappingLayout::LoadFromCache() { | ||
| 115 | SpinMutexLock l(&cache_lock); | ||
| 116 | if (cached_proc_self_maps.data) | ||
| 117 | data_.proc_self_maps = cached_proc_self_maps; | ||
| 118 | } | ||
| 119 | |||
| 120 | void MemoryMappingLayout::DumpListOfModules( | ||
| 121 | InternalMmapVectorNoCtor<LoadedModule> *modules) { | ||
| 122 | Reset(); | ||
| 123 | InternalScopedString module_name(kMaxPathLength); | ||
| 124 | MemoryMappedSegment segment(module_name.data(), module_name.size()); | ||
| 125 | for (uptr i = 0; Next(&segment); i++) { | ||
| 126 | const char *cur_name = segment.filename; | ||
| 127 | if (cur_name[0] == '\0') | ||
| 128 | continue; | ||
| 129 | // Don't subtract 'cur_beg' from the first entry: | ||
| 130 | // * If a binary is compiled w/o -pie, then the first entry in | ||
| 131 | // process maps is likely the binary itself (all dynamic libs | ||
| 132 | // are mapped higher in address space). For such a binary, | ||
| 133 | // instruction offset in binary coincides with the actual | ||
| 134 | // instruction address in virtual memory (as code section | ||
| 135 | // is mapped to a fixed memory range). | ||
| 136 | // * If a binary is compiled with -pie, all the modules are | ||
| 137 | // mapped high at address space (in particular, higher than | ||
| 138 | // shadow memory of the tool), so the module can't be the | ||
| 139 | // first entry. | ||
| 140 | uptr base_address = (i ? segment.start : 0) - segment.offset; | ||
| 141 | LoadedModule cur_module; | ||
| 142 | cur_module.set(cur_name, base_address); | ||
| 143 | segment.AddAddressRanges(&cur_module); | ||
| 144 | modules->push_back(cur_module); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { | ||
| 149 | char *smaps = nullptr; | ||
| 150 | uptr smaps_cap = 0; | ||
| 151 | uptr smaps_len = 0; | ||
| 152 | if (!ReadFileToBuffer("/proc/self/smaps", &smaps, &smaps_cap, &smaps_len)) | ||
| 153 | return; | ||
| 154 | uptr start = 0; | ||
| 155 | bool file = false; | ||
| 156 | const char *pos = smaps; | ||
| 157 | while (pos < smaps + smaps_len) { | ||
| 158 | if (IsHex(pos[0])) { | ||
| 159 | start = ParseHex(&pos); | ||
| 160 | for (; *pos != '/' && *pos > '\n'; pos++) {} | ||
| 161 | file = *pos == '/'; | ||
| 162 | } else if (internal_strncmp(pos, "Rss:", 4) == 0) { | ||
| 163 | while (!IsDecimal(*pos)) pos++; | ||
| 164 | uptr rss = ParseDecimal(&pos) * 1024; | ||
| 165 | cb(start, rss, file, stats, stats_size); | ||
| 166 | } | ||
| 167 | while (*pos++ != '\n') {} | ||
| 168 | } | ||
| 169 | UnmapOrDie(smaps, smaps_cap); | ||
| 170 | } | ||
| 171 | |||
| 172 | } // namespace __sanitizer | ||
| 173 | |||
| 174 | #endif | ||
lib/tsan/sanitizer_common/sanitizer_procmaps_fuchsia.cpp created+80| ... | @@ -0,0 +1,80 @@ | ||
| 1 | //===-- sanitizer_procmaps_fuchsia.cpp | ||
| 2 | //----------------------------------------===// | ||
| 3 | // | ||
| 4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 5 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 7 | // | ||
| 8 | //===----------------------------------------------------------------------===// | ||
| 9 | // | ||
| 10 | // Information about the process mappings (Fuchsia-specific parts). | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_platform.h" | ||
| 14 | #if SANITIZER_FUCHSIA | ||
| 15 | #include <zircon/process.h> | ||
| 16 | #include <zircon/syscalls.h> | ||
| 17 | |||
| 18 | #include "sanitizer_common.h" | ||
| 19 | #include "sanitizer_procmaps.h" | ||
| 20 | |||
| 21 | namespace __sanitizer { | ||
| 22 | |||
| 23 | // The cache flag is ignored on Fuchsia because a process can always get this | ||
| 24 | // information via its process-self handle. | ||
| 25 | MemoryMappingLayout::MemoryMappingLayout(bool) { Reset(); } | ||
| 26 | |||
| 27 | void MemoryMappingLayout::Reset() { | ||
| 28 | data_.data.clear(); | ||
| 29 | data_.current = 0; | ||
| 30 | |||
| 31 | size_t count; | ||
| 32 | zx_status_t status = _zx_object_get_info( | ||
| 33 | _zx_process_self(), ZX_INFO_PROCESS_MAPS, nullptr, 0, nullptr, &count); | ||
| 34 | if (status != ZX_OK) { | ||
| 35 | return; | ||
| 36 | } | ||
| 37 | |||
| 38 | size_t filled; | ||
| 39 | do { | ||
| 40 | data_.data.resize(count); | ||
| 41 | status = _zx_object_get_info( | ||
| 42 | _zx_process_self(), ZX_INFO_PROCESS_MAPS, data_.data.data(), | ||
| 43 | count * sizeof(zx_info_maps_t), &filled, &count); | ||
| 44 | if (status != ZX_OK) { | ||
| 45 | data_.data.clear(); | ||
| 46 | return; | ||
| 47 | } | ||
| 48 | } while (filled < count); | ||
| 49 | } | ||
| 50 | |||
| 51 | MemoryMappingLayout::~MemoryMappingLayout() {} | ||
| 52 | |||
| 53 | bool MemoryMappingLayout::Error() const { return data_.data.empty(); } | ||
| 54 | |||
| 55 | bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { | ||
| 56 | while (data_.current < data_.data.size()) { | ||
| 57 | const auto &entry = data_.data[data_.current++]; | ||
| 58 | if (entry.type == ZX_INFO_MAPS_TYPE_MAPPING) { | ||
| 59 | segment->start = entry.base; | ||
| 60 | segment->end = entry.base + entry.size; | ||
| 61 | segment->offset = entry.u.mapping.vmo_offset; | ||
| 62 | const auto flags = entry.u.mapping.mmu_flags; | ||
| 63 | segment->protection = | ||
| 64 | ((flags & ZX_VM_PERM_READ) ? kProtectionRead : 0) | | ||
| 65 | ((flags & ZX_VM_PERM_WRITE) ? kProtectionWrite : 0) | | ||
| 66 | ((flags & ZX_VM_PERM_EXECUTE) ? kProtectionExecute : 0); | ||
| 67 | if (segment->filename && segment->filename_size > 0) { | ||
| 68 | uptr len = Min(sizeof(entry.name), segment->filename_size) - 1; | ||
| 69 | internal_strncpy(segment->filename, entry.name, len); | ||
| 70 | segment->filename[len] = 0; | ||
| 71 | } | ||
| 72 | return true; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | return false; | ||
| 76 | } | ||
| 77 | |||
| 78 | } // namespace __sanitizer | ||
| 79 | |||
| 80 | #endif // SANITIZER_FUCHSIA | ||
lib/tsan/sanitizer_common/sanitizer_procmaps_linux.cpp created+81| ... | @@ -0,0 +1,81 @@ | ||
| 1 | //===-- sanitizer_procmaps_linux.cpp --------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Information about the process mappings (Linux-specific parts). | ||
| 10 | //===----------------------------------------------------------------------===// | ||
| 11 | |||
| 12 | #include "sanitizer_platform.h" | ||
| 13 | #if SANITIZER_LINUX | ||
| 14 | #include "sanitizer_common.h" | ||
| 15 | #include "sanitizer_procmaps.h" | ||
| 16 | |||
| 17 | namespace __sanitizer { | ||
| 18 | |||
| 19 | void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { | ||
| 20 | if (!ReadFileToBuffer("/proc/self/maps", &proc_maps->data, | ||
| 21 | &proc_maps->mmaped_size, &proc_maps->len)) { | ||
| 22 | proc_maps->data = nullptr; | ||
| 23 | proc_maps->mmaped_size = 0; | ||
| 24 | proc_maps->len = 0; | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | static bool IsOneOf(char c, char c1, char c2) { | ||
| 29 | return c == c1 || c == c2; | ||
| 30 | } | ||
| 31 | |||
| 32 | bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { | ||
| 33 | if (Error()) return false; // simulate empty maps | ||
| 34 | char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; | ||
| 35 | if (data_.current >= last) return false; | ||
| 36 | char *next_line = | ||
| 37 | (char *)internal_memchr(data_.current, '\n', last - data_.current); | ||
| 38 | if (next_line == 0) | ||
| 39 | next_line = last; | ||
| 40 | // Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar | ||
| 41 | segment->start = ParseHex(&data_.current); | ||
| 42 | CHECK_EQ(*data_.current++, '-'); | ||
| 43 | segment->end = ParseHex(&data_.current); | ||
| 44 | CHECK_EQ(*data_.current++, ' '); | ||
| 45 | CHECK(IsOneOf(*data_.current, '-', 'r')); | ||
| 46 | segment->protection = 0; | ||
| 47 | if (*data_.current++ == 'r') segment->protection |= kProtectionRead; | ||
| 48 | CHECK(IsOneOf(*data_.current, '-', 'w')); | ||
| 49 | if (*data_.current++ == 'w') segment->protection |= kProtectionWrite; | ||
| 50 | CHECK(IsOneOf(*data_.current, '-', 'x')); | ||
| 51 | if (*data_.current++ == 'x') segment->protection |= kProtectionExecute; | ||
| 52 | CHECK(IsOneOf(*data_.current, 's', 'p')); | ||
| 53 | if (*data_.current++ == 's') segment->protection |= kProtectionShared; | ||
| 54 | CHECK_EQ(*data_.current++, ' '); | ||
| 55 | segment->offset = ParseHex(&data_.current); | ||
| 56 | CHECK_EQ(*data_.current++, ' '); | ||
| 57 | ParseHex(&data_.current); | ||
| 58 | CHECK_EQ(*data_.current++, ':'); | ||
| 59 | ParseHex(&data_.current); | ||
| 60 | CHECK_EQ(*data_.current++, ' '); | ||
| 61 | while (IsDecimal(*data_.current)) data_.current++; | ||
| 62 | // Qemu may lack the trailing space. | ||
| 63 | // https://github.com/google/sanitizers/issues/160 | ||
| 64 | // CHECK_EQ(*data_.current++, ' '); | ||
| 65 | // Skip spaces. | ||
| 66 | while (data_.current < next_line && *data_.current == ' ') data_.current++; | ||
| 67 | // Fill in the filename. | ||
| 68 | if (segment->filename) { | ||
| 69 | uptr len = | ||
| 70 | Min((uptr)(next_line - data_.current), segment->filename_size - 1); | ||
| 71 | internal_strncpy(segment->filename, data_.current, len); | ||
| 72 | segment->filename[len] = 0; | ||
| 73 | } | ||
| 74 | |||
| 75 | data_.current = next_line + 1; | ||
| 76 | return true; | ||
| 77 | } | ||
| 78 | |||
| 79 | } // namespace __sanitizer | ||
| 80 | |||
| 81 | #endif // SANITIZER_LINUX | ||
lib/tsan/sanitizer_common/sanitizer_procmaps_mac.cpp created+379| ... | @@ -0,0 +1,379 @@ | ||
| 1 | //===-- sanitizer_procmaps_mac.cpp ----------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Information about the process mappings (Mac-specific parts). | ||
| 10 | //===----------------------------------------------------------------------===// | ||
| 11 | |||
| 12 | #include "sanitizer_platform.h" | ||
| 13 | #if SANITIZER_MAC | ||
| 14 | #include "sanitizer_common.h" | ||
| 15 | #include "sanitizer_placement_new.h" | ||
| 16 | #include "sanitizer_procmaps.h" | ||
| 17 | |||
| 18 | #include <mach-o/dyld.h> | ||
| 19 | #include <mach-o/loader.h> | ||
| 20 | #include <mach/mach.h> | ||
| 21 | |||
| 22 | // These are not available in older macOS SDKs. | ||
| 23 | #ifndef CPU_SUBTYPE_X86_64_H | ||
| 24 | #define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) /* Haswell */ | ||
| 25 | #endif | ||
| 26 | #ifndef CPU_SUBTYPE_ARM_V7S | ||
| 27 | #define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t)11) /* Swift */ | ||
| 28 | #endif | ||
| 29 | #ifndef CPU_SUBTYPE_ARM_V7K | ||
| 30 | #define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t)12) | ||
| 31 | #endif | ||
| 32 | #ifndef CPU_TYPE_ARM64 | ||
| 33 | #define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) | ||
| 34 | #endif | ||
| 35 | |||
| 36 | namespace __sanitizer { | ||
| 37 | |||
| 38 | // Contains information used to iterate through sections. | ||
| 39 | struct MemoryMappedSegmentData { | ||
| 40 | char name[kMaxSegName]; | ||
| 41 | uptr nsects; | ||
| 42 | const char *current_load_cmd_addr; | ||
| 43 | u32 lc_type; | ||
| 44 | uptr base_virt_addr; | ||
| 45 | uptr addr_mask; | ||
| 46 | }; | ||
| 47 | |||
| 48 | template <typename Section> | ||
| 49 | static void NextSectionLoad(LoadedModule *module, MemoryMappedSegmentData *data, | ||
| 50 | bool isWritable) { | ||
| 51 | const Section *sc = (const Section *)data->current_load_cmd_addr; | ||
| 52 | data->current_load_cmd_addr += sizeof(Section); | ||
| 53 | |||
| 54 | uptr sec_start = (sc->addr & data->addr_mask) + data->base_virt_addr; | ||
| 55 | uptr sec_end = sec_start + sc->size; | ||
| 56 | module->addAddressRange(sec_start, sec_end, /*executable=*/false, isWritable, | ||
| 57 | sc->sectname); | ||
| 58 | } | ||
| 59 | |||
| 60 | void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) { | ||
| 61 | // Don't iterate over sections when the caller hasn't set up the | ||
| 62 | // data pointer, when there are no sections, or when the segment | ||
| 63 | // is executable. Avoid iterating over executable sections because | ||
| 64 | // it will confuse libignore, and because the extra granularity | ||
| 65 | // of information is not needed by any sanitizers. | ||
| 66 | if (!data_ || !data_->nsects || IsExecutable()) { | ||
| 67 | module->addAddressRange(start, end, IsExecutable(), IsWritable(), | ||
| 68 | data_ ? data_->name : nullptr); | ||
| 69 | return; | ||
| 70 | } | ||
| 71 | |||
| 72 | do { | ||
| 73 | if (data_->lc_type == LC_SEGMENT) { | ||
| 74 | NextSectionLoad<struct section>(module, data_, IsWritable()); | ||
| 75 | #ifdef MH_MAGIC_64 | ||
| 76 | } else if (data_->lc_type == LC_SEGMENT_64) { | ||
| 77 | NextSectionLoad<struct section_64>(module, data_, IsWritable()); | ||
| 78 | #endif | ||
| 79 | } | ||
| 80 | } while (--data_->nsects); | ||
| 81 | } | ||
| 82 | |||
| 83 | MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { | ||
| 84 | Reset(); | ||
| 85 | } | ||
| 86 | |||
| 87 | MemoryMappingLayout::~MemoryMappingLayout() { | ||
| 88 | } | ||
| 89 | |||
| 90 | bool MemoryMappingLayout::Error() const { | ||
| 91 | return false; | ||
| 92 | } | ||
| 93 | |||
| 94 | // More information about Mach-O headers can be found in mach-o/loader.h | ||
| 95 | // Each Mach-O image has a header (mach_header or mach_header_64) starting with | ||
| 96 | // a magic number, and a list of linker load commands directly following the | ||
| 97 | // header. | ||
| 98 | // A load command is at least two 32-bit words: the command type and the | ||
| 99 | // command size in bytes. We're interested only in segment load commands | ||
| 100 | // (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped | ||
| 101 | // into the task's address space. | ||
| 102 | // The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or | ||
| 103 | // segment_command_64 correspond to the memory address, memory size and the | ||
| 104 | // file offset of the current memory segment. | ||
| 105 | // Because these fields are taken from the images as is, one needs to add | ||
| 106 | // _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime. | ||
| 107 | |||
| 108 | void MemoryMappingLayout::Reset() { | ||
| 109 | // Count down from the top. | ||
| 110 | // TODO(glider): as per man 3 dyld, iterating over the headers with | ||
| 111 | // _dyld_image_count is thread-unsafe. We need to register callbacks for | ||
| 112 | // adding and removing images which will invalidate the MemoryMappingLayout | ||
| 113 | // state. | ||
| 114 | data_.current_image = _dyld_image_count(); | ||
| 115 | data_.current_load_cmd_count = -1; | ||
| 116 | data_.current_load_cmd_addr = 0; | ||
| 117 | data_.current_magic = 0; | ||
| 118 | data_.current_filetype = 0; | ||
| 119 | data_.current_arch = kModuleArchUnknown; | ||
| 120 | internal_memset(data_.current_uuid, 0, kModuleUUIDSize); | ||
| 121 | } | ||
| 122 | |||
| 123 | // The dyld load address should be unchanged throughout process execution, | ||
| 124 | // and it is expensive to compute once many libraries have been loaded, | ||
| 125 | // so cache it here and do not reset. | ||
| 126 | static mach_header *dyld_hdr = 0; | ||
| 127 | static const char kDyldPath[] = "/usr/lib/dyld"; | ||
| 128 | static const int kDyldImageIdx = -1; | ||
| 129 | |||
| 130 | // static | ||
| 131 | void MemoryMappingLayout::CacheMemoryMappings() { | ||
| 132 | // No-op on Mac for now. | ||
| 133 | } | ||
| 134 | |||
| 135 | void MemoryMappingLayout::LoadFromCache() { | ||
| 136 | // No-op on Mac for now. | ||
| 137 | } | ||
| 138 | |||
| 139 | // _dyld_get_image_header() and related APIs don't report dyld itself. | ||
| 140 | // We work around this by manually recursing through the memory map | ||
| 141 | // until we hit a Mach header matching dyld instead. These recurse | ||
| 142 | // calls are expensive, but the first memory map generation occurs | ||
| 143 | // early in the process, when dyld is one of the only images loaded, | ||
| 144 | // so it will be hit after only a few iterations. | ||
| 145 | static mach_header *get_dyld_image_header() { | ||
| 146 | unsigned depth = 1; | ||
| 147 | vm_size_t size = 0; | ||
| 148 | vm_address_t address = 0; | ||
| 149 | kern_return_t err = KERN_SUCCESS; | ||
| 150 | mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; | ||
| 151 | |||
| 152 | while (true) { | ||
| 153 | struct vm_region_submap_info_64 info; | ||
| 154 | err = vm_region_recurse_64(mach_task_self(), &address, &size, &depth, | ||
| 155 | (vm_region_info_t)&info, &count); | ||
| 156 | if (err != KERN_SUCCESS) return nullptr; | ||
| 157 | |||
| 158 | if (size >= sizeof(mach_header) && info.protection & kProtectionRead) { | ||
| 159 | mach_header *hdr = (mach_header *)address; | ||
| 160 | if ((hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) && | ||
| 161 | hdr->filetype == MH_DYLINKER) { | ||
| 162 | return hdr; | ||
| 163 | } | ||
| 164 | } | ||
| 165 | address += size; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | const mach_header *get_dyld_hdr() { | ||
| 170 | if (!dyld_hdr) dyld_hdr = get_dyld_image_header(); | ||
| 171 | |||
| 172 | return dyld_hdr; | ||
| 173 | } | ||
| 174 | |||
| 175 | // Next and NextSegmentLoad were inspired by base/sysinfo.cc in | ||
| 176 | // Google Perftools, https://github.com/gperftools/gperftools. | ||
| 177 | |||
| 178 | // NextSegmentLoad scans the current image for the next segment load command | ||
| 179 | // and returns the start and end addresses and file offset of the corresponding | ||
| 180 | // segment. | ||
| 181 | // Note that the segment addresses are not necessarily sorted. | ||
| 182 | template <u32 kLCSegment, typename SegmentCommand> | ||
| 183 | static bool NextSegmentLoad(MemoryMappedSegment *segment, | ||
| 184 | MemoryMappedSegmentData *seg_data, | ||
| 185 | MemoryMappingLayoutData *layout_data) { | ||
| 186 | const char *lc = layout_data->current_load_cmd_addr; | ||
| 187 | layout_data->current_load_cmd_addr += ((const load_command *)lc)->cmdsize; | ||
| 188 | if (((const load_command *)lc)->cmd == kLCSegment) { | ||
| 189 | const SegmentCommand* sc = (const SegmentCommand *)lc; | ||
| 190 | uptr base_virt_addr, addr_mask; | ||
| 191 | if (layout_data->current_image == kDyldImageIdx) { | ||
| 192 | base_virt_addr = (uptr)get_dyld_hdr(); | ||
| 193 | // vmaddr is masked with 0xfffff because on macOS versions < 10.12, | ||
| 194 | // it contains an absolute address rather than an offset for dyld. | ||
| 195 | // To make matters even more complicated, this absolute address | ||
| 196 | // isn't actually the absolute segment address, but the offset portion | ||
| 197 | // of the address is accurate when combined with the dyld base address, | ||
| 198 | // and the mask will give just this offset. | ||
| 199 | addr_mask = 0xfffff; | ||
| 200 | } else { | ||
| 201 | base_virt_addr = | ||
| 202 | (uptr)_dyld_get_image_vmaddr_slide(layout_data->current_image); | ||
| 203 | addr_mask = ~0; | ||
| 204 | } | ||
| 205 | |||
| 206 | segment->start = (sc->vmaddr & addr_mask) + base_virt_addr; | ||
| 207 | segment->end = segment->start + sc->vmsize; | ||
| 208 | // Most callers don't need section information, so only fill this struct | ||
| 209 | // when required. | ||
| 210 | if (seg_data) { | ||
| 211 | seg_data->nsects = sc->nsects; | ||
| 212 | seg_data->current_load_cmd_addr = | ||
| 213 | (const char *)lc + sizeof(SegmentCommand); | ||
| 214 | seg_data->lc_type = kLCSegment; | ||
| 215 | seg_data->base_virt_addr = base_virt_addr; | ||
| 216 | seg_data->addr_mask = addr_mask; | ||
| 217 | internal_strncpy(seg_data->name, sc->segname, | ||
| 218 | ARRAY_SIZE(seg_data->name)); | ||
| 219 | } | ||
| 220 | |||
| 221 | // Return the initial protection. | ||
| 222 | segment->protection = sc->initprot; | ||
| 223 | segment->offset = (layout_data->current_filetype == | ||
| 224 | /*MH_EXECUTE*/ 0x2) | ||
| 225 | ? sc->vmaddr | ||
| 226 | : sc->fileoff; | ||
| 227 | if (segment->filename) { | ||
| 228 | const char *src = (layout_data->current_image == kDyldImageIdx) | ||
| 229 | ? kDyldPath | ||
| 230 | : _dyld_get_image_name(layout_data->current_image); | ||
| 231 | internal_strncpy(segment->filename, src, segment->filename_size); | ||
| 232 | } | ||
| 233 | segment->arch = layout_data->current_arch; | ||
| 234 | internal_memcpy(segment->uuid, layout_data->current_uuid, kModuleUUIDSize); | ||
| 235 | return true; | ||
| 236 | } | ||
| 237 | return false; | ||
| 238 | } | ||
| 239 | |||
| 240 | ModuleArch ModuleArchFromCpuType(cpu_type_t cputype, cpu_subtype_t cpusubtype) { | ||
| 241 | cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK; | ||
| 242 | switch (cputype) { | ||
| 243 | case CPU_TYPE_I386: | ||
| 244 | return kModuleArchI386; | ||
| 245 | case CPU_TYPE_X86_64: | ||
| 246 | if (cpusubtype == CPU_SUBTYPE_X86_64_ALL) return kModuleArchX86_64; | ||
| 247 | if (cpusubtype == CPU_SUBTYPE_X86_64_H) return kModuleArchX86_64H; | ||
| 248 | CHECK(0 && "Invalid subtype of x86_64"); | ||
| 249 | return kModuleArchUnknown; | ||
| 250 | case CPU_TYPE_ARM: | ||
| 251 | if (cpusubtype == CPU_SUBTYPE_ARM_V6) return kModuleArchARMV6; | ||
| 252 | if (cpusubtype == CPU_SUBTYPE_ARM_V7) return kModuleArchARMV7; | ||
| 253 | if (cpusubtype == CPU_SUBTYPE_ARM_V7S) return kModuleArchARMV7S; | ||
| 254 | if (cpusubtype == CPU_SUBTYPE_ARM_V7K) return kModuleArchARMV7K; | ||
| 255 | CHECK(0 && "Invalid subtype of ARM"); | ||
| 256 | return kModuleArchUnknown; | ||
| 257 | case CPU_TYPE_ARM64: | ||
| 258 | return kModuleArchARM64; | ||
| 259 | default: | ||
| 260 | CHECK(0 && "Invalid CPU type"); | ||
| 261 | return kModuleArchUnknown; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | static const load_command *NextCommand(const load_command *lc) { | ||
| 266 | return (const load_command *)((const char *)lc + lc->cmdsize); | ||
| 267 | } | ||
| 268 | |||
| 269 | static void FindUUID(const load_command *first_lc, u8 *uuid_output) { | ||
| 270 | for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) { | ||
| 271 | if (lc->cmd != LC_UUID) continue; | ||
| 272 | |||
| 273 | const uuid_command *uuid_lc = (const uuid_command *)lc; | ||
| 274 | const uint8_t *uuid = &uuid_lc->uuid[0]; | ||
| 275 | internal_memcpy(uuid_output, uuid, kModuleUUIDSize); | ||
| 276 | return; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | static bool IsModuleInstrumented(const load_command *first_lc) { | ||
| 281 | for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) { | ||
| 282 | if (lc->cmd != LC_LOAD_DYLIB) continue; | ||
| 283 | |||
| 284 | const dylib_command *dylib_lc = (const dylib_command *)lc; | ||
| 285 | uint32_t dylib_name_offset = dylib_lc->dylib.name.offset; | ||
| 286 | const char *dylib_name = ((const char *)dylib_lc) + dylib_name_offset; | ||
| 287 | dylib_name = StripModuleName(dylib_name); | ||
| 288 | if (dylib_name != 0 && (internal_strstr(dylib_name, "libclang_rt."))) { | ||
| 289 | return true; | ||
| 290 | } | ||
| 291 | } | ||
| 292 | return false; | ||
| 293 | } | ||
| 294 | |||
| 295 | bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { | ||
| 296 | for (; data_.current_image >= kDyldImageIdx; data_.current_image--) { | ||
| 297 | const mach_header *hdr = (data_.current_image == kDyldImageIdx) | ||
| 298 | ? get_dyld_hdr() | ||
| 299 | : _dyld_get_image_header(data_.current_image); | ||
| 300 | if (!hdr) continue; | ||
| 301 | if (data_.current_load_cmd_count < 0) { | ||
| 302 | // Set up for this image; | ||
| 303 | data_.current_load_cmd_count = hdr->ncmds; | ||
| 304 | data_.current_magic = hdr->magic; | ||
| 305 | data_.current_filetype = hdr->filetype; | ||
| 306 | data_.current_arch = ModuleArchFromCpuType(hdr->cputype, hdr->cpusubtype); | ||
| 307 | switch (data_.current_magic) { | ||
| 308 | #ifdef MH_MAGIC_64 | ||
| 309 | case MH_MAGIC_64: { | ||
| 310 | data_.current_load_cmd_addr = | ||
| 311 | (const char *)hdr + sizeof(mach_header_64); | ||
| 312 | break; | ||
| 313 | } | ||
| 314 | #endif | ||
| 315 | case MH_MAGIC: { | ||
| 316 | data_.current_load_cmd_addr = (const char *)hdr + sizeof(mach_header); | ||
| 317 | break; | ||
| 318 | } | ||
| 319 | default: { | ||
| 320 | continue; | ||
| 321 | } | ||
| 322 | } | ||
| 323 | FindUUID((const load_command *)data_.current_load_cmd_addr, | ||
| 324 | data_.current_uuid); | ||
| 325 | data_.current_instrumented = IsModuleInstrumented( | ||
| 326 | (const load_command *)data_.current_load_cmd_addr); | ||
| 327 | } | ||
| 328 | |||
| 329 | for (; data_.current_load_cmd_count >= 0; data_.current_load_cmd_count--) { | ||
| 330 | switch (data_.current_magic) { | ||
| 331 | // data_.current_magic may be only one of MH_MAGIC, MH_MAGIC_64. | ||
| 332 | #ifdef MH_MAGIC_64 | ||
| 333 | case MH_MAGIC_64: { | ||
| 334 | if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>( | ||
| 335 | segment, segment->data_, &data_)) | ||
| 336 | return true; | ||
| 337 | break; | ||
| 338 | } | ||
| 339 | #endif | ||
| 340 | case MH_MAGIC: { | ||
| 341 | if (NextSegmentLoad<LC_SEGMENT, struct segment_command>( | ||
| 342 | segment, segment->data_, &data_)) | ||
| 343 | return true; | ||
| 344 | break; | ||
| 345 | } | ||
| 346 | } | ||
| 347 | } | ||
| 348 | // If we get here, no more load_cmd's in this image talk about | ||
| 349 | // segments. Go on to the next image. | ||
| 350 | } | ||
| 351 | return false; | ||
| 352 | } | ||
| 353 | |||
| 354 | void MemoryMappingLayout::DumpListOfModules( | ||
| 355 | InternalMmapVectorNoCtor<LoadedModule> *modules) { | ||
| 356 | Reset(); | ||
| 357 | InternalScopedString module_name(kMaxPathLength); | ||
| 358 | MemoryMappedSegment segment(module_name.data(), kMaxPathLength); | ||
| 359 | MemoryMappedSegmentData data; | ||
| 360 | segment.data_ = &data; | ||
| 361 | while (Next(&segment)) { | ||
| 362 | if (segment.filename[0] == '\0') continue; | ||
| 363 | LoadedModule *cur_module = nullptr; | ||
| 364 | if (!modules->empty() && | ||
| 365 | 0 == internal_strcmp(segment.filename, modules->back().full_name())) { | ||
| 366 | cur_module = &modules->back(); | ||
| 367 | } else { | ||
| 368 | modules->push_back(LoadedModule()); | ||
| 369 | cur_module = &modules->back(); | ||
| 370 | cur_module->set(segment.filename, segment.start, segment.arch, | ||
| 371 | segment.uuid, data_.current_instrumented); | ||
| 372 | } | ||
| 373 | segment.AddAddressRanges(cur_module); | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | } // namespace __sanitizer | ||
| 378 | |||
| 379 | #endif // SANITIZER_MAC | ||
lib/tsan/sanitizer_common/sanitizer_procmaps_solaris.cpp created+67| ... | @@ -0,0 +1,67 @@ | ||
| 1 | //===-- sanitizer_procmaps_solaris.cpp ------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Information about the process mappings (Solaris-specific parts). | ||
| 10 | //===----------------------------------------------------------------------===// | ||
| 11 | |||
| 12 | #include "sanitizer_platform.h" | ||
| 13 | #if SANITIZER_SOLARIS | ||
| 14 | #include "sanitizer_common.h" | ||
| 15 | #include "sanitizer_procmaps.h" | ||
| 16 | |||
| 17 | // Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment. | ||
| 18 | #undef _FILE_OFFSET_BITS | ||
| 19 | #include <procfs.h> | ||
| 20 | #include <limits.h> | ||
| 21 | |||
| 22 | namespace __sanitizer { | ||
| 23 | |||
| 24 | void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { | ||
| 25 | if (!ReadFileToBuffer("/proc/self/xmap", &proc_maps->data, | ||
| 26 | &proc_maps->mmaped_size, &proc_maps->len)) { | ||
| 27 | proc_maps->data = nullptr; | ||
| 28 | proc_maps->mmaped_size = 0; | ||
| 29 | proc_maps->len = 0; | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { | ||
| 34 | if (Error()) return false; // simulate empty maps | ||
| 35 | char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; | ||
| 36 | if (data_.current >= last) return false; | ||
| 37 | |||
| 38 | prxmap_t *xmapentry = (prxmap_t*)data_.current; | ||
| 39 | |||
| 40 | segment->start = (uptr)xmapentry->pr_vaddr; | ||
| 41 | segment->end = (uptr)(xmapentry->pr_vaddr + xmapentry->pr_size); | ||
| 42 | segment->offset = (uptr)xmapentry->pr_offset; | ||
| 43 | |||
| 44 | segment->protection = 0; | ||
| 45 | if ((xmapentry->pr_mflags & MA_READ) != 0) | ||
| 46 | segment->protection |= kProtectionRead; | ||
| 47 | if ((xmapentry->pr_mflags & MA_WRITE) != 0) | ||
| 48 | segment->protection |= kProtectionWrite; | ||
| 49 | if ((xmapentry->pr_mflags & MA_EXEC) != 0) | ||
| 50 | segment->protection |= kProtectionExecute; | ||
| 51 | |||
| 52 | if (segment->filename != NULL && segment->filename_size > 0) { | ||
| 53 | char proc_path[PATH_MAX + 1]; | ||
| 54 | |||
| 55 | internal_snprintf(proc_path, sizeof(proc_path), "/proc/self/path/%s", | ||
| 56 | xmapentry->pr_mapname); | ||
| 57 | internal_readlink(proc_path, segment->filename, segment->filename_size); | ||
| 58 | } | ||
| 59 | |||
| 60 | data_.current += sizeof(prxmap_t); | ||
| 61 | |||
| 62 | return true; | ||
| 63 | } | ||
| 64 | |||
| 65 | } // namespace __sanitizer | ||
| 66 | |||
| 67 | #endif // SANITIZER_SOLARIS | ||
lib/tsan/sanitizer_common/sanitizer_ptrauth.h created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | //===-- sanitizer_ptrauth.h -------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | |||
| 9 | #ifndef SANITIZER_PTRAUTH_H | ||
| 10 | #define SANITIZER_PTRAUTH_H | ||
| 11 | |||
| 12 | #if __has_feature(ptrauth_calls) | ||
| 13 | #include <ptrauth.h> | ||
| 14 | #else | ||
| 15 | // Copied from <ptrauth.h> | ||
| 16 | #define ptrauth_strip(__value, __key) __value | ||
| 17 | #define ptrauth_auth_data(__value, __old_key, __old_data) __value | ||
| 18 | #define ptrauth_string_discriminator(__string) ((int)0) | ||
| 19 | #endif | ||
| 20 | |||
| 21 | #endif // SANITIZER_PTRAUTH_H | ||
lib/tsan/sanitizer_common/sanitizer_quarantine.h created+317| ... | @@ -0,0 +1,317 @@ | ||
| 1 | //===-- sanitizer_quarantine.h ----------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Memory quarantine for AddressSanitizer and potentially other tools. | ||
| 10 | // Quarantine caches some specified amount of memory in per-thread caches, | ||
| 11 | // then evicts to global FIFO queue. When the queue reaches specified threshold, | ||
| 12 | // oldest memory is recycled. | ||
| 13 | // | ||
| 14 | //===----------------------------------------------------------------------===// | ||
| 15 | |||
| 16 | #ifndef SANITIZER_QUARANTINE_H | ||
| 17 | #define SANITIZER_QUARANTINE_H | ||
| 18 | |||
| 19 | #include "sanitizer_internal_defs.h" | ||
| 20 | #include "sanitizer_mutex.h" | ||
| 21 | #include "sanitizer_list.h" | ||
| 22 | |||
| 23 | namespace __sanitizer { | ||
| 24 | |||
| 25 | template<typename Node> class QuarantineCache; | ||
| 26 | |||
| 27 | struct QuarantineBatch { | ||
| 28 | static const uptr kSize = 1021; | ||
| 29 | QuarantineBatch *next; | ||
| 30 | uptr size; | ||
| 31 | uptr count; | ||
| 32 | void *batch[kSize]; | ||
| 33 | |||
| 34 | void init(void *ptr, uptr size) { | ||
| 35 | count = 1; | ||
| 36 | batch[0] = ptr; | ||
| 37 | this->size = size + sizeof(QuarantineBatch); // Account for the batch size. | ||
| 38 | } | ||
| 39 | |||
| 40 | // The total size of quarantined nodes recorded in this batch. | ||
| 41 | uptr quarantined_size() const { | ||
| 42 | return size - sizeof(QuarantineBatch); | ||
| 43 | } | ||
| 44 | |||
| 45 | void push_back(void *ptr, uptr size) { | ||
| 46 | CHECK_LT(count, kSize); | ||
| 47 | batch[count++] = ptr; | ||
| 48 | this->size += size; | ||
| 49 | } | ||
| 50 | |||
| 51 | bool can_merge(const QuarantineBatch* const from) const { | ||
| 52 | return count + from->count <= kSize; | ||
| 53 | } | ||
| 54 | |||
| 55 | void merge(QuarantineBatch* const from) { | ||
| 56 | CHECK_LE(count + from->count, kSize); | ||
| 57 | CHECK_GE(size, sizeof(QuarantineBatch)); | ||
| 58 | |||
| 59 | for (uptr i = 0; i < from->count; ++i) | ||
| 60 | batch[count + i] = from->batch[i]; | ||
| 61 | count += from->count; | ||
| 62 | size += from->quarantined_size(); | ||
| 63 | |||
| 64 | from->count = 0; | ||
| 65 | from->size = sizeof(QuarantineBatch); | ||
| 66 | } | ||
| 67 | }; | ||
| 68 | |||
| 69 | COMPILER_CHECK(sizeof(QuarantineBatch) <= (1 << 13)); // 8Kb. | ||
| 70 | |||
| 71 | // The callback interface is: | ||
| 72 | // void Callback::Recycle(Node *ptr); | ||
| 73 | // void *cb.Allocate(uptr size); | ||
| 74 | // void cb.Deallocate(void *ptr); | ||
| 75 | template<typename Callback, typename Node> | ||
| 76 | class Quarantine { | ||
| 77 | public: | ||
| 78 | typedef QuarantineCache<Callback> Cache; | ||
| 79 | |||
| 80 | explicit Quarantine(LinkerInitialized) | ||
| 81 | : cache_(LINKER_INITIALIZED) { | ||
| 82 | } | ||
| 83 | |||
| 84 | void Init(uptr size, uptr cache_size) { | ||
| 85 | // Thread local quarantine size can be zero only when global quarantine size | ||
| 86 | // is zero (it allows us to perform just one atomic read per Put() call). | ||
| 87 | CHECK((size == 0 && cache_size == 0) || cache_size != 0); | ||
| 88 | |||
| 89 | atomic_store_relaxed(&max_size_, size); | ||
| 90 | atomic_store_relaxed(&min_size_, size / 10 * 9); // 90% of max size. | ||
| 91 | atomic_store_relaxed(&max_cache_size_, cache_size); | ||
| 92 | |||
| 93 | cache_mutex_.Init(); | ||
| 94 | recycle_mutex_.Init(); | ||
| 95 | } | ||
| 96 | |||
| 97 | uptr GetSize() const { return atomic_load_relaxed(&max_size_); } | ||
| 98 | uptr GetCacheSize() const { | ||
| 99 | return atomic_load_relaxed(&max_cache_size_); | ||
| 100 | } | ||
| 101 | |||
| 102 | void Put(Cache *c, Callback cb, Node *ptr, uptr size) { | ||
| 103 | uptr cache_size = GetCacheSize(); | ||
| 104 | if (cache_size) { | ||
| 105 | c->Enqueue(cb, ptr, size); | ||
| 106 | } else { | ||
| 107 | // GetCacheSize() == 0 only when GetSize() == 0 (see Init). | ||
| 108 | cb.Recycle(ptr); | ||
| 109 | } | ||
| 110 | // Check cache size anyway to accommodate for runtime cache_size change. | ||
| 111 | if (c->Size() > cache_size) | ||
| 112 | Drain(c, cb); | ||
| 113 | } | ||
| 114 | |||
| 115 | void NOINLINE Drain(Cache *c, Callback cb) { | ||
| 116 | { | ||
| 117 | SpinMutexLock l(&cache_mutex_); | ||
| 118 | cache_.Transfer(c); | ||
| 119 | } | ||
| 120 | if (cache_.Size() > GetSize() && recycle_mutex_.TryLock()) | ||
| 121 | Recycle(atomic_load_relaxed(&min_size_), cb); | ||
| 122 | } | ||
| 123 | |||
| 124 | void NOINLINE DrainAndRecycle(Cache *c, Callback cb) { | ||
| 125 | { | ||
| 126 | SpinMutexLock l(&cache_mutex_); | ||
| 127 | cache_.Transfer(c); | ||
| 128 | } | ||
| 129 | recycle_mutex_.Lock(); | ||
| 130 | Recycle(0, cb); | ||
| 131 | } | ||
| 132 | |||
| 133 | void PrintStats() const { | ||
| 134 | // It assumes that the world is stopped, just as the allocator's PrintStats. | ||
| 135 | Printf("Quarantine limits: global: %zdMb; thread local: %zdKb\n", | ||
| 136 | GetSize() >> 20, GetCacheSize() >> 10); | ||
| 137 | cache_.PrintStats(); | ||
| 138 | } | ||
| 139 | |||
| 140 | private: | ||
| 141 | // Read-only data. | ||
| 142 | char pad0_[kCacheLineSize]; | ||
| 143 | atomic_uintptr_t max_size_; | ||
| 144 | atomic_uintptr_t min_size_; | ||
| 145 | atomic_uintptr_t max_cache_size_; | ||
| 146 | char pad1_[kCacheLineSize]; | ||
| 147 | StaticSpinMutex cache_mutex_; | ||
| 148 | StaticSpinMutex recycle_mutex_; | ||
| 149 | Cache cache_; | ||
| 150 | char pad2_[kCacheLineSize]; | ||
| 151 | |||
| 152 | void NOINLINE Recycle(uptr min_size, Callback cb) { | ||
| 153 | Cache tmp; | ||
| 154 | { | ||
| 155 | SpinMutexLock l(&cache_mutex_); | ||
| 156 | // Go over the batches and merge partially filled ones to | ||
| 157 | // save some memory, otherwise batches themselves (since the memory used | ||
| 158 | // by them is counted against quarantine limit) can overcome the actual | ||
| 159 | // user's quarantined chunks, which diminishes the purpose of the | ||
| 160 | // quarantine. | ||
| 161 | uptr cache_size = cache_.Size(); | ||
| 162 | uptr overhead_size = cache_.OverheadSize(); | ||
| 163 | CHECK_GE(cache_size, overhead_size); | ||
| 164 | // Do the merge only when overhead exceeds this predefined limit (might | ||
| 165 | // require some tuning). It saves us merge attempt when the batch list | ||
| 166 | // quarantine is unlikely to contain batches suitable for merge. | ||
| 167 | const uptr kOverheadThresholdPercents = 100; | ||
| 168 | if (cache_size > overhead_size && | ||
| 169 | overhead_size * (100 + kOverheadThresholdPercents) > | ||
| 170 | cache_size * kOverheadThresholdPercents) { | ||
| 171 | cache_.MergeBatches(&tmp); | ||
| 172 | } | ||
| 173 | // Extract enough chunks from the quarantine to get below the max | ||
| 174 | // quarantine size and leave some leeway for the newly quarantined chunks. | ||
| 175 | while (cache_.Size() > min_size) { | ||
| 176 | tmp.EnqueueBatch(cache_.DequeueBatch()); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | recycle_mutex_.Unlock(); | ||
| 180 | DoRecycle(&tmp, cb); | ||
| 181 | } | ||
| 182 | |||
| 183 | void NOINLINE DoRecycle(Cache *c, Callback cb) { | ||
| 184 | while (QuarantineBatch *b = c->DequeueBatch()) { | ||
| 185 | const uptr kPrefetch = 16; | ||
| 186 | CHECK(kPrefetch <= ARRAY_SIZE(b->batch)); | ||
| 187 | for (uptr i = 0; i < kPrefetch; i++) | ||
| 188 | PREFETCH(b->batch[i]); | ||
| 189 | for (uptr i = 0, count = b->count; i < count; i++) { | ||
| 190 | if (i + kPrefetch < count) | ||
| 191 | PREFETCH(b->batch[i + kPrefetch]); | ||
| 192 | cb.Recycle((Node*)b->batch[i]); | ||
| 193 | } | ||
| 194 | cb.Deallocate(b); | ||
| 195 | } | ||
| 196 | } | ||
| 197 | }; | ||
| 198 | |||
| 199 | // Per-thread cache of memory blocks. | ||
| 200 | template<typename Callback> | ||
| 201 | class QuarantineCache { | ||
| 202 | public: | ||
| 203 | explicit QuarantineCache(LinkerInitialized) { | ||
| 204 | } | ||
| 205 | |||
| 206 | QuarantineCache() | ||
| 207 | : size_() { | ||
| 208 | list_.clear(); | ||
| 209 | } | ||
| 210 | |||
| 211 | // Total memory used, including internal accounting. | ||
| 212 | uptr Size() const { | ||
| 213 | return atomic_load_relaxed(&size_); | ||
| 214 | } | ||
| 215 | |||
| 216 | // Memory used for internal accounting. | ||
| 217 | uptr OverheadSize() const { | ||
| 218 | return list_.size() * sizeof(QuarantineBatch); | ||
| 219 | } | ||
| 220 | |||
| 221 | void Enqueue(Callback cb, void *ptr, uptr size) { | ||
| 222 | if (list_.empty() || list_.back()->count == QuarantineBatch::kSize) { | ||
| 223 | QuarantineBatch *b = (QuarantineBatch *)cb.Allocate(sizeof(*b)); | ||
| 224 | CHECK(b); | ||
| 225 | b->init(ptr, size); | ||
| 226 | EnqueueBatch(b); | ||
| 227 | } else { | ||
| 228 | list_.back()->push_back(ptr, size); | ||
| 229 | SizeAdd(size); | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | void Transfer(QuarantineCache *from_cache) { | ||
| 234 | list_.append_back(&from_cache->list_); | ||
| 235 | SizeAdd(from_cache->Size()); | ||
| 236 | |||
| 237 | atomic_store_relaxed(&from_cache->size_, 0); | ||
| 238 | } | ||
| 239 | |||
| 240 | void EnqueueBatch(QuarantineBatch *b) { | ||
| 241 | list_.push_back(b); | ||
| 242 | SizeAdd(b->size); | ||
| 243 | } | ||
| 244 | |||
| 245 | QuarantineBatch *DequeueBatch() { | ||
| 246 | if (list_.empty()) | ||
| 247 | return nullptr; | ||
| 248 | QuarantineBatch *b = list_.front(); | ||
| 249 | list_.pop_front(); | ||
| 250 | SizeSub(b->size); | ||
| 251 | return b; | ||
| 252 | } | ||
| 253 | |||
| 254 | void MergeBatches(QuarantineCache *to_deallocate) { | ||
| 255 | uptr extracted_size = 0; | ||
| 256 | QuarantineBatch *current = list_.front(); | ||
| 257 | while (current && current->next) { | ||
| 258 | if (current->can_merge(current->next)) { | ||
| 259 | QuarantineBatch *extracted = current->next; | ||
| 260 | // Move all the chunks into the current batch. | ||
| 261 | current->merge(extracted); | ||
| 262 | CHECK_EQ(extracted->count, 0); | ||
| 263 | CHECK_EQ(extracted->size, sizeof(QuarantineBatch)); | ||
| 264 | // Remove the next batch from the list and account for its size. | ||
| 265 | list_.extract(current, extracted); | ||
| 266 | extracted_size += extracted->size; | ||
| 267 | // Add it to deallocation list. | ||
| 268 | to_deallocate->EnqueueBatch(extracted); | ||
| 269 | } else { | ||
| 270 | current = current->next; | ||
| 271 | } | ||
| 272 | } | ||
| 273 | SizeSub(extracted_size); | ||
| 274 | } | ||
| 275 | |||
| 276 | void PrintStats() const { | ||
| 277 | uptr batch_count = 0; | ||
| 278 | uptr total_overhead_bytes = 0; | ||
| 279 | uptr total_bytes = 0; | ||
| 280 | uptr total_quarantine_chunks = 0; | ||
| 281 | for (List::ConstIterator it = list_.begin(); it != list_.end(); ++it) { | ||
| 282 | batch_count++; | ||
| 283 | total_bytes += (*it).size; | ||
| 284 | total_overhead_bytes += (*it).size - (*it).quarantined_size(); | ||
| 285 | total_quarantine_chunks += (*it).count; | ||
| 286 | } | ||
| 287 | uptr quarantine_chunks_capacity = batch_count * QuarantineBatch::kSize; | ||
| 288 | int chunks_usage_percent = quarantine_chunks_capacity == 0 ? | ||
| 289 | 0 : total_quarantine_chunks * 100 / quarantine_chunks_capacity; | ||
| 290 | uptr total_quarantined_bytes = total_bytes - total_overhead_bytes; | ||
| 291 | int memory_overhead_percent = total_quarantined_bytes == 0 ? | ||
| 292 | 0 : total_overhead_bytes * 100 / total_quarantined_bytes; | ||
| 293 | Printf("Global quarantine stats: batches: %zd; bytes: %zd (user: %zd); " | ||
| 294 | "chunks: %zd (capacity: %zd); %d%% chunks used; %d%% memory overhead" | ||
| 295 | "\n", | ||
| 296 | batch_count, total_bytes, total_quarantined_bytes, | ||
| 297 | total_quarantine_chunks, quarantine_chunks_capacity, | ||
| 298 | chunks_usage_percent, memory_overhead_percent); | ||
| 299 | } | ||
| 300 | |||
| 301 | private: | ||
| 302 | typedef IntrusiveList<QuarantineBatch> List; | ||
| 303 | |||
| 304 | List list_; | ||
| 305 | atomic_uintptr_t size_; | ||
| 306 | |||
| 307 | void SizeAdd(uptr add) { | ||
| 308 | atomic_store_relaxed(&size_, Size() + add); | ||
| 309 | } | ||
| 310 | void SizeSub(uptr sub) { | ||
| 311 | atomic_store_relaxed(&size_, Size() - sub); | ||
| 312 | } | ||
| 313 | }; | ||
| 314 | |||
| 315 | } // namespace __sanitizer | ||
| 316 | |||
| 317 | #endif // SANITIZER_QUARANTINE_H | ||
lib/tsan/sanitizer_common/sanitizer_report_decorator.h created+48| ... | @@ -0,0 +1,48 @@ | ||
| 1 | //===-- sanitizer_report_decorator.h ----------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Tags to decorate the sanitizer reports. | ||
| 10 | // Currently supported tags: | ||
| 11 | // * None. | ||
| 12 | // * ANSI color sequences. | ||
| 13 | // | ||
| 14 | //===----------------------------------------------------------------------===// | ||
| 15 | |||
| 16 | #ifndef SANITIZER_REPORT_DECORATOR_H | ||
| 17 | #define SANITIZER_REPORT_DECORATOR_H | ||
| 18 | |||
| 19 | #include "sanitizer_common.h" | ||
| 20 | |||
| 21 | namespace __sanitizer { | ||
| 22 | class SanitizerCommonDecorator { | ||
| 23 | // FIXME: This is not portable. It assumes the special strings are printed to | ||
| 24 | // stdout, which is not the case on Windows (see SetConsoleTextAttribute()). | ||
| 25 | public: | ||
| 26 | SanitizerCommonDecorator() : ansi_(ColorizeReports()) {} | ||
| 27 | const char *Bold() const { return ansi_ ? "\033[1m" : ""; } | ||
| 28 | const char *Default() const { return ansi_ ? "\033[1m\033[0m" : ""; } | ||
| 29 | const char *Warning() const { return Red(); } | ||
| 30 | const char *Error() const { return Red(); } | ||
| 31 | const char *MemoryByte() const { return Magenta(); } | ||
| 32 | |||
| 33 | protected: | ||
| 34 | const char *Black() const { return ansi_ ? "\033[1m\033[30m" : ""; } | ||
| 35 | const char *Red() const { return ansi_ ? "\033[1m\033[31m" : ""; } | ||
| 36 | const char *Green() const { return ansi_ ? "\033[1m\033[32m" : ""; } | ||
| 37 | const char *Yellow() const { return ansi_ ? "\033[1m\033[33m" : ""; } | ||
| 38 | const char *Blue() const { return ansi_ ? "\033[1m\033[34m" : ""; } | ||
| 39 | const char *Magenta() const { return ansi_ ? "\033[1m\033[35m" : ""; } | ||
| 40 | const char *Cyan() const { return ansi_ ? "\033[1m\033[36m" : ""; } | ||
| 41 | const char *White() const { return ansi_ ? "\033[1m\033[37m" : ""; } | ||
| 42 | private: | ||
| 43 | bool ansi_; | ||
| 44 | }; | ||
| 45 | |||
| 46 | } // namespace __sanitizer | ||
| 47 | |||
| 48 | #endif // SANITIZER_REPORT_DECORATOR_H | ||
lib/tsan/sanitizer_common/sanitizer_ring_buffer.h created+161| ... | @@ -0,0 +1,161 @@ | ||
| 1 | //===-- sanitizer_ring_buffer.h ---------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Simple ring buffer. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_RING_BUFFER_H | ||
| 13 | #define SANITIZER_RING_BUFFER_H | ||
| 14 | |||
| 15 | #include "sanitizer_common.h" | ||
| 16 | |||
| 17 | namespace __sanitizer { | ||
| 18 | // RingBuffer<T>: fixed-size ring buffer optimized for speed of push(). | ||
| 19 | // T should be a POD type and sizeof(T) should be divisible by sizeof(void*). | ||
| 20 | // At creation, all elements are zero. | ||
| 21 | template<class T> | ||
| 22 | class RingBuffer { | ||
| 23 | public: | ||
| 24 | COMPILER_CHECK(sizeof(T) % sizeof(void *) == 0); | ||
| 25 | static RingBuffer *New(uptr Size) { | ||
| 26 | void *Ptr = MmapOrDie(SizeInBytes(Size), "RingBuffer"); | ||
| 27 | RingBuffer *RB = reinterpret_cast<RingBuffer*>(Ptr); | ||
| 28 | uptr End = reinterpret_cast<uptr>(Ptr) + SizeInBytes(Size); | ||
| 29 | RB->last_ = RB->next_ = reinterpret_cast<T*>(End - sizeof(T)); | ||
| 30 | return RB; | ||
| 31 | } | ||
| 32 | void Delete() { | ||
| 33 | UnmapOrDie(this, SizeInBytes(size())); | ||
| 34 | } | ||
| 35 | uptr size() const { | ||
| 36 | return last_ + 1 - | ||
| 37 | reinterpret_cast<T *>(reinterpret_cast<uptr>(this) + | ||
| 38 | 2 * sizeof(T *)); | ||
| 39 | } | ||
| 40 | |||
| 41 | static uptr SizeInBytes(uptr Size) { | ||
| 42 | return Size * sizeof(T) + 2 * sizeof(T*); | ||
| 43 | } | ||
| 44 | |||
| 45 | uptr SizeInBytes() { return SizeInBytes(size()); } | ||
| 46 | |||
| 47 | void push(T t) { | ||
| 48 | *next_ = t; | ||
| 49 | next_--; | ||
| 50 | // The condition below works only if sizeof(T) is divisible by sizeof(T*). | ||
| 51 | if (next_ <= reinterpret_cast<T*>(&next_)) | ||
| 52 | next_ = last_; | ||
| 53 | } | ||
| 54 | |||
| 55 | T operator[](uptr Idx) const { | ||
| 56 | CHECK_LT(Idx, size()); | ||
| 57 | sptr IdxNext = Idx + 1; | ||
| 58 | if (IdxNext > last_ - next_) | ||
| 59 | IdxNext -= size(); | ||
| 60 | return next_[IdxNext]; | ||
| 61 | } | ||
| 62 | |||
| 63 | private: | ||
| 64 | RingBuffer() {} | ||
| 65 | ~RingBuffer() {} | ||
| 66 | RingBuffer(const RingBuffer&) = delete; | ||
| 67 | |||
| 68 | // Data layout: | ||
| 69 | // LNDDDDDDDD | ||
| 70 | // D: data elements. | ||
| 71 | // L: last_, always points to the last data element. | ||
| 72 | // N: next_, initially equals to last_, is decremented on every push, | ||
| 73 | // wraps around if it's less or equal than its own address. | ||
| 74 | T *last_; | ||
| 75 | T *next_; | ||
| 76 | T data_[1]; // flexible array. | ||
| 77 | }; | ||
| 78 | |||
| 79 | // A ring buffer with externally provided storage that encodes its state in 8 | ||
| 80 | // bytes. Has significant constraints on size and alignment of storage. | ||
| 81 | // See a comment in hwasan/hwasan_thread_list.h for the motivation behind this. | ||
| 82 | #if SANITIZER_WORDSIZE == 64 | ||
| 83 | template <class T> | ||
| 84 | class CompactRingBuffer { | ||
| 85 | // Top byte of long_ stores the buffer size in pages. | ||
| 86 | // Lower bytes store the address of the next buffer element. | ||
| 87 | static constexpr int kPageSizeBits = 12; | ||
| 88 | static constexpr int kSizeShift = 56; | ||
| 89 | static constexpr uptr kNextMask = (1ULL << kSizeShift) - 1; | ||
| 90 | |||
| 91 | uptr GetStorageSize() const { return (long_ >> kSizeShift) << kPageSizeBits; } | ||
| 92 | |||
| 93 | void Init(void *storage, uptr size) { | ||
| 94 | CHECK_EQ(sizeof(CompactRingBuffer<T>), sizeof(void *)); | ||
| 95 | CHECK(IsPowerOfTwo(size)); | ||
| 96 | CHECK_GE(size, 1 << kPageSizeBits); | ||
| 97 | CHECK_LE(size, 128 << kPageSizeBits); | ||
| 98 | CHECK_EQ(size % 4096, 0); | ||
| 99 | CHECK_EQ(size % sizeof(T), 0); | ||
| 100 | CHECK_EQ((uptr)storage % (size * 2), 0); | ||
| 101 | long_ = (uptr)storage | ((size >> kPageSizeBits) << kSizeShift); | ||
| 102 | } | ||
| 103 | |||
| 104 | void SetNext(const T *next) { | ||
| 105 | long_ = (long_ & ~kNextMask) | (uptr)next; | ||
| 106 | } | ||
| 107 | |||
| 108 | public: | ||
| 109 | CompactRingBuffer(void *storage, uptr size) { | ||
| 110 | Init(storage, size); | ||
| 111 | } | ||
| 112 | |||
| 113 | // A copy constructor of sorts. | ||
| 114 | CompactRingBuffer(const CompactRingBuffer &other, void *storage) { | ||
| 115 | uptr size = other.GetStorageSize(); | ||
| 116 | internal_memcpy(storage, other.StartOfStorage(), size); | ||
| 117 | Init(storage, size); | ||
| 118 | uptr Idx = other.Next() - (const T *)other.StartOfStorage(); | ||
| 119 | SetNext((const T *)storage + Idx); | ||
| 120 | } | ||
| 121 | |||
| 122 | T *Next() const { return (T *)(long_ & kNextMask); } | ||
| 123 | |||
| 124 | void *StartOfStorage() const { | ||
| 125 | return (void *)((uptr)Next() & ~(GetStorageSize() - 1)); | ||
| 126 | } | ||
| 127 | |||
| 128 | void *EndOfStorage() const { | ||
| 129 | return (void *)((uptr)StartOfStorage() + GetStorageSize()); | ||
| 130 | } | ||
| 131 | |||
| 132 | uptr size() const { return GetStorageSize() / sizeof(T); } | ||
| 133 | |||
| 134 | void push(T t) { | ||
| 135 | T *next = Next(); | ||
| 136 | *next = t; | ||
| 137 | next++; | ||
| 138 | next = (T *)((uptr)next & ~GetStorageSize()); | ||
| 139 | SetNext(next); | ||
| 140 | } | ||
| 141 | |||
| 142 | const T &operator[](uptr Idx) const { | ||
| 143 | CHECK_LT(Idx, size()); | ||
| 144 | const T *Begin = (const T *)StartOfStorage(); | ||
| 145 | sptr StorageIdx = Next() - Begin; | ||
| 146 | StorageIdx -= (sptr)(Idx + 1); | ||
| 147 | if (StorageIdx < 0) | ||
| 148 | StorageIdx += size(); | ||
| 149 | return Begin[StorageIdx]; | ||
| 150 | } | ||
| 151 | |||
| 152 | public: | ||
| 153 | ~CompactRingBuffer() {} | ||
| 154 | CompactRingBuffer(const CompactRingBuffer &) = delete; | ||
| 155 | |||
| 156 | uptr long_; | ||
| 157 | }; | ||
| 158 | #endif | ||
| 159 | } // namespace __sanitizer | ||
| 160 | |||
| 161 | #endif // SANITIZER_RING_BUFFER_H | ||
lib/tsan/sanitizer_common/sanitizer_rtems.cpp created+283| ... | @@ -0,0 +1,283 @@ | ||
| 1 | //===-- sanitizer_rtems.cpp -----------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between various sanitizers' runtime libraries and | ||
| 10 | // implements RTEMS-specific functions. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_rtems.h" | ||
| 14 | #if SANITIZER_RTEMS | ||
| 15 | |||
| 16 | #define posix_memalign __real_posix_memalign | ||
| 17 | #define free __real_free | ||
| 18 | #define memset __real_memset | ||
| 19 | |||
| 20 | #include "sanitizer_file.h" | ||
| 21 | #include "sanitizer_symbolizer.h" | ||
| 22 | #include <errno.h> | ||
| 23 | #include <fcntl.h> | ||
| 24 | #include <pthread.h> | ||
| 25 | #include <sched.h> | ||
| 26 | #include <stdio.h> | ||
| 27 | #include <stdlib.h> | ||
| 28 | #include <string.h> | ||
| 29 | #include <unistd.h> | ||
| 30 | |||
| 31 | // There is no mmap on RTEMS. Use memalign, etc. | ||
| 32 | #define __mmap_alloc_aligned posix_memalign | ||
| 33 | #define __mmap_free free | ||
| 34 | #define __mmap_memset memset | ||
| 35 | |||
| 36 | namespace __sanitizer { | ||
| 37 | |||
| 38 | #include "sanitizer_syscall_generic.inc" | ||
| 39 | |||
| 40 | void NORETURN internal__exit(int exitcode) { | ||
| 41 | _exit(exitcode); | ||
| 42 | } | ||
| 43 | |||
| 44 | uptr internal_sched_yield() { | ||
| 45 | return sched_yield(); | ||
| 46 | } | ||
| 47 | |||
| 48 | uptr internal_getpid() { | ||
| 49 | return getpid(); | ||
| 50 | } | ||
| 51 | |||
| 52 | int internal_dlinfo(void *handle, int request, void *p) { | ||
| 53 | UNIMPLEMENTED(); | ||
| 54 | } | ||
| 55 | |||
| 56 | bool FileExists(const char *filename) { | ||
| 57 | struct stat st; | ||
| 58 | if (stat(filename, &st)) | ||
| 59 | return false; | ||
| 60 | // Sanity check: filename is a regular file. | ||
| 61 | return S_ISREG(st.st_mode); | ||
| 62 | } | ||
| 63 | |||
| 64 | uptr GetThreadSelf() { return static_cast<uptr>(pthread_self()); } | ||
| 65 | |||
| 66 | tid_t GetTid() { return GetThreadSelf(); } | ||
| 67 | |||
| 68 | void Abort() { abort(); } | ||
| 69 | |||
| 70 | int Atexit(void (*function)(void)) { return atexit(function); } | ||
| 71 | |||
| 72 | void SleepForSeconds(int seconds) { sleep(seconds); } | ||
| 73 | |||
| 74 | void SleepForMillis(int millis) { usleep(millis * 1000); } | ||
| 75 | |||
| 76 | bool SupportsColoredOutput(fd_t fd) { return false; } | ||
| 77 | |||
| 78 | void GetThreadStackTopAndBottom(bool at_initialization, | ||
| 79 | uptr *stack_top, uptr *stack_bottom) { | ||
| 80 | pthread_attr_t attr; | ||
| 81 | pthread_attr_init(&attr); | ||
| 82 | CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); | ||
| 83 | void *base = nullptr; | ||
| 84 | size_t size = 0; | ||
| 85 | CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0); | ||
| 86 | CHECK_EQ(pthread_attr_destroy(&attr), 0); | ||
| 87 | |||
| 88 | *stack_bottom = reinterpret_cast<uptr>(base); | ||
| 89 | *stack_top = *stack_bottom + size; | ||
| 90 | } | ||
| 91 | |||
| 92 | void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, | ||
| 93 | uptr *tls_addr, uptr *tls_size) { | ||
| 94 | uptr stack_top, stack_bottom; | ||
| 95 | GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); | ||
| 96 | *stk_addr = stack_bottom; | ||
| 97 | *stk_size = stack_top - stack_bottom; | ||
| 98 | *tls_addr = *tls_size = 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | void InitializePlatformEarly() {} | ||
| 102 | void MaybeReexec() {} | ||
| 103 | void CheckASLR() {} | ||
| 104 | void CheckMPROTECT() {} | ||
| 105 | void DisableCoreDumperIfNecessary() {} | ||
| 106 | void InstallDeadlySignalHandlers(SignalHandlerType handler) {} | ||
| 107 | void SetAlternateSignalStack() {} | ||
| 108 | void UnsetAlternateSignalStack() {} | ||
| 109 | void InitTlsSize() {} | ||
| 110 | |||
| 111 | void PrintModuleMap() {} | ||
| 112 | |||
| 113 | void SignalContext::DumpAllRegisters(void *context) {} | ||
| 114 | const char *DescribeSignalOrException(int signo) { UNIMPLEMENTED(); } | ||
| 115 | |||
| 116 | enum MutexState { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 }; | ||
| 117 | |||
| 118 | BlockingMutex::BlockingMutex() { | ||
| 119 | internal_memset(this, 0, sizeof(*this)); | ||
| 120 | } | ||
| 121 | |||
| 122 | void BlockingMutex::Lock() { | ||
| 123 | CHECK_EQ(owner_, 0); | ||
| 124 | atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_); | ||
| 125 | if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked) | ||
| 126 | return; | ||
| 127 | while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) { | ||
| 128 | internal_sched_yield(); | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | void BlockingMutex::Unlock() { | ||
| 133 | atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_); | ||
| 134 | u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release); | ||
| 135 | CHECK_NE(v, MtxUnlocked); | ||
| 136 | } | ||
| 137 | |||
| 138 | void BlockingMutex::CheckLocked() { | ||
| 139 | atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_); | ||
| 140 | CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed)); | ||
| 141 | } | ||
| 142 | |||
| 143 | uptr GetPageSize() { return getpagesize(); } | ||
| 144 | |||
| 145 | uptr GetMmapGranularity() { return GetPageSize(); } | ||
| 146 | |||
| 147 | uptr GetMaxVirtualAddress() { | ||
| 148 | return (1ULL << 32) - 1; // 0xffffffff | ||
| 149 | } | ||
| 150 | |||
| 151 | void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { | ||
| 152 | void* ptr = 0; | ||
| 153 | int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size); | ||
| 154 | if (UNLIKELY(res)) | ||
| 155 | ReportMmapFailureAndDie(size, mem_type, "allocate", res, raw_report); | ||
| 156 | __mmap_memset(ptr, 0, size); | ||
| 157 | IncreaseTotalMmap(size); | ||
| 158 | return ptr; | ||
| 159 | } | ||
| 160 | |||
| 161 | void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { | ||
| 162 | void* ptr = 0; | ||
| 163 | int res = __mmap_alloc_aligned(&ptr, GetPageSize(), size); | ||
| 164 | if (UNLIKELY(res)) { | ||
| 165 | if (res == ENOMEM) | ||
| 166 | return nullptr; | ||
| 167 | ReportMmapFailureAndDie(size, mem_type, "allocate", false); | ||
| 168 | } | ||
| 169 | __mmap_memset(ptr, 0, size); | ||
| 170 | IncreaseTotalMmap(size); | ||
| 171 | return ptr; | ||
| 172 | } | ||
| 173 | |||
| 174 | void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, | ||
| 175 | const char *mem_type) { | ||
| 176 | CHECK(IsPowerOfTwo(size)); | ||
| 177 | CHECK(IsPowerOfTwo(alignment)); | ||
| 178 | void* ptr = 0; | ||
| 179 | int res = __mmap_alloc_aligned(&ptr, alignment, size); | ||
| 180 | if (res) | ||
| 181 | ReportMmapFailureAndDie(size, mem_type, "align allocate", res, false); | ||
| 182 | __mmap_memset(ptr, 0, size); | ||
| 183 | IncreaseTotalMmap(size); | ||
| 184 | return ptr; | ||
| 185 | } | ||
| 186 | |||
| 187 | void *MmapNoReserveOrDie(uptr size, const char *mem_type) { | ||
| 188 | return MmapOrDie(size, mem_type, false); | ||
| 189 | } | ||
| 190 | |||
| 191 | void UnmapOrDie(void *addr, uptr size) { | ||
| 192 | if (!addr || !size) return; | ||
| 193 | __mmap_free(addr); | ||
| 194 | DecreaseTotalMmap(size); | ||
| 195 | } | ||
| 196 | |||
| 197 | fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) { | ||
| 198 | int flags; | ||
| 199 | switch (mode) { | ||
| 200 | case RdOnly: flags = O_RDONLY; break; | ||
| 201 | case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break; | ||
| 202 | case RdWr: flags = O_RDWR | O_CREAT; break; | ||
| 203 | } | ||
| 204 | fd_t res = open(filename, flags, 0660); | ||
| 205 | if (internal_iserror(res, errno_p)) | ||
| 206 | return kInvalidFd; | ||
| 207 | return res; | ||
| 208 | } | ||
| 209 | |||
| 210 | void CloseFile(fd_t fd) { | ||
| 211 | close(fd); | ||
| 212 | } | ||
| 213 | |||
| 214 | bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, | ||
| 215 | error_t *error_p) { | ||
| 216 | uptr res = read(fd, buff, buff_size); | ||
| 217 | if (internal_iserror(res, error_p)) | ||
| 218 | return false; | ||
| 219 | if (bytes_read) | ||
| 220 | *bytes_read = res; | ||
| 221 | return true; | ||
| 222 | } | ||
| 223 | |||
| 224 | bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, | ||
| 225 | error_t *error_p) { | ||
| 226 | uptr res = write(fd, buff, buff_size); | ||
| 227 | if (internal_iserror(res, error_p)) | ||
| 228 | return false; | ||
| 229 | if (bytes_written) | ||
| 230 | *bytes_written = res; | ||
| 231 | return true; | ||
| 232 | } | ||
| 233 | |||
| 234 | void ReleaseMemoryPagesToOS(uptr beg, uptr end) {} | ||
| 235 | void DumpProcessMap() {} | ||
| 236 | |||
| 237 | // There is no page protection so everything is "accessible." | ||
| 238 | bool IsAccessibleMemoryRange(uptr beg, uptr size) { | ||
| 239 | return true; | ||
| 240 | } | ||
| 241 | |||
| 242 | char **GetArgv() { return nullptr; } | ||
| 243 | char **GetEnviron() { return nullptr; } | ||
| 244 | |||
| 245 | const char *GetEnv(const char *name) { | ||
| 246 | return getenv(name); | ||
| 247 | } | ||
| 248 | |||
| 249 | uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { | ||
| 250 | internal_strncpy(buf, "StubBinaryName", buf_len); | ||
| 251 | return internal_strlen(buf); | ||
| 252 | } | ||
| 253 | |||
| 254 | uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { | ||
| 255 | internal_strncpy(buf, "StubProcessName", buf_len); | ||
| 256 | return internal_strlen(buf); | ||
| 257 | } | ||
| 258 | |||
| 259 | bool IsPathSeparator(const char c) { | ||
| 260 | return c == '/'; | ||
| 261 | } | ||
| 262 | |||
| 263 | bool IsAbsolutePath(const char *path) { | ||
| 264 | return path != nullptr && IsPathSeparator(path[0]); | ||
| 265 | } | ||
| 266 | |||
| 267 | void ReportFile::Write(const char *buffer, uptr length) { | ||
| 268 | SpinMutexLock l(mu); | ||
| 269 | static const char *kWriteError = | ||
| 270 | "ReportFile::Write() can't output requested buffer!\n"; | ||
| 271 | ReopenIfNecessary(); | ||
| 272 | if (length != write(fd, buffer, length)) { | ||
| 273 | write(fd, kWriteError, internal_strlen(kWriteError)); | ||
| 274 | Die(); | ||
| 275 | } | ||
| 276 | } | ||
| 277 | |||
| 278 | uptr MainThreadStackBase, MainThreadStackSize; | ||
| 279 | uptr MainThreadTlsBase, MainThreadTlsSize; | ||
| 280 | |||
| 281 | } // namespace __sanitizer | ||
| 282 | |||
| 283 | #endif // SANITIZER_RTEMS | ||
lib/tsan/sanitizer_common/sanitizer_rtems.h created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | //===-- sanitizer_rtems.h ---------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between various sanitizers' runtime libraries and | ||
| 10 | // provides definitions for RTEMS-specific functions. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_RTEMS_H | ||
| 13 | #define SANITIZER_RTEMS_H | ||
| 14 | |||
| 15 | #include "sanitizer_platform.h" | ||
| 16 | #if SANITIZER_RTEMS | ||
| 17 | #include "sanitizer_common.h" | ||
| 18 | |||
| 19 | #endif // SANITIZER_RTEMS | ||
| 20 | #endif // SANITIZER_RTEMS_H | ||
lib/tsan/sanitizer_common/sanitizer_signal_interceptors.inc created+86| ... | @@ -0,0 +1,86 @@ | ||
| 1 | //===-- sanitizer_signal_interceptors.inc -----------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Signal interceptors for sanitizers. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "interception/interception.h" | ||
| 14 | #include "sanitizer_common.h" | ||
| 15 | #include "sanitizer_internal_defs.h" | ||
| 16 | #include "sanitizer_platform_interceptors.h" | ||
| 17 | |||
| 18 | using namespace __sanitizer; | ||
| 19 | |||
| 20 | #if SANITIZER_NETBSD | ||
| 21 | #define sigaction_symname __sigaction14 | ||
| 22 | #else | ||
| 23 | #define sigaction_symname sigaction | ||
| 24 | #endif | ||
| 25 | |||
| 26 | #ifndef SIGNAL_INTERCEPTOR_SIGNAL_IMPL | ||
| 27 | #define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signum, handler) \ | ||
| 28 | { return REAL(func)(signum, handler); } | ||
| 29 | #endif | ||
| 30 | |||
| 31 | #ifndef SIGNAL_INTERCEPTOR_SIGACTION_IMPL | ||
| 32 | #define SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact) \ | ||
| 33 | { return REAL(sigaction_symname)(signum, act, oldact); } | ||
| 34 | #endif | ||
| 35 | |||
| 36 | #if SANITIZER_INTERCEPT_BSD_SIGNAL | ||
| 37 | INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) { | ||
| 38 | if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0; | ||
| 39 | SIGNAL_INTERCEPTOR_SIGNAL_IMPL(bsd_signal, signum, handler); | ||
| 40 | } | ||
| 41 | #define INIT_BSD_SIGNAL COMMON_INTERCEPT_FUNCTION(bsd_signal) | ||
| 42 | #else // SANITIZER_INTERCEPT_BSD_SIGNAL | ||
| 43 | #define INIT_BSD_SIGNAL | ||
| 44 | #endif // SANITIZER_INTERCEPT_BSD_SIGNAL | ||
| 45 | |||
| 46 | #if SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION | ||
| 47 | INTERCEPTOR(uptr, signal, int signum, uptr handler) { | ||
| 48 | if (GetHandleSignalMode(signum) == kHandleSignalExclusive) | ||
| 49 | return (uptr) nullptr; | ||
| 50 | SIGNAL_INTERCEPTOR_SIGNAL_IMPL(signal, signum, handler); | ||
| 51 | } | ||
| 52 | #define INIT_SIGNAL COMMON_INTERCEPT_FUNCTION(signal) | ||
| 53 | |||
| 54 | INTERCEPTOR(int, sigaction_symname, int signum, | ||
| 55 | const __sanitizer_sigaction *act, __sanitizer_sigaction *oldact) { | ||
| 56 | if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0; | ||
| 57 | SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); | ||
| 58 | } | ||
| 59 | #define INIT_SIGACTION COMMON_INTERCEPT_FUNCTION(sigaction_symname) | ||
| 60 | |||
| 61 | namespace __sanitizer { | ||
| 62 | int real_sigaction(int signum, const void *act, void *oldact) { | ||
| 63 | return REAL(sigaction_symname)(signum, (const __sanitizer_sigaction *)act, | ||
| 64 | (__sanitizer_sigaction *)oldact); | ||
| 65 | } | ||
| 66 | } // namespace __sanitizer | ||
| 67 | #else // SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION | ||
| 68 | #define INIT_SIGNAL | ||
| 69 | #define INIT_SIGACTION | ||
| 70 | // We need to have defined REAL(sigaction) on other systems. | ||
| 71 | namespace __sanitizer { | ||
| 72 | struct __sanitizer_sigaction; | ||
| 73 | } | ||
| 74 | DEFINE_REAL(int, sigaction, int signum, const __sanitizer_sigaction *act, | ||
| 75 | __sanitizer_sigaction *oldact) | ||
| 76 | #endif // SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION | ||
| 77 | |||
| 78 | static void InitializeSignalInterceptors() { | ||
| 79 | static bool was_called_once; | ||
| 80 | CHECK(!was_called_once); | ||
| 81 | was_called_once = true; | ||
| 82 | |||
| 83 | INIT_BSD_SIGNAL; | ||
| 84 | INIT_SIGNAL; | ||
| 85 | INIT_SIGACTION; | ||
| 86 | } | ||
lib/tsan/sanitizer_common/sanitizer_solaris.cpp created+230| ... | @@ -0,0 +1,230 @@ | ||
| 1 | //===-- sanitizer_solaris.cpp ---------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between various sanitizers' runtime libraries and | ||
| 10 | // implements Solaris-specific functions. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_platform.h" | ||
| 14 | #if SANITIZER_SOLARIS | ||
| 15 | |||
| 16 | #include <stdio.h> | ||
| 17 | |||
| 18 | #include "sanitizer_common.h" | ||
| 19 | #include "sanitizer_flags.h" | ||
| 20 | #include "sanitizer_internal_defs.h" | ||
| 21 | #include "sanitizer_libc.h" | ||
| 22 | #include "sanitizer_placement_new.h" | ||
| 23 | #include "sanitizer_platform_limits_posix.h" | ||
| 24 | #include "sanitizer_procmaps.h" | ||
| 25 | |||
| 26 | #include <fcntl.h> | ||
| 27 | #include <pthread.h> | ||
| 28 | #include <sched.h> | ||
| 29 | #include <thread.h> | ||
| 30 | #include <synch.h> | ||
| 31 | #include <signal.h> | ||
| 32 | #include <sys/mman.h> | ||
| 33 | #include <sys/resource.h> | ||
| 34 | #include <sys/stat.h> | ||
| 35 | #include <sys/types.h> | ||
| 36 | #include <dirent.h> | ||
| 37 | #include <unistd.h> | ||
| 38 | #include <errno.h> | ||
| 39 | #include <stdlib.h> | ||
| 40 | |||
| 41 | namespace __sanitizer { | ||
| 42 | |||
| 43 | //#include "sanitizer_syscall_generic.inc" | ||
| 44 | |||
| 45 | #define _REAL(func) _ ## func | ||
| 46 | #define DECLARE__REAL(ret_type, func, ...) \ | ||
| 47 | extern "C" ret_type _REAL(func)(__VA_ARGS__) | ||
| 48 | #define DECLARE__REAL_AND_INTERNAL(ret_type, func, ...) \ | ||
| 49 | DECLARE__REAL(ret_type, func, __VA_ARGS__); \ | ||
| 50 | ret_type internal_ ## func(__VA_ARGS__) | ||
| 51 | |||
| 52 | #if !defined(_LP64) && _FILE_OFFSET_BITS == 64 | ||
| 53 | #define _REAL64(func) _ ## func ## 64 | ||
| 54 | #else | ||
| 55 | #define _REAL64(func) _REAL(func) | ||
| 56 | #endif | ||
| 57 | #define DECLARE__REAL64(ret_type, func, ...) \ | ||
| 58 | extern "C" ret_type _REAL64(func)(__VA_ARGS__) | ||
| 59 | #define DECLARE__REAL_AND_INTERNAL64(ret_type, func, ...) \ | ||
| 60 | DECLARE__REAL64(ret_type, func, __VA_ARGS__); \ | ||
| 61 | ret_type internal_ ## func(__VA_ARGS__) | ||
| 62 | |||
| 63 | // ---------------------- sanitizer_libc.h | ||
| 64 | DECLARE__REAL_AND_INTERNAL64(uptr, mmap, void *addr, uptr /*size_t*/ length, | ||
| 65 | int prot, int flags, int fd, OFF_T offset) { | ||
| 66 | return (uptr)_REAL64(mmap)(addr, length, prot, flags, fd, offset); | ||
| 67 | } | ||
| 68 | |||
| 69 | DECLARE__REAL_AND_INTERNAL(uptr, munmap, void *addr, uptr length) { | ||
| 70 | return _REAL(munmap)(addr, length); | ||
| 71 | } | ||
| 72 | |||
| 73 | DECLARE__REAL_AND_INTERNAL(int, mprotect, void *addr, uptr length, int prot) { | ||
| 74 | return _REAL(mprotect)(addr, length, prot); | ||
| 75 | } | ||
| 76 | |||
| 77 | DECLARE__REAL_AND_INTERNAL(uptr, close, fd_t fd) { | ||
| 78 | return _REAL(close)(fd); | ||
| 79 | } | ||
| 80 | |||
| 81 | extern "C" int _REAL64(open)(const char *, int, ...); | ||
| 82 | |||
| 83 | uptr internal_open(const char *filename, int flags) { | ||
| 84 | return _REAL64(open)(filename, flags); | ||
| 85 | } | ||
| 86 | |||
| 87 | uptr internal_open(const char *filename, int flags, u32 mode) { | ||
| 88 | return _REAL64(open)(filename, flags, mode); | ||
| 89 | } | ||
| 90 | |||
| 91 | DECLARE__REAL_AND_INTERNAL(uptr, read, fd_t fd, void *buf, uptr count) { | ||
| 92 | return _REAL(read)(fd, buf, count); | ||
| 93 | } | ||
| 94 | |||
| 95 | DECLARE__REAL_AND_INTERNAL(uptr, write, fd_t fd, const void *buf, uptr count) { | ||
| 96 | return _REAL(write)(fd, buf, count); | ||
| 97 | } | ||
| 98 | |||
| 99 | // FIXME: There's only _ftruncate64 beginning with Solaris 11. | ||
| 100 | DECLARE__REAL_AND_INTERNAL(uptr, ftruncate, fd_t fd, uptr size) { | ||
| 101 | return ftruncate(fd, size); | ||
| 102 | } | ||
| 103 | |||
| 104 | DECLARE__REAL_AND_INTERNAL64(uptr, stat, const char *path, void *buf) { | ||
| 105 | return _REAL64(stat)(path, (struct stat *)buf); | ||
| 106 | } | ||
| 107 | |||
| 108 | DECLARE__REAL_AND_INTERNAL64(uptr, lstat, const char *path, void *buf) { | ||
| 109 | return _REAL64(lstat)(path, (struct stat *)buf); | ||
| 110 | } | ||
| 111 | |||
| 112 | DECLARE__REAL_AND_INTERNAL64(uptr, fstat, fd_t fd, void *buf) { | ||
| 113 | return _REAL64(fstat)(fd, (struct stat *)buf); | ||
| 114 | } | ||
| 115 | |||
| 116 | uptr internal_filesize(fd_t fd) { | ||
| 117 | struct stat st; | ||
| 118 | if (internal_fstat(fd, &st)) | ||
| 119 | return -1; | ||
| 120 | return (uptr)st.st_size; | ||
| 121 | } | ||
| 122 | |||
| 123 | DECLARE__REAL_AND_INTERNAL(uptr, dup, int oldfd) { | ||
| 124 | return _REAL(dup)(oldfd); | ||
| 125 | } | ||
| 126 | |||
| 127 | DECLARE__REAL_AND_INTERNAL(uptr, dup2, int oldfd, int newfd) { | ||
| 128 | return _REAL(dup2)(oldfd, newfd); | ||
| 129 | } | ||
| 130 | |||
| 131 | DECLARE__REAL_AND_INTERNAL(uptr, readlink, const char *path, char *buf, | ||
| 132 | uptr bufsize) { | ||
| 133 | return _REAL(readlink)(path, buf, bufsize); | ||
| 134 | } | ||
| 135 | |||
| 136 | DECLARE__REAL_AND_INTERNAL(uptr, unlink, const char *path) { | ||
| 137 | return _REAL(unlink)(path); | ||
| 138 | } | ||
| 139 | |||
| 140 | DECLARE__REAL_AND_INTERNAL(uptr, rename, const char *oldpath, | ||
| 141 | const char *newpath) { | ||
| 142 | return _REAL(rename)(oldpath, newpath); | ||
| 143 | } | ||
| 144 | |||
| 145 | DECLARE__REAL_AND_INTERNAL(uptr, sched_yield, void) { | ||
| 146 | return sched_yield(); | ||
| 147 | } | ||
| 148 | |||
| 149 | DECLARE__REAL_AND_INTERNAL(void, _exit, int exitcode) { | ||
| 150 | _exit(exitcode); | ||
| 151 | } | ||
| 152 | |||
| 153 | DECLARE__REAL_AND_INTERNAL(uptr, execve, const char *filename, | ||
| 154 | char *const argv[], char *const envp[]) { | ||
| 155 | return _REAL(execve)(filename, argv, envp); | ||
| 156 | } | ||
| 157 | |||
| 158 | DECLARE__REAL_AND_INTERNAL(uptr, waitpid, int pid, int *status, int options) { | ||
| 159 | return _REAL(waitpid)(pid, status, options); | ||
| 160 | } | ||
| 161 | |||
| 162 | DECLARE__REAL_AND_INTERNAL(uptr, getpid, void) { | ||
| 163 | return _REAL(getpid)(); | ||
| 164 | } | ||
| 165 | |||
| 166 | // FIXME: This might be wrong: _getdents doesn't take a struct linux_dirent *. | ||
| 167 | DECLARE__REAL_AND_INTERNAL64(uptr, getdents, fd_t fd, struct linux_dirent *dirp, | ||
| 168 | unsigned int count) { | ||
| 169 | return _REAL64(getdents)(fd, dirp, count); | ||
| 170 | } | ||
| 171 | |||
| 172 | DECLARE__REAL_AND_INTERNAL64(uptr, lseek, fd_t fd, OFF_T offset, int whence) { | ||
| 173 | return _REAL64(lseek)(fd, offset, whence); | ||
| 174 | } | ||
| 175 | |||
| 176 | // FIXME: This might be wrong: _sigfillset doesn't take a | ||
| 177 | // __sanitizer_sigset_t *. | ||
| 178 | DECLARE__REAL_AND_INTERNAL(void, sigfillset, __sanitizer_sigset_t *set) { | ||
| 179 | _REAL(sigfillset)(set); | ||
| 180 | } | ||
| 181 | |||
| 182 | // FIXME: This might be wrong: _sigprocmask doesn't take __sanitizer_sigset_t *. | ||
| 183 | DECLARE__REAL_AND_INTERNAL(uptr, sigprocmask, int how, | ||
| 184 | __sanitizer_sigset_t *set, | ||
| 185 | __sanitizer_sigset_t *oldset) { | ||
| 186 | return _REAL(sigprocmask)(how, set, oldset); | ||
| 187 | } | ||
| 188 | |||
| 189 | DECLARE__REAL_AND_INTERNAL(int, fork, void) { | ||
| 190 | // TODO(glider): this may call user's pthread_atfork() handlers which is bad. | ||
| 191 | return _REAL(fork)(); | ||
| 192 | } | ||
| 193 | |||
| 194 | u64 NanoTime() { | ||
| 195 | return gethrtime(); | ||
| 196 | } | ||
| 197 | |||
| 198 | uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { | ||
| 199 | // FIXME: No internal variant. | ||
| 200 | return clock_gettime(clk_id, (timespec *)tp); | ||
| 201 | } | ||
| 202 | |||
| 203 | // ----------------- sanitizer_common.h | ||
| 204 | BlockingMutex::BlockingMutex() { | ||
| 205 | CHECK(sizeof(mutex_t) <= sizeof(opaque_storage_)); | ||
| 206 | internal_memset(this, 0, sizeof(*this)); | ||
| 207 | CHECK_EQ(mutex_init((mutex_t *)&opaque_storage_, USYNC_THREAD, NULL), 0); | ||
| 208 | } | ||
| 209 | |||
| 210 | void BlockingMutex::Lock() { | ||
| 211 | CHECK(sizeof(mutex_t) <= sizeof(opaque_storage_)); | ||
| 212 | CHECK_NE(owner_, (uptr)thr_self()); | ||
| 213 | CHECK_EQ(mutex_lock((mutex_t *)&opaque_storage_), 0); | ||
| 214 | CHECK(!owner_); | ||
| 215 | owner_ = (uptr)thr_self(); | ||
| 216 | } | ||
| 217 | |||
| 218 | void BlockingMutex::Unlock() { | ||
| 219 | CHECK(owner_ == (uptr)thr_self()); | ||
| 220 | owner_ = 0; | ||
| 221 | CHECK_EQ(mutex_unlock((mutex_t *)&opaque_storage_), 0); | ||
| 222 | } | ||
| 223 | |||
| 224 | void BlockingMutex::CheckLocked() { | ||
| 225 | CHECK_EQ((uptr)thr_self(), owner_); | ||
| 226 | } | ||
| 227 | |||
| 228 | } // namespace __sanitizer | ||
| 229 | |||
| 230 | #endif // SANITIZER_SOLARIS | ||
lib/tsan/sanitizer_common/sanitizer_stackdepot.h created+71| ... | @@ -0,0 +1,71 @@ | ||
| 1 | //===-- sanitizer_stackdepot.h ----------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer | ||
| 10 | // run-time libraries. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef SANITIZER_STACKDEPOT_H | ||
| 14 | #define SANITIZER_STACKDEPOT_H | ||
| 15 | |||
| 16 | #include "sanitizer_common.h" | ||
| 17 | #include "sanitizer_internal_defs.h" | ||
| 18 | #include "sanitizer_stacktrace.h" | ||
| 19 | |||
| 20 | namespace __sanitizer { | ||
| 21 | |||
| 22 | // StackDepot efficiently stores huge amounts of stack traces. | ||
| 23 | struct StackDepotNode; | ||
| 24 | struct StackDepotHandle { | ||
| 25 | StackDepotNode *node_; | ||
| 26 | StackDepotHandle() : node_(nullptr) {} | ||
| 27 | explicit StackDepotHandle(StackDepotNode *node) : node_(node) {} | ||
| 28 | bool valid() { return node_; } | ||
| 29 | u32 id(); | ||
| 30 | int use_count(); | ||
| 31 | void inc_use_count_unsafe(); | ||
| 32 | }; | ||
| 33 | |||
| 34 | const int kStackDepotMaxUseCount = 1U << (SANITIZER_ANDROID ? 16 : 20); | ||
| 35 | |||
| 36 | StackDepotStats *StackDepotGetStats(); | ||
| 37 | u32 StackDepotPut(StackTrace stack); | ||
| 38 | StackDepotHandle StackDepotPut_WithHandle(StackTrace stack); | ||
| 39 | // Retrieves a stored stack trace by the id. | ||
| 40 | StackTrace StackDepotGet(u32 id); | ||
| 41 | |||
| 42 | void StackDepotLockAll(); | ||
| 43 | void StackDepotUnlockAll(); | ||
| 44 | |||
| 45 | // Instantiating this class creates a snapshot of StackDepot which can be | ||
| 46 | // efficiently queried with StackDepotGet(). You can use it concurrently with | ||
| 47 | // StackDepot, but the snapshot is only guaranteed to contain those stack traces | ||
| 48 | // which were stored before it was instantiated. | ||
| 49 | class StackDepotReverseMap { | ||
| 50 | public: | ||
| 51 | StackDepotReverseMap(); | ||
| 52 | StackTrace Get(u32 id); | ||
| 53 | |||
| 54 | private: | ||
| 55 | struct IdDescPair { | ||
| 56 | u32 id; | ||
| 57 | StackDepotNode *desc; | ||
| 58 | |||
| 59 | static bool IdComparator(const IdDescPair &a, const IdDescPair &b); | ||
| 60 | }; | ||
| 61 | |||
| 62 | InternalMmapVector<IdDescPair> map_; | ||
| 63 | |||
| 64 | // Disallow evil constructors. | ||
| 65 | StackDepotReverseMap(const StackDepotReverseMap&); | ||
| 66 | void operator=(const StackDepotReverseMap&); | ||
| 67 | }; | ||
| 68 | |||
| 69 | } // namespace __sanitizer | ||
| 70 | |||
| 71 | #endif // SANITIZER_STACKDEPOT_H | ||
lib/tsan/sanitizer_common/sanitizer_stackdepotbase.h created+177| ... | @@ -0,0 +1,177 @@ | ||
| 1 | //===-- sanitizer_stackdepotbase.h ------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Implementation of a mapping from arbitrary values to unique 32-bit | ||
| 10 | // identifiers. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef SANITIZER_STACKDEPOTBASE_H | ||
| 14 | #define SANITIZER_STACKDEPOTBASE_H | ||
| 15 | |||
| 16 | #include "sanitizer_internal_defs.h" | ||
| 17 | #include "sanitizer_mutex.h" | ||
| 18 | #include "sanitizer_atomic.h" | ||
| 19 | #include "sanitizer_persistent_allocator.h" | ||
| 20 | |||
| 21 | namespace __sanitizer { | ||
| 22 | |||
| 23 | template <class Node, int kReservedBits, int kTabSizeLog> | ||
| 24 | class StackDepotBase { | ||
| 25 | public: | ||
| 26 | typedef typename Node::args_type args_type; | ||
| 27 | typedef typename Node::handle_type handle_type; | ||
| 28 | // Maps stack trace to an unique id. | ||
| 29 | handle_type Put(args_type args, bool *inserted = nullptr); | ||
| 30 | // Retrieves a stored stack trace by the id. | ||
| 31 | args_type Get(u32 id); | ||
| 32 | |||
| 33 | StackDepotStats *GetStats() { return &stats; } | ||
| 34 | |||
| 35 | void LockAll(); | ||
| 36 | void UnlockAll(); | ||
| 37 | |||
| 38 | private: | ||
| 39 | static Node *find(Node *s, args_type args, u32 hash); | ||
| 40 | static Node *lock(atomic_uintptr_t *p); | ||
| 41 | static void unlock(atomic_uintptr_t *p, Node *s); | ||
| 42 | |||
| 43 | static const int kTabSize = 1 << kTabSizeLog; // Hash table size. | ||
| 44 | static const int kPartBits = 8; | ||
| 45 | static const int kPartShift = sizeof(u32) * 8 - kPartBits - kReservedBits; | ||
| 46 | static const int kPartCount = | ||
| 47 | 1 << kPartBits; // Number of subparts in the table. | ||
| 48 | static const int kPartSize = kTabSize / kPartCount; | ||
| 49 | static const int kMaxId = 1 << kPartShift; | ||
| 50 | |||
| 51 | atomic_uintptr_t tab[kTabSize]; // Hash table of Node's. | ||
| 52 | atomic_uint32_t seq[kPartCount]; // Unique id generators. | ||
| 53 | |||
| 54 | StackDepotStats stats; | ||
| 55 | |||
| 56 | friend class StackDepotReverseMap; | ||
| 57 | }; | ||
| 58 | |||
| 59 | template <class Node, int kReservedBits, int kTabSizeLog> | ||
| 60 | Node *StackDepotBase<Node, kReservedBits, kTabSizeLog>::find(Node *s, | ||
| 61 | args_type args, | ||
| 62 | u32 hash) { | ||
| 63 | // Searches linked list s for the stack, returns its id. | ||
| 64 | for (; s; s = s->link) { | ||
| 65 | if (s->eq(hash, args)) { | ||
| 66 | return s; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | return nullptr; | ||
| 70 | } | ||
| 71 | |||
| 72 | template <class Node, int kReservedBits, int kTabSizeLog> | ||
| 73 | Node *StackDepotBase<Node, kReservedBits, kTabSizeLog>::lock( | ||
| 74 | atomic_uintptr_t *p) { | ||
| 75 | // Uses the pointer lsb as mutex. | ||
| 76 | for (int i = 0;; i++) { | ||
| 77 | uptr cmp = atomic_load(p, memory_order_relaxed); | ||
| 78 | if ((cmp & 1) == 0 && | ||
| 79 | atomic_compare_exchange_weak(p, &cmp, cmp | 1, memory_order_acquire)) | ||
| 80 | return (Node *)cmp; | ||
| 81 | if (i < 10) | ||
| 82 | proc_yield(10); | ||
| 83 | else | ||
| 84 | internal_sched_yield(); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | template <class Node, int kReservedBits, int kTabSizeLog> | ||
| 89 | void StackDepotBase<Node, kReservedBits, kTabSizeLog>::unlock( | ||
| 90 | atomic_uintptr_t *p, Node *s) { | ||
| 91 | DCHECK_EQ((uptr)s & 1, 0); | ||
| 92 | atomic_store(p, (uptr)s, memory_order_release); | ||
| 93 | } | ||
| 94 | |||
| 95 | template <class Node, int kReservedBits, int kTabSizeLog> | ||
| 96 | typename StackDepotBase<Node, kReservedBits, kTabSizeLog>::handle_type | ||
| 97 | StackDepotBase<Node, kReservedBits, kTabSizeLog>::Put(args_type args, | ||
| 98 | bool *inserted) { | ||
| 99 | if (inserted) *inserted = false; | ||
| 100 | if (!Node::is_valid(args)) return handle_type(); | ||
| 101 | uptr h = Node::hash(args); | ||
| 102 | atomic_uintptr_t *p = &tab[h % kTabSize]; | ||
| 103 | uptr v = atomic_load(p, memory_order_consume); | ||
| 104 | Node *s = (Node *)(v & ~1); | ||
| 105 | // First, try to find the existing stack. | ||
| 106 | Node *node = find(s, args, h); | ||
| 107 | if (node) return node->get_handle(); | ||
| 108 | // If failed, lock, retry and insert new. | ||
| 109 | Node *s2 = lock(p); | ||
| 110 | if (s2 != s) { | ||
| 111 | node = find(s2, args, h); | ||
| 112 | if (node) { | ||
| 113 | unlock(p, s2); | ||
| 114 | return node->get_handle(); | ||
| 115 | } | ||
| 116 | } | ||
| 117 | uptr part = (h % kTabSize) / kPartSize; | ||
| 118 | u32 id = atomic_fetch_add(&seq[part], 1, memory_order_relaxed) + 1; | ||
| 119 | stats.n_uniq_ids++; | ||
| 120 | CHECK_LT(id, kMaxId); | ||
| 121 | id |= part << kPartShift; | ||
| 122 | CHECK_NE(id, 0); | ||
| 123 | CHECK_EQ(id & (((u32)-1) >> kReservedBits), id); | ||
| 124 | uptr memsz = Node::storage_size(args); | ||
| 125 | s = (Node *)PersistentAlloc(memsz); | ||
| 126 | stats.allocated += memsz; | ||
| 127 | s->id = id; | ||
| 128 | s->store(args, h); | ||
| 129 | s->link = s2; | ||
| 130 | unlock(p, s); | ||
| 131 | if (inserted) *inserted = true; | ||
| 132 | return s->get_handle(); | ||
| 133 | } | ||
| 134 | |||
| 135 | template <class Node, int kReservedBits, int kTabSizeLog> | ||
| 136 | typename StackDepotBase<Node, kReservedBits, kTabSizeLog>::args_type | ||
| 137 | StackDepotBase<Node, kReservedBits, kTabSizeLog>::Get(u32 id) { | ||
| 138 | if (id == 0) { | ||
| 139 | return args_type(); | ||
| 140 | } | ||
| 141 | CHECK_EQ(id & (((u32)-1) >> kReservedBits), id); | ||
| 142 | // High kPartBits contain part id, so we need to scan at most kPartSize lists. | ||
| 143 | uptr part = id >> kPartShift; | ||
| 144 | for (int i = 0; i != kPartSize; i++) { | ||
| 145 | uptr idx = part * kPartSize + i; | ||
| 146 | CHECK_LT(idx, kTabSize); | ||
| 147 | atomic_uintptr_t *p = &tab[idx]; | ||
| 148 | uptr v = atomic_load(p, memory_order_consume); | ||
| 149 | Node *s = (Node *)(v & ~1); | ||
| 150 | for (; s; s = s->link) { | ||
| 151 | if (s->id == id) { | ||
| 152 | return s->load(); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | } | ||
| 156 | return args_type(); | ||
| 157 | } | ||
| 158 | |||
| 159 | template <class Node, int kReservedBits, int kTabSizeLog> | ||
| 160 | void StackDepotBase<Node, kReservedBits, kTabSizeLog>::LockAll() { | ||
| 161 | for (int i = 0; i < kTabSize; ++i) { | ||
| 162 | lock(&tab[i]); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | template <class Node, int kReservedBits, int kTabSizeLog> | ||
| 167 | void StackDepotBase<Node, kReservedBits, kTabSizeLog>::UnlockAll() { | ||
| 168 | for (int i = 0; i < kTabSize; ++i) { | ||
| 169 | atomic_uintptr_t *p = &tab[i]; | ||
| 170 | uptr s = atomic_load(p, memory_order_relaxed); | ||
| 171 | unlock(p, (Node *)(s & ~1UL)); | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | } // namespace __sanitizer | ||
| 176 | |||
| 177 | #endif // SANITIZER_STACKDEPOTBASE_H | ||
lib/tsan/sanitizer_common/sanitizer_stacktrace.h created+176| ... | @@ -0,0 +1,176 @@ | ||
| 1 | //===-- sanitizer_stacktrace.h ----------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer | ||
| 10 | // run-time libraries. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_STACKTRACE_H | ||
| 13 | #define SANITIZER_STACKTRACE_H | ||
| 14 | |||
| 15 | #include "sanitizer_internal_defs.h" | ||
| 16 | |||
| 17 | namespace __sanitizer { | ||
| 18 | |||
| 19 | struct BufferedStackTrace; | ||
| 20 | |||
| 21 | static const u32 kStackTraceMax = 256; | ||
| 22 | |||
| 23 | #if SANITIZER_LINUX && defined(__mips__) | ||
| 24 | # define SANITIZER_CAN_FAST_UNWIND 0 | ||
| 25 | #elif SANITIZER_WINDOWS | ||
| 26 | # define SANITIZER_CAN_FAST_UNWIND 0 | ||
| 27 | #elif SANITIZER_OPENBSD | ||
| 28 | # define SANITIZER_CAN_FAST_UNWIND 0 | ||
| 29 | #else | ||
| 30 | # define SANITIZER_CAN_FAST_UNWIND 1 | ||
| 31 | #endif | ||
| 32 | |||
| 33 | // Fast unwind is the only option on Mac for now; we will need to | ||
| 34 | // revisit this macro when slow unwind works on Mac, see | ||
| 35 | // https://github.com/google/sanitizers/issues/137 | ||
| 36 | #if SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_RTEMS | ||
| 37 | # define SANITIZER_CAN_SLOW_UNWIND 0 | ||
| 38 | #else | ||
| 39 | # define SANITIZER_CAN_SLOW_UNWIND 1 | ||
| 40 | #endif | ||
| 41 | |||
| 42 | struct StackTrace { | ||
| 43 | const uptr *trace; | ||
| 44 | u32 size; | ||
| 45 | u32 tag; | ||
| 46 | |||
| 47 | static const int TAG_UNKNOWN = 0; | ||
| 48 | static const int TAG_ALLOC = 1; | ||
| 49 | static const int TAG_DEALLOC = 2; | ||
| 50 | static const int TAG_CUSTOM = 100; // Tool specific tags start here. | ||
| 51 | |||
| 52 | StackTrace() : trace(nullptr), size(0), tag(0) {} | ||
| 53 | StackTrace(const uptr *trace, u32 size) : trace(trace), size(size), tag(0) {} | ||
| 54 | StackTrace(const uptr *trace, u32 size, u32 tag) | ||
| 55 | : trace(trace), size(size), tag(tag) {} | ||
| 56 | |||
| 57 | // Prints a symbolized stacktrace, followed by an empty line. | ||
| 58 | void Print() const; | ||
| 59 | |||
| 60 | static bool WillUseFastUnwind(bool request_fast_unwind) { | ||
| 61 | if (!SANITIZER_CAN_FAST_UNWIND) | ||
| 62 | return false; | ||
| 63 | if (!SANITIZER_CAN_SLOW_UNWIND) | ||
| 64 | return true; | ||
| 65 | return request_fast_unwind; | ||
| 66 | } | ||
| 67 | |||
| 68 | static uptr GetCurrentPc(); | ||
| 69 | static inline uptr GetPreviousInstructionPc(uptr pc); | ||
| 70 | static uptr GetNextInstructionPc(uptr pc); | ||
| 71 | typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer, | ||
| 72 | int out_size); | ||
| 73 | }; | ||
| 74 | |||
| 75 | // Performance-critical, must be in the header. | ||
| 76 | ALWAYS_INLINE | ||
| 77 | uptr StackTrace::GetPreviousInstructionPc(uptr pc) { | ||
| 78 | #if defined(__arm__) | ||
| 79 | // T32 (Thumb) branch instructions might be 16 or 32 bit long, | ||
| 80 | // so we return (pc-2) in that case in order to be safe. | ||
| 81 | // For A32 mode we return (pc-4) because all instructions are 32 bit long. | ||
| 82 | return (pc - 3) & (~1); | ||
| 83 | #elif defined(__powerpc__) || defined(__powerpc64__) || defined(__aarch64__) | ||
| 84 | // PCs are always 4 byte aligned. | ||
| 85 | return pc - 4; | ||
| 86 | #elif defined(__sparc__) || defined(__mips__) | ||
| 87 | return pc - 8; | ||
| 88 | #else | ||
| 89 | return pc - 1; | ||
| 90 | #endif | ||
| 91 | } | ||
| 92 | |||
| 93 | // StackTrace that owns the buffer used to store the addresses. | ||
| 94 | struct BufferedStackTrace : public StackTrace { | ||
| 95 | uptr trace_buffer[kStackTraceMax]; | ||
| 96 | uptr top_frame_bp; // Optional bp of a top frame. | ||
| 97 | |||
| 98 | BufferedStackTrace() : StackTrace(trace_buffer, 0), top_frame_bp(0) {} | ||
| 99 | |||
| 100 | void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0); | ||
| 101 | |||
| 102 | // Get the stack trace with the given pc and bp. | ||
| 103 | // The pc will be in the position 0 of the resulting stack trace. | ||
| 104 | // The bp may refer to the current frame or to the caller's frame. | ||
| 105 | void Unwind(uptr pc, uptr bp, void *context, bool request_fast, | ||
| 106 | u32 max_depth = kStackTraceMax) { | ||
| 107 | top_frame_bp = (max_depth > 0) ? bp : 0; | ||
| 108 | // Small max_depth optimization | ||
| 109 | if (max_depth <= 1) { | ||
| 110 | if (max_depth == 1) | ||
| 111 | trace_buffer[0] = pc; | ||
| 112 | size = max_depth; | ||
| 113 | return; | ||
| 114 | } | ||
| 115 | UnwindImpl(pc, bp, context, request_fast, max_depth); | ||
| 116 | } | ||
| 117 | |||
| 118 | void Unwind(u32 max_depth, uptr pc, uptr bp, void *context, uptr stack_top, | ||
| 119 | uptr stack_bottom, bool request_fast_unwind); | ||
| 120 | |||
| 121 | void Reset() { | ||
| 122 | *static_cast<StackTrace *>(this) = StackTrace(trace_buffer, 0); | ||
| 123 | top_frame_bp = 0; | ||
| 124 | } | ||
| 125 | |||
| 126 | private: | ||
| 127 | // Every runtime defines its own implementation of this method | ||
| 128 | void UnwindImpl(uptr pc, uptr bp, void *context, bool request_fast, | ||
| 129 | u32 max_depth); | ||
| 130 | |||
| 131 | // UnwindFast/Slow have platform-specific implementations | ||
| 132 | void UnwindFast(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom, | ||
| 133 | u32 max_depth); | ||
| 134 | void UnwindSlow(uptr pc, u32 max_depth); | ||
| 135 | void UnwindSlow(uptr pc, void *context, u32 max_depth); | ||
| 136 | |||
| 137 | void PopStackFrames(uptr count); | ||
| 138 | uptr LocatePcInTrace(uptr pc); | ||
| 139 | |||
| 140 | BufferedStackTrace(const BufferedStackTrace &) = delete; | ||
| 141 | void operator=(const BufferedStackTrace &) = delete; | ||
| 142 | |||
| 143 | friend class FastUnwindTest; | ||
| 144 | }; | ||
| 145 | |||
| 146 | // Check if given pointer points into allocated stack area. | ||
| 147 | static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) { | ||
| 148 | return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr); | ||
| 149 | } | ||
| 150 | |||
| 151 | } // namespace __sanitizer | ||
| 152 | |||
| 153 | // Use this macro if you want to print stack trace with the caller | ||
| 154 | // of the current function in the top frame. | ||
| 155 | #define GET_CALLER_PC_BP \ | ||
| 156 | uptr bp = GET_CURRENT_FRAME(); \ | ||
| 157 | uptr pc = GET_CALLER_PC(); | ||
| 158 | |||
| 159 | #define GET_CALLER_PC_BP_SP \ | ||
| 160 | GET_CALLER_PC_BP; \ | ||
| 161 | uptr local_stack; \ | ||
| 162 | uptr sp = (uptr)&local_stack | ||
| 163 | |||
| 164 | // Use this macro if you want to print stack trace with the current | ||
| 165 | // function in the top frame. | ||
| 166 | #define GET_CURRENT_PC_BP \ | ||
| 167 | uptr bp = GET_CURRENT_FRAME(); \ | ||
| 168 | uptr pc = StackTrace::GetCurrentPc() | ||
| 169 | |||
| 170 | #define GET_CURRENT_PC_BP_SP \ | ||
| 171 | GET_CURRENT_PC_BP; \ | ||
| 172 | uptr local_stack; \ | ||
| 173 | uptr sp = (uptr)&local_stack | ||
| 174 | |||
| 175 | |||
| 176 | #endif // SANITIZER_STACKTRACE_H | ||
lib/tsan/sanitizer_common/sanitizer_stacktrace_printer.h created+71| ... | @@ -0,0 +1,71 @@ | ||
| 1 | //===-- sanitizer_stacktrace_printer.h --------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between sanitizers' run-time libraries. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_STACKTRACE_PRINTER_H | ||
| 13 | #define SANITIZER_STACKTRACE_PRINTER_H | ||
| 14 | |||
| 15 | #include "sanitizer_common.h" | ||
| 16 | #include "sanitizer_symbolizer.h" | ||
| 17 | |||
| 18 | namespace __sanitizer { | ||
| 19 | |||
| 20 | // Render the contents of "info" structure, which represents the contents of | ||
| 21 | // stack frame "frame_no" and appends it to the "buffer". "format" is a | ||
| 22 | // string with placeholders, which is copied to the output with | ||
| 23 | // placeholders substituted with the contents of "info". For example, | ||
| 24 | // format string | ||
| 25 | // " frame %n: function %F at %S" | ||
| 26 | // will be turned into | ||
| 27 | // " frame 10: function foo::bar() at my/file.cc:10" | ||
| 28 | // You may additionally pass "strip_path_prefix" to strip prefixes of paths to | ||
| 29 | // source files and modules, and "strip_func_prefix" to strip prefixes of | ||
| 30 | // function names. | ||
| 31 | // Here's the full list of available placeholders: | ||
| 32 | // %% - represents a '%' character; | ||
| 33 | // %n - frame number (copy of frame_no); | ||
| 34 | // %p - PC in hex format; | ||
| 35 | // %m - path to module (binary or shared object); | ||
| 36 | // %o - offset in the module in hex format; | ||
| 37 | // %f - function name; | ||
| 38 | // %q - offset in the function in hex format (*if available*); | ||
| 39 | // %s - path to source file; | ||
| 40 | // %l - line in the source file; | ||
| 41 | // %c - column in the source file; | ||
| 42 | // %F - if function is known to be <foo>, prints "in <foo>", possibly | ||
| 43 | // followed by the offset in this function, but only if source file | ||
| 44 | // is unknown; | ||
| 45 | // %S - prints file/line/column information; | ||
| 46 | // %L - prints location information: file/line/column, if it is known, or | ||
| 47 | // module+offset if it is known, or (<unknown module>) string. | ||
| 48 | // %M - prints module basename and offset, if it is known, or PC. | ||
| 49 | void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, | ||
| 50 | const AddressInfo &info, bool vs_style, | ||
| 51 | const char *strip_path_prefix = "", | ||
| 52 | const char *strip_func_prefix = ""); | ||
| 53 | |||
| 54 | void RenderSourceLocation(InternalScopedString *buffer, const char *file, | ||
| 55 | int line, int column, bool vs_style, | ||
| 56 | const char *strip_path_prefix); | ||
| 57 | |||
| 58 | void RenderModuleLocation(InternalScopedString *buffer, const char *module, | ||
| 59 | uptr offset, ModuleArch arch, | ||
| 60 | const char *strip_path_prefix); | ||
| 61 | |||
| 62 | // Same as RenderFrame, but for data section (global variables). | ||
| 63 | // Accepts %s, %l from above. | ||
| 64 | // Also accepts: | ||
| 65 | // %g - name of the global variable. | ||
| 66 | void RenderData(InternalScopedString *buffer, const char *format, | ||
| 67 | const DataInfo *DI, const char *strip_path_prefix = ""); | ||
| 68 | |||
| 69 | } // namespace __sanitizer | ||
| 70 | |||
| 71 | #endif // SANITIZER_STACKTRACE_PRINTER_H | ||
lib/tsan/sanitizer_common/sanitizer_stoptheworld.h created+64| ... | @@ -0,0 +1,64 @@ | ||
| 1 | //===-- sanitizer_stoptheworld.h --------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Defines the StopTheWorld function which suspends the execution of the current | ||
| 10 | // process and runs the user-supplied callback in the same address space. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | #ifndef SANITIZER_STOPTHEWORLD_H | ||
| 14 | #define SANITIZER_STOPTHEWORLD_H | ||
| 15 | |||
| 16 | #include "sanitizer_internal_defs.h" | ||
| 17 | #include "sanitizer_common.h" | ||
| 18 | |||
| 19 | namespace __sanitizer { | ||
| 20 | |||
| 21 | enum PtraceRegistersStatus { | ||
| 22 | REGISTERS_UNAVAILABLE_FATAL = -1, | ||
| 23 | REGISTERS_UNAVAILABLE = 0, | ||
| 24 | REGISTERS_AVAILABLE = 1 | ||
| 25 | }; | ||
| 26 | |||
| 27 | // Holds the list of suspended threads and provides an interface to dump their | ||
| 28 | // register contexts. | ||
| 29 | class SuspendedThreadsList { | ||
| 30 | public: | ||
| 31 | SuspendedThreadsList() = default; | ||
| 32 | |||
| 33 | // Can't declare pure virtual functions in sanitizer runtimes: | ||
| 34 | // __cxa_pure_virtual might be unavailable. Use UNIMPLEMENTED() instead. | ||
| 35 | virtual PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, | ||
| 36 | uptr *sp) const { | ||
| 37 | UNIMPLEMENTED(); | ||
| 38 | } | ||
| 39 | |||
| 40 | // The buffer in GetRegistersAndSP should be at least this big. | ||
| 41 | virtual uptr RegisterCount() const { UNIMPLEMENTED(); } | ||
| 42 | virtual uptr ThreadCount() const { UNIMPLEMENTED(); } | ||
| 43 | virtual tid_t GetThreadID(uptr index) const { UNIMPLEMENTED(); } | ||
| 44 | |||
| 45 | private: | ||
| 46 | // Prohibit copy and assign. | ||
| 47 | SuspendedThreadsList(const SuspendedThreadsList&); | ||
| 48 | void operator=(const SuspendedThreadsList&); | ||
| 49 | }; | ||
| 50 | |||
| 51 | typedef void (*StopTheWorldCallback)( | ||
| 52 | const SuspendedThreadsList &suspended_threads_list, | ||
| 53 | void *argument); | ||
| 54 | |||
| 55 | // Suspend all threads in the current process and run the callback on the list | ||
| 56 | // of suspended threads. This function will resume the threads before returning. | ||
| 57 | // The callback should not call any libc functions. The callback must not call | ||
| 58 | // exit() nor _exit() and instead return to the caller. | ||
| 59 | // This function should NOT be called from multiple threads simultaneously. | ||
| 60 | void StopTheWorld(StopTheWorldCallback callback, void *argument); | ||
| 61 | |||
| 62 | } // namespace __sanitizer | ||
| 63 | |||
| 64 | #endif // SANITIZER_STOPTHEWORLD_H | ||
lib/tsan/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp created+42| ... | @@ -0,0 +1,42 @@ | ||
| 1 | //===-- sanitizer_stoptheworld_fuchsia.cpp -------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===---------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // See sanitizer_stoptheworld.h for details. | ||
| 10 | // | ||
| 11 | //===---------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_platform.h" | ||
| 14 | |||
| 15 | #if SANITIZER_FUCHSIA | ||
| 16 | |||
| 17 | #include <zircon/sanitizer.h> | ||
| 18 | |||
| 19 | #include "sanitizer_stoptheworld.h" | ||
| 20 | |||
| 21 | namespace __sanitizer { | ||
| 22 | |||
| 23 | // The Fuchsia implementation stops the world but doesn't offer a real | ||
| 24 | // SuspendedThreadsList argument. This is enough for ASan's use case, | ||
| 25 | // and LSan does not use this API on Fuchsia. | ||
| 26 | void StopTheWorld(StopTheWorldCallback callback, void *argument) { | ||
| 27 | struct Params { | ||
| 28 | StopTheWorldCallback callback; | ||
| 29 | void *argument; | ||
| 30 | } params = {callback, argument}; | ||
| 31 | __sanitizer_memory_snapshot( | ||
| 32 | nullptr, nullptr, nullptr, nullptr, | ||
| 33 | [](zx_status_t, void *data) { | ||
| 34 | auto params = reinterpret_cast<Params *>(data); | ||
| 35 | params->callback({}, params->argument); | ||
| 36 | }, | ||
| 37 | &params); | ||
| 38 | } | ||
| 39 | |||
| 40 | } // namespace __sanitizer | ||
| 41 | |||
| 42 | #endif // SANITIZER_FUCHSIA | ||
lib/tsan/sanitizer_common/sanitizer_stoptheworld_mac.cpp created+182| ... | @@ -0,0 +1,182 @@ | ||
| 1 | //===-- sanitizer_stoptheworld_mac.cpp ------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // See sanitizer_stoptheworld.h for details. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_platform.h" | ||
| 14 | |||
| 15 | #if SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__) || \ | ||
| 16 | defined(__i386)) | ||
| 17 | |||
| 18 | #include <mach/mach.h> | ||
| 19 | #include <mach/thread_info.h> | ||
| 20 | #include <pthread.h> | ||
| 21 | |||
| 22 | #include "sanitizer_stoptheworld.h" | ||
| 23 | |||
| 24 | namespace __sanitizer { | ||
| 25 | typedef struct { | ||
| 26 | tid_t tid; | ||
| 27 | thread_t thread; | ||
| 28 | } SuspendedThreadInfo; | ||
| 29 | |||
| 30 | class SuspendedThreadsListMac : public SuspendedThreadsList { | ||
| 31 | public: | ||
| 32 | SuspendedThreadsListMac() : threads_(1024) {} | ||
| 33 | |||
| 34 | tid_t GetThreadID(uptr index) const; | ||
| 35 | thread_t GetThread(uptr index) const; | ||
| 36 | uptr ThreadCount() const; | ||
| 37 | bool ContainsThread(thread_t thread) const; | ||
| 38 | void Append(thread_t thread); | ||
| 39 | |||
| 40 | PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, | ||
| 41 | uptr *sp) const; | ||
| 42 | uptr RegisterCount() const; | ||
| 43 | |||
| 44 | private: | ||
| 45 | InternalMmapVector<SuspendedThreadInfo> threads_; | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct RunThreadArgs { | ||
| 49 | StopTheWorldCallback callback; | ||
| 50 | void *argument; | ||
| 51 | }; | ||
| 52 | |||
| 53 | void *RunThread(void *arg) { | ||
| 54 | struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg; | ||
| 55 | SuspendedThreadsListMac suspended_threads_list; | ||
| 56 | |||
| 57 | thread_array_t threads; | ||
| 58 | mach_msg_type_number_t num_threads; | ||
| 59 | kern_return_t err = task_threads(mach_task_self(), &threads, &num_threads); | ||
| 60 | if (err != KERN_SUCCESS) { | ||
| 61 | VReport(1, "Failed to get threads for task (errno %d).\n", err); | ||
| 62 | return nullptr; | ||
| 63 | } | ||
| 64 | |||
| 65 | thread_t thread_self = mach_thread_self(); | ||
| 66 | for (unsigned int i = 0; i < num_threads; ++i) { | ||
| 67 | if (threads[i] == thread_self) continue; | ||
| 68 | |||
| 69 | thread_suspend(threads[i]); | ||
| 70 | suspended_threads_list.Append(threads[i]); | ||
| 71 | } | ||
| 72 | |||
| 73 | run_args->callback(suspended_threads_list, run_args->argument); | ||
| 74 | |||
| 75 | uptr num_suspended = suspended_threads_list.ThreadCount(); | ||
| 76 | for (unsigned int i = 0; i < num_suspended; ++i) { | ||
| 77 | thread_resume(suspended_threads_list.GetThread(i)); | ||
| 78 | } | ||
| 79 | return nullptr; | ||
| 80 | } | ||
| 81 | |||
| 82 | void StopTheWorld(StopTheWorldCallback callback, void *argument) { | ||
| 83 | struct RunThreadArgs arg = {callback, argument}; | ||
| 84 | pthread_t run_thread = (pthread_t)internal_start_thread(RunThread, &arg); | ||
| 85 | internal_join_thread(run_thread); | ||
| 86 | } | ||
| 87 | |||
| 88 | #if defined(__x86_64__) | ||
| 89 | typedef x86_thread_state64_t regs_struct; | ||
| 90 | |||
| 91 | #define SP_REG __rsp | ||
| 92 | |||
| 93 | #elif defined(__aarch64__) | ||
| 94 | typedef arm_thread_state64_t regs_struct; | ||
| 95 | |||
| 96 | # if __DARWIN_UNIX03 | ||
| 97 | # define SP_REG __sp | ||
| 98 | # else | ||
| 99 | # define SP_REG sp | ||
| 100 | # endif | ||
| 101 | |||
| 102 | #elif defined(__i386) | ||
| 103 | typedef x86_thread_state32_t regs_struct; | ||
| 104 | |||
| 105 | #define SP_REG __esp | ||
| 106 | |||
| 107 | #else | ||
| 108 | #error "Unsupported architecture" | ||
| 109 | #endif | ||
| 110 | |||
| 111 | tid_t SuspendedThreadsListMac::GetThreadID(uptr index) const { | ||
| 112 | CHECK_LT(index, threads_.size()); | ||
| 113 | return threads_[index].tid; | ||
| 114 | } | ||
| 115 | |||
| 116 | thread_t SuspendedThreadsListMac::GetThread(uptr index) const { | ||
| 117 | CHECK_LT(index, threads_.size()); | ||
| 118 | return threads_[index].thread; | ||
| 119 | } | ||
| 120 | |||
| 121 | uptr SuspendedThreadsListMac::ThreadCount() const { | ||
| 122 | return threads_.size(); | ||
| 123 | } | ||
| 124 | |||
| 125 | bool SuspendedThreadsListMac::ContainsThread(thread_t thread) const { | ||
| 126 | for (uptr i = 0; i < threads_.size(); i++) { | ||
| 127 | if (threads_[i].thread == thread) return true; | ||
| 128 | } | ||
| 129 | return false; | ||
| 130 | } | ||
| 131 | |||
| 132 | void SuspendedThreadsListMac::Append(thread_t thread) { | ||
| 133 | thread_identifier_info_data_t info; | ||
| 134 | mach_msg_type_number_t info_count = THREAD_IDENTIFIER_INFO_COUNT; | ||
| 135 | kern_return_t err = thread_info(thread, THREAD_IDENTIFIER_INFO, | ||
| 136 | (thread_info_t)&info, &info_count); | ||
| 137 | if (err != KERN_SUCCESS) { | ||
| 138 | VReport(1, "Error - unable to get thread ident for a thread\n"); | ||
| 139 | return; | ||
| 140 | } | ||
| 141 | threads_.push_back({info.thread_id, thread}); | ||
| 142 | } | ||
| 143 | |||
| 144 | PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( | ||
| 145 | uptr index, uptr *buffer, uptr *sp) const { | ||
| 146 | thread_t thread = GetThread(index); | ||
| 147 | regs_struct regs; | ||
| 148 | int err; | ||
| 149 | mach_msg_type_number_t reg_count = MACHINE_THREAD_STATE_COUNT; | ||
| 150 | err = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)&regs, | ||
| 151 | &reg_count); | ||
| 152 | if (err != KERN_SUCCESS) { | ||
| 153 | VReport(1, "Error - unable to get registers for a thread\n"); | ||
| 154 | // KERN_INVALID_ARGUMENT indicates that either the flavor is invalid, | ||
| 155 | // or the thread does not exist. The other possible error case, | ||
| 156 | // MIG_ARRAY_TOO_LARGE, means that the state is too large, but it's | ||
| 157 | // still safe to proceed. | ||
| 158 | return err == KERN_INVALID_ARGUMENT ? REGISTERS_UNAVAILABLE_FATAL | ||
| 159 | : REGISTERS_UNAVAILABLE; | ||
| 160 | } | ||
| 161 | |||
| 162 | internal_memcpy(buffer, &regs, sizeof(regs)); | ||
| 163 | #if defined(__aarch64__) && defined(arm_thread_state64_get_sp) | ||
| 164 | *sp = arm_thread_state64_get_sp(regs); | ||
| 165 | #else | ||
| 166 | *sp = regs.SP_REG; | ||
| 167 | #endif | ||
| 168 | |||
| 169 | // On x86_64 and aarch64, we must account for the stack redzone, which is 128 | ||
| 170 | // bytes. | ||
| 171 | if (SANITIZER_WORDSIZE == 64) *sp -= 128; | ||
| 172 | |||
| 173 | return REGISTERS_AVAILABLE; | ||
| 174 | } | ||
| 175 | |||
| 176 | uptr SuspendedThreadsListMac::RegisterCount() const { | ||
| 177 | return MACHINE_THREAD_STATE_COUNT; | ||
| 178 | } | ||
| 179 | } // namespace __sanitizer | ||
| 180 | |||
| 181 | #endif // SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__)) || | ||
| 182 | // defined(__i386)) | ||
lib/tsan/sanitizer_common/sanitizer_suppressions.cpp created+181| ... | @@ -0,0 +1,181 @@ | ||
| 1 | //===-- sanitizer_suppressions.cpp ----------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Suppression parsing/matching code. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_suppressions.h" | ||
| 14 | |||
| 15 | #include "sanitizer_allocator_internal.h" | ||
| 16 | #include "sanitizer_common.h" | ||
| 17 | #include "sanitizer_flags.h" | ||
| 18 | #include "sanitizer_file.h" | ||
| 19 | #include "sanitizer_libc.h" | ||
| 20 | #include "sanitizer_placement_new.h" | ||
| 21 | |||
| 22 | namespace __sanitizer { | ||
| 23 | |||
| 24 | SuppressionContext::SuppressionContext(const char *suppression_types[], | ||
| 25 | int suppression_types_num) | ||
| 26 | : suppression_types_(suppression_types), | ||
| 27 | suppression_types_num_(suppression_types_num), | ||
| 28 | can_parse_(true) { | ||
| 29 | CHECK_LE(suppression_types_num_, kMaxSuppressionTypes); | ||
| 30 | internal_memset(has_suppression_type_, 0, suppression_types_num_); | ||
| 31 | } | ||
| 32 | |||
| 33 | #if !SANITIZER_FUCHSIA | ||
| 34 | static bool GetPathAssumingFileIsRelativeToExec(const char *file_path, | ||
| 35 | /*out*/char *new_file_path, | ||
| 36 | uptr new_file_path_size) { | ||
| 37 | InternalScopedString exec(kMaxPathLength); | ||
| 38 | if (ReadBinaryNameCached(exec.data(), exec.size())) { | ||
| 39 | const char *file_name_pos = StripModuleName(exec.data()); | ||
| 40 | uptr path_to_exec_len = file_name_pos - exec.data(); | ||
| 41 | internal_strncat(new_file_path, exec.data(), | ||
| 42 | Min(path_to_exec_len, new_file_path_size - 1)); | ||
| 43 | internal_strncat(new_file_path, file_path, | ||
| 44 | new_file_path_size - internal_strlen(new_file_path) - 1); | ||
| 45 | return true; | ||
| 46 | } | ||
| 47 | return false; | ||
| 48 | } | ||
| 49 | |||
| 50 | static const char *FindFile(const char *file_path, | ||
| 51 | /*out*/char *new_file_path, | ||
| 52 | uptr new_file_path_size) { | ||
| 53 | // If we cannot find the file, check if its location is relative to | ||
| 54 | // the location of the executable. | ||
| 55 | if (!FileExists(file_path) && !IsAbsolutePath(file_path) && | ||
| 56 | GetPathAssumingFileIsRelativeToExec(file_path, new_file_path, | ||
| 57 | new_file_path_size)) { | ||
| 58 | return new_file_path; | ||
| 59 | } | ||
| 60 | return file_path; | ||
| 61 | } | ||
| 62 | #else | ||
| 63 | static const char *FindFile(const char *file_path, char *, uptr) { | ||
| 64 | return file_path; | ||
| 65 | } | ||
| 66 | #endif | ||
| 67 | |||
| 68 | void SuppressionContext::ParseFromFile(const char *filename) { | ||
| 69 | if (filename[0] == '\0') | ||
| 70 | return; | ||
| 71 | |||
| 72 | InternalScopedString new_file_path(kMaxPathLength); | ||
| 73 | filename = FindFile(filename, new_file_path.data(), new_file_path.size()); | ||
| 74 | |||
| 75 | // Read the file. | ||
| 76 | VPrintf(1, "%s: reading suppressions file at %s\n", | ||
| 77 | SanitizerToolName, filename); | ||
| 78 | char *file_contents; | ||
| 79 | uptr buffer_size; | ||
| 80 | uptr contents_size; | ||
| 81 | if (!ReadFileToBuffer(filename, &file_contents, &buffer_size, | ||
| 82 | &contents_size)) { | ||
| 83 | Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName, | ||
| 84 | filename); | ||
| 85 | Die(); | ||
| 86 | } | ||
| 87 | |||
| 88 | Parse(file_contents); | ||
| 89 | } | ||
| 90 | |||
| 91 | bool SuppressionContext::Match(const char *str, const char *type, | ||
| 92 | Suppression **s) { | ||
| 93 | can_parse_ = false; | ||
| 94 | if (!HasSuppressionType(type)) | ||
| 95 | return false; | ||
| 96 | for (uptr i = 0; i < suppressions_.size(); i++) { | ||
| 97 | Suppression &cur = suppressions_[i]; | ||
| 98 | if (0 == internal_strcmp(cur.type, type) && TemplateMatch(cur.templ, str)) { | ||
| 99 | *s = &cur; | ||
| 100 | return true; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | return false; | ||
| 104 | } | ||
| 105 | |||
| 106 | static const char *StripPrefix(const char *str, const char *prefix) { | ||
| 107 | while (*str && *str == *prefix) { | ||
| 108 | str++; | ||
| 109 | prefix++; | ||
| 110 | } | ||
| 111 | if (!*prefix) | ||
| 112 | return str; | ||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | |||
| 116 | void SuppressionContext::Parse(const char *str) { | ||
| 117 | // Context must not mutate once Match has been called. | ||
| 118 | CHECK(can_parse_); | ||
| 119 | const char *line = str; | ||
| 120 | while (line) { | ||
| 121 | while (line[0] == ' ' || line[0] == '\t') | ||
| 122 | line++; | ||
| 123 | const char *end = internal_strchr(line, '\n'); | ||
| 124 | if (end == 0) | ||
| 125 | end = line + internal_strlen(line); | ||
| 126 | if (line != end && line[0] != '#') { | ||
| 127 | const char *end2 = end; | ||
| 128 | while (line != end2 && | ||
| 129 | (end2[-1] == ' ' || end2[-1] == '\t' || end2[-1] == '\r')) | ||
| 130 | end2--; | ||
| 131 | int type; | ||
| 132 | for (type = 0; type < suppression_types_num_; type++) { | ||
| 133 | const char *next_char = StripPrefix(line, suppression_types_[type]); | ||
| 134 | if (next_char && *next_char == ':') { | ||
| 135 | line = ++next_char; | ||
| 136 | break; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | if (type == suppression_types_num_) { | ||
| 140 | Printf("%s: failed to parse suppressions\n", SanitizerToolName); | ||
| 141 | Die(); | ||
| 142 | } | ||
| 143 | Suppression s; | ||
| 144 | s.type = suppression_types_[type]; | ||
| 145 | s.templ = (char*)InternalAlloc(end2 - line + 1); | ||
| 146 | internal_memcpy(s.templ, line, end2 - line); | ||
| 147 | s.templ[end2 - line] = 0; | ||
| 148 | suppressions_.push_back(s); | ||
| 149 | has_suppression_type_[type] = true; | ||
| 150 | } | ||
| 151 | if (end[0] == 0) | ||
| 152 | break; | ||
| 153 | line = end + 1; | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | uptr SuppressionContext::SuppressionCount() const { | ||
| 158 | return suppressions_.size(); | ||
| 159 | } | ||
| 160 | |||
| 161 | bool SuppressionContext::HasSuppressionType(const char *type) const { | ||
| 162 | for (int i = 0; i < suppression_types_num_; i++) { | ||
| 163 | if (0 == internal_strcmp(type, suppression_types_[i])) | ||
| 164 | return has_suppression_type_[i]; | ||
| 165 | } | ||
| 166 | return false; | ||
| 167 | } | ||
| 168 | |||
| 169 | const Suppression *SuppressionContext::SuppressionAt(uptr i) const { | ||
| 170 | CHECK_LT(i, suppressions_.size()); | ||
| 171 | return &suppressions_[i]; | ||
| 172 | } | ||
| 173 | |||
| 174 | void SuppressionContext::GetMatched( | ||
| 175 | InternalMmapVector<Suppression *> *matched) { | ||
| 176 | for (uptr i = 0; i < suppressions_.size(); i++) | ||
| 177 | if (atomic_load_relaxed(&suppressions_[i].hit_count)) | ||
| 178 | matched->push_back(&suppressions_[i]); | ||
| 179 | } | ||
| 180 | |||
| 181 | } // namespace __sanitizer | ||
lib/tsan/sanitizer_common/sanitizer_suppressions.h created+56| ... | @@ -0,0 +1,56 @@ | ||
| 1 | //===-- sanitizer_suppressions.h --------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Suppression parsing/matching code. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_SUPPRESSIONS_H | ||
| 13 | #define SANITIZER_SUPPRESSIONS_H | ||
| 14 | |||
| 15 | #include "sanitizer_common.h" | ||
| 16 | #include "sanitizer_atomic.h" | ||
| 17 | #include "sanitizer_internal_defs.h" | ||
| 18 | |||
| 19 | namespace __sanitizer { | ||
| 20 | |||
| 21 | struct Suppression { | ||
| 22 | Suppression() { internal_memset(this, 0, sizeof(*this)); } | ||
| 23 | const char *type; | ||
| 24 | char *templ; | ||
| 25 | atomic_uint32_t hit_count; | ||
| 26 | uptr weight; | ||
| 27 | }; | ||
| 28 | |||
| 29 | class SuppressionContext { | ||
| 30 | public: | ||
| 31 | // Create new SuppressionContext capable of parsing given suppression types. | ||
| 32 | SuppressionContext(const char *supprression_types[], | ||
| 33 | int suppression_types_num); | ||
| 34 | |||
| 35 | void ParseFromFile(const char *filename); | ||
| 36 | void Parse(const char *str); | ||
| 37 | |||
| 38 | bool Match(const char *str, const char *type, Suppression **s); | ||
| 39 | uptr SuppressionCount() const; | ||
| 40 | bool HasSuppressionType(const char *type) const; | ||
| 41 | const Suppression *SuppressionAt(uptr i) const; | ||
| 42 | void GetMatched(InternalMmapVector<Suppression *> *matched); | ||
| 43 | |||
| 44 | private: | ||
| 45 | static const int kMaxSuppressionTypes = 64; | ||
| 46 | const char **const suppression_types_; | ||
| 47 | const int suppression_types_num_; | ||
| 48 | |||
| 49 | InternalMmapVector<Suppression> suppressions_; | ||
| 50 | bool has_suppression_type_[kMaxSuppressionTypes]; | ||
| 51 | bool can_parse_; | ||
| 52 | }; | ||
| 53 | |||
| 54 | } // namespace __sanitizer | ||
| 55 | |||
| 56 | #endif // SANITIZER_SUPPRESSIONS_H | ||
lib/tsan/sanitizer_common/sanitizer_symbolizer.h created+223| ... | @@ -0,0 +1,223 @@ | ||
| 1 | //===-- sanitizer_symbolizer.h ----------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Symbolizer is used by sanitizers to map instruction address to a location in | ||
| 10 | // source code at run-time. Symbolizer either uses __sanitizer_symbolize_* | ||
| 11 | // defined in the program, or (if they are missing) tries to find and | ||
| 12 | // launch "llvm-symbolizer" commandline tool in a separate process and | ||
| 13 | // communicate with it. | ||
| 14 | // | ||
| 15 | // Generally we should try to avoid calling system library functions during | ||
| 16 | // symbolization (and use their replacements from sanitizer_libc.h instead). | ||
| 17 | //===----------------------------------------------------------------------===// | ||
| 18 | #ifndef SANITIZER_SYMBOLIZER_H | ||
| 19 | #define SANITIZER_SYMBOLIZER_H | ||
| 20 | |||
| 21 | #include "sanitizer_common.h" | ||
| 22 | #include "sanitizer_mutex.h" | ||
| 23 | #include "sanitizer_vector.h" | ||
| 24 | |||
| 25 | namespace __sanitizer { | ||
| 26 | |||
| 27 | struct AddressInfo { | ||
| 28 | // Owns all the string members. Storage for them is | ||
| 29 | // (de)allocated using sanitizer internal allocator. | ||
| 30 | uptr address; | ||
| 31 | |||
| 32 | char *module; | ||
| 33 | uptr module_offset; | ||
| 34 | ModuleArch module_arch; | ||
| 35 | |||
| 36 | static const uptr kUnknown = ~(uptr)0; | ||
| 37 | char *function; | ||
| 38 | uptr function_offset; | ||
| 39 | |||
| 40 | char *file; | ||
| 41 | int line; | ||
| 42 | int column; | ||
| 43 | |||
| 44 | AddressInfo(); | ||
| 45 | // Deletes all strings and resets all fields. | ||
| 46 | void Clear(); | ||
| 47 | void FillModuleInfo(const char *mod_name, uptr mod_offset, ModuleArch arch); | ||
| 48 | }; | ||
| 49 | |||
| 50 | // Linked list of symbolized frames (each frame is described by AddressInfo). | ||
| 51 | struct SymbolizedStack { | ||
| 52 | SymbolizedStack *next; | ||
| 53 | AddressInfo info; | ||
| 54 | static SymbolizedStack *New(uptr addr); | ||
| 55 | // Deletes current, and all subsequent frames in the linked list. | ||
| 56 | // The object cannot be accessed after the call to this function. | ||
| 57 | void ClearAll(); | ||
| 58 | |||
| 59 | private: | ||
| 60 | SymbolizedStack(); | ||
| 61 | }; | ||
| 62 | |||
| 63 | // For now, DataInfo is used to describe global variable. | ||
| 64 | struct DataInfo { | ||
| 65 | // Owns all the string members. Storage for them is | ||
| 66 | // (de)allocated using sanitizer internal allocator. | ||
| 67 | char *module; | ||
| 68 | uptr module_offset; | ||
| 69 | ModuleArch module_arch; | ||
| 70 | |||
| 71 | char *file; | ||
| 72 | uptr line; | ||
| 73 | char *name; | ||
| 74 | uptr start; | ||
| 75 | uptr size; | ||
| 76 | |||
| 77 | DataInfo(); | ||
| 78 | void Clear(); | ||
| 79 | }; | ||
| 80 | |||
| 81 | struct LocalInfo { | ||
| 82 | char *function_name = nullptr; | ||
| 83 | char *name = nullptr; | ||
| 84 | char *decl_file = nullptr; | ||
| 85 | unsigned decl_line = 0; | ||
| 86 | |||
| 87 | bool has_frame_offset = false; | ||
| 88 | bool has_size = false; | ||
| 89 | bool has_tag_offset = false; | ||
| 90 | |||
| 91 | sptr frame_offset; | ||
| 92 | uptr size; | ||
| 93 | uptr tag_offset; | ||
| 94 | |||
| 95 | void Clear(); | ||
| 96 | }; | ||
| 97 | |||
| 98 | struct FrameInfo { | ||
| 99 | char *module; | ||
| 100 | uptr module_offset; | ||
| 101 | ModuleArch module_arch; | ||
| 102 | |||
| 103 | InternalMmapVector<LocalInfo> locals; | ||
| 104 | void Clear(); | ||
| 105 | }; | ||
| 106 | |||
| 107 | class SymbolizerTool; | ||
| 108 | |||
| 109 | class Symbolizer final { | ||
| 110 | public: | ||
| 111 | /// Initialize and return platform-specific implementation of symbolizer | ||
| 112 | /// (if it wasn't already initialized). | ||
| 113 | static Symbolizer *GetOrInit(); | ||
| 114 | static void LateInitialize(); | ||
| 115 | // Returns a list of symbolized frames for a given address (containing | ||
| 116 | // all inlined functions, if necessary). | ||
| 117 | SymbolizedStack *SymbolizePC(uptr address); | ||
| 118 | bool SymbolizeData(uptr address, DataInfo *info); | ||
| 119 | bool SymbolizeFrame(uptr address, FrameInfo *info); | ||
| 120 | |||
| 121 | // The module names Symbolizer returns are stable and unique for every given | ||
| 122 | // module. It is safe to store and compare them as pointers. | ||
| 123 | bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, | ||
| 124 | uptr *module_address); | ||
| 125 | const char *GetModuleNameForPc(uptr pc) { | ||
| 126 | const char *module_name = nullptr; | ||
| 127 | uptr unused; | ||
| 128 | if (GetModuleNameAndOffsetForPC(pc, &module_name, &unused)) | ||
| 129 | return module_name; | ||
| 130 | return nullptr; | ||
| 131 | } | ||
| 132 | |||
| 133 | // Release internal caches (if any). | ||
| 134 | void Flush(); | ||
| 135 | // Attempts to demangle the provided C++ mangled name. | ||
| 136 | const char *Demangle(const char *name); | ||
| 137 | |||
| 138 | // Allow user to install hooks that would be called before/after Symbolizer | ||
| 139 | // does the actual file/line info fetching. Specific sanitizers may need this | ||
| 140 | // to distinguish system library calls made in user code from calls made | ||
| 141 | // during in-process symbolization. | ||
| 142 | typedef void (*StartSymbolizationHook)(); | ||
| 143 | typedef void (*EndSymbolizationHook)(); | ||
| 144 | // May be called at most once. | ||
| 145 | void AddHooks(StartSymbolizationHook start_hook, | ||
| 146 | EndSymbolizationHook end_hook); | ||
| 147 | |||
| 148 | void RefreshModules(); | ||
| 149 | const LoadedModule *FindModuleForAddress(uptr address); | ||
| 150 | |||
| 151 | void InvalidateModuleList(); | ||
| 152 | |||
| 153 | private: | ||
| 154 | // GetModuleNameAndOffsetForPC has to return a string to the caller. | ||
| 155 | // Since the corresponding module might get unloaded later, we should create | ||
| 156 | // our owned copies of the strings that we can safely return. | ||
| 157 | // ModuleNameOwner does not provide any synchronization, thus calls to | ||
| 158 | // its method should be protected by |mu_|. | ||
| 159 | class ModuleNameOwner { | ||
| 160 | public: | ||
| 161 | explicit ModuleNameOwner(BlockingMutex *synchronized_by) | ||
| 162 | : last_match_(nullptr), mu_(synchronized_by) { | ||
| 163 | storage_.reserve(kInitialCapacity); | ||
| 164 | } | ||
| 165 | const char *GetOwnedCopy(const char *str); | ||
| 166 | |||
| 167 | private: | ||
| 168 | static const uptr kInitialCapacity = 1000; | ||
| 169 | InternalMmapVector<const char*> storage_; | ||
| 170 | const char *last_match_; | ||
| 171 | |||
| 172 | BlockingMutex *mu_; | ||
| 173 | } module_names_; | ||
| 174 | |||
| 175 | /// Platform-specific function for creating a Symbolizer object. | ||
| 176 | static Symbolizer *PlatformInit(); | ||
| 177 | |||
| 178 | bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name, | ||
| 179 | uptr *module_offset, | ||
| 180 | ModuleArch *module_arch); | ||
| 181 | ListOfModules modules_; | ||
| 182 | ListOfModules fallback_modules_; | ||
| 183 | // If stale, need to reload the modules before looking up addresses. | ||
| 184 | bool modules_fresh_; | ||
| 185 | |||
| 186 | // Platform-specific default demangler, must not return nullptr. | ||
| 187 | const char *PlatformDemangle(const char *name); | ||
| 188 | |||
| 189 | static Symbolizer *symbolizer_; | ||
| 190 | static StaticSpinMutex init_mu_; | ||
| 191 | |||
| 192 | // Mutex locked from public methods of |Symbolizer|, so that the internals | ||
| 193 | // (including individual symbolizer tools and platform-specific methods) are | ||
| 194 | // always synchronized. | ||
| 195 | BlockingMutex mu_; | ||
| 196 | |||
| 197 | IntrusiveList<SymbolizerTool> tools_; | ||
| 198 | |||
| 199 | explicit Symbolizer(IntrusiveList<SymbolizerTool> tools); | ||
| 200 | |||
| 201 | static LowLevelAllocator symbolizer_allocator_; | ||
| 202 | |||
| 203 | StartSymbolizationHook start_hook_; | ||
| 204 | EndSymbolizationHook end_hook_; | ||
| 205 | class SymbolizerScope { | ||
| 206 | public: | ||
| 207 | explicit SymbolizerScope(const Symbolizer *sym); | ||
| 208 | ~SymbolizerScope(); | ||
| 209 | private: | ||
| 210 | const Symbolizer *sym_; | ||
| 211 | }; | ||
| 212 | |||
| 213 | // Calls `LateInitialize()` on all items in `tools_`. | ||
| 214 | void LateInitializeTools(); | ||
| 215 | }; | ||
| 216 | |||
| 217 | #ifdef SANITIZER_WINDOWS | ||
| 218 | void InitializeDbgHelpIfNeeded(); | ||
| 219 | #endif | ||
| 220 | |||
| 221 | } // namespace __sanitizer | ||
| 222 | |||
| 223 | #endif // SANITIZER_SYMBOLIZER_H | ||
lib/tsan/sanitizer_common/sanitizer_symbolizer_fuchsia.h created+42| ... | @@ -0,0 +1,42 @@ | ||
| 1 | //===-- sanitizer_symbolizer_fuchsia.h -----------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between various sanitizers' runtime libraries. | ||
| 10 | // | ||
| 11 | // Define Fuchsia's string formats and limits for the markup symbolizer. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | #ifndef SANITIZER_SYMBOLIZER_FUCHSIA_H | ||
| 14 | #define SANITIZER_SYMBOLIZER_FUCHSIA_H | ||
| 15 | |||
| 16 | #include "sanitizer_internal_defs.h" | ||
| 17 | |||
| 18 | namespace __sanitizer { | ||
| 19 | |||
| 20 | // See the spec at: | ||
| 21 | // https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md | ||
| 22 | |||
| 23 | // This is used by UBSan for type names, and by ASan for global variable names. | ||
| 24 | constexpr const char *kFormatDemangle = "{{{symbol:%s}}}"; | ||
| 25 | constexpr uptr kFormatDemangleMax = 1024; // Arbitrary. | ||
| 26 | |||
| 27 | // Function name or equivalent from PC location. | ||
| 28 | constexpr const char *kFormatFunction = "{{{pc:%p}}}"; | ||
| 29 | constexpr uptr kFormatFunctionMax = 64; // More than big enough for 64-bit hex. | ||
| 30 | |||
| 31 | // Global variable name or equivalent from data memory address. | ||
| 32 | constexpr const char *kFormatData = "{{{data:%p}}}"; | ||
| 33 | |||
| 34 | // One frame in a backtrace (printed on a line by itself). | ||
| 35 | constexpr const char *kFormatFrame = "{{{bt:%u:%p}}}"; | ||
| 36 | |||
| 37 | // Dump trigger element. | ||
| 38 | #define FORMAT_DUMPFILE "{{{dumpfile:%s:%s}}}" | ||
| 39 | |||
| 40 | } // namespace __sanitizer | ||
| 41 | |||
| 42 | #endif // SANITIZER_SYMBOLIZER_FUCHSIA_H | ||
lib/tsan/sanitizer_common/sanitizer_symbolizer_internal.h created+165| ... | @@ -0,0 +1,165 @@ | ||
| 1 | //===-- sanitizer_symbolizer_internal.h -------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Header for internal classes and functions to be used by implementations of | ||
| 10 | // symbolizers. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | #ifndef SANITIZER_SYMBOLIZER_INTERNAL_H | ||
| 14 | #define SANITIZER_SYMBOLIZER_INTERNAL_H | ||
| 15 | |||
| 16 | #include "sanitizer_symbolizer.h" | ||
| 17 | #include "sanitizer_file.h" | ||
| 18 | #include "sanitizer_vector.h" | ||
| 19 | |||
| 20 | namespace __sanitizer { | ||
| 21 | |||
| 22 | // Parsing helpers, 'str' is searched for delimiter(s) and a string or uptr | ||
| 23 | // is extracted. When extracting a string, a newly allocated (using | ||
| 24 | // InternalAlloc) and null-terminataed buffer is returned. They return a pointer | ||
| 25 | // to the next characted after the found delimiter. | ||
| 26 | const char *ExtractToken(const char *str, const char *delims, char **result); | ||
| 27 | const char *ExtractInt(const char *str, const char *delims, int *result); | ||
| 28 | const char *ExtractUptr(const char *str, const char *delims, uptr *result); | ||
| 29 | const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter, | ||
| 30 | char **result); | ||
| 31 | |||
| 32 | const char *DemangleSwiftAndCXX(const char *name); | ||
| 33 | |||
| 34 | // SymbolizerTool is an interface that is implemented by individual "tools" | ||
| 35 | // that can perform symbolication (external llvm-symbolizer, libbacktrace, | ||
| 36 | // Windows DbgHelp symbolizer, etc.). | ||
| 37 | class SymbolizerTool { | ||
| 38 | public: | ||
| 39 | // The main |Symbolizer| class implements a "fallback chain" of symbolizer | ||
| 40 | // tools. In a request to symbolize an address, if one tool returns false, | ||
| 41 | // the next tool in the chain will be tried. | ||
| 42 | SymbolizerTool *next; | ||
| 43 | |||
| 44 | SymbolizerTool() : next(nullptr) { } | ||
| 45 | |||
| 46 | // Can't declare pure virtual functions in sanitizer runtimes: | ||
| 47 | // __cxa_pure_virtual might be unavailable. | ||
| 48 | |||
| 49 | // The |stack| parameter is inout. It is pre-filled with the address, | ||
| 50 | // module base and module offset values and is to be used to construct | ||
| 51 | // other stack frames. | ||
| 52 | virtual bool SymbolizePC(uptr addr, SymbolizedStack *stack) { | ||
| 53 | UNIMPLEMENTED(); | ||
| 54 | } | ||
| 55 | |||
| 56 | // The |info| parameter is inout. It is pre-filled with the module base | ||
| 57 | // and module offset values. | ||
| 58 | virtual bool SymbolizeData(uptr addr, DataInfo *info) { | ||
| 59 | UNIMPLEMENTED(); | ||
| 60 | } | ||
| 61 | |||
| 62 | virtual bool SymbolizeFrame(uptr addr, FrameInfo *info) { | ||
| 63 | return false; | ||
| 64 | } | ||
| 65 | |||
| 66 | virtual void Flush() {} | ||
| 67 | |||
| 68 | // Return nullptr to fallback to the default platform-specific demangler. | ||
| 69 | virtual const char *Demangle(const char *name) { | ||
| 70 | return nullptr; | ||
| 71 | } | ||
| 72 | |||
| 73 | // Called during the LateInitialize phase of Sanitizer initialization. | ||
| 74 | // Usually this is a safe place to call code that might need to use user | ||
| 75 | // memory allocators. | ||
| 76 | virtual void LateInitialize() {} | ||
| 77 | }; | ||
| 78 | |||
| 79 | // SymbolizerProcess encapsulates communication between the tool and | ||
| 80 | // external symbolizer program, running in a different subprocess. | ||
| 81 | // SymbolizerProcess may not be used from two threads simultaneously. | ||
| 82 | class SymbolizerProcess { | ||
| 83 | public: | ||
| 84 | explicit SymbolizerProcess(const char *path, bool use_posix_spawn = false); | ||
| 85 | const char *SendCommand(const char *command); | ||
| 86 | |||
| 87 | protected: | ||
| 88 | /// The maximum number of arguments required to invoke a tool process. | ||
| 89 | static const unsigned kArgVMax = 6; | ||
| 90 | |||
| 91 | // Customizable by subclasses. | ||
| 92 | virtual bool StartSymbolizerSubprocess(); | ||
| 93 | virtual bool ReadFromSymbolizer(char *buffer, uptr max_length); | ||
| 94 | // Return the environment to run the symbolizer in. | ||
| 95 | virtual char **GetEnvP() { return GetEnviron(); } | ||
| 96 | |||
| 97 | private: | ||
| 98 | virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const { | ||
| 99 | UNIMPLEMENTED(); | ||
| 100 | } | ||
| 101 | |||
| 102 | /// Fill in an argv array to invoke the child process. | ||
| 103 | virtual void GetArgV(const char *path_to_binary, | ||
| 104 | const char *(&argv)[kArgVMax]) const { | ||
| 105 | UNIMPLEMENTED(); | ||
| 106 | } | ||
| 107 | |||
| 108 | bool Restart(); | ||
| 109 | const char *SendCommandImpl(const char *command); | ||
| 110 | bool WriteToSymbolizer(const char *buffer, uptr length); | ||
| 111 | |||
| 112 | const char *path_; | ||
| 113 | fd_t input_fd_; | ||
| 114 | fd_t output_fd_; | ||
| 115 | |||
| 116 | static const uptr kBufferSize = 16 * 1024; | ||
| 117 | char buffer_[kBufferSize]; | ||
| 118 | |||
| 119 | static const uptr kMaxTimesRestarted = 5; | ||
| 120 | static const int kSymbolizerStartupTimeMillis = 10; | ||
| 121 | uptr times_restarted_; | ||
| 122 | bool failed_to_start_; | ||
| 123 | bool reported_invalid_path_; | ||
| 124 | bool use_posix_spawn_; | ||
| 125 | }; | ||
| 126 | |||
| 127 | class LLVMSymbolizerProcess; | ||
| 128 | |||
| 129 | // This tool invokes llvm-symbolizer in a subprocess. It should be as portable | ||
| 130 | // as the llvm-symbolizer tool is. | ||
| 131 | class LLVMSymbolizer : public SymbolizerTool { | ||
| 132 | public: | ||
| 133 | explicit LLVMSymbolizer(const char *path, LowLevelAllocator *allocator); | ||
| 134 | |||
| 135 | bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; | ||
| 136 | bool SymbolizeData(uptr addr, DataInfo *info) override; | ||
| 137 | bool SymbolizeFrame(uptr addr, FrameInfo *info) override; | ||
| 138 | |||
| 139 | private: | ||
| 140 | const char *FormatAndSendCommand(const char *command_prefix, | ||
| 141 | const char *module_name, uptr module_offset, | ||
| 142 | ModuleArch arch); | ||
| 143 | |||
| 144 | LLVMSymbolizerProcess *symbolizer_process_; | ||
| 145 | static const uptr kBufferSize = 16 * 1024; | ||
| 146 | char buffer_[kBufferSize]; | ||
| 147 | }; | ||
| 148 | |||
| 149 | // Parses one or more two-line strings in the following format: | ||
| 150 | // <function_name> | ||
| 151 | // <file_name>:<line_number>[:<column_number>] | ||
| 152 | // Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of | ||
| 153 | // them use the same output format. Returns true if any useful debug | ||
| 154 | // information was found. | ||
| 155 | void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res); | ||
| 156 | |||
| 157 | // Parses a two-line string in the following format: | ||
| 158 | // <symbol_name> | ||
| 159 | // <start_address> <size> | ||
| 160 | // Used by LLVMSymbolizer and InternalSymbolizer. | ||
| 161 | void ParseSymbolizeDataOutput(const char *str, DataInfo *info); | ||
| 162 | |||
| 163 | } // namespace __sanitizer | ||
| 164 | |||
| 165 | #endif // SANITIZER_SYMBOLIZER_INTERNAL_H | ||
lib/tsan/sanitizer_common/sanitizer_symbolizer_libbacktrace.h created+49| ... | @@ -0,0 +1,49 @@ | ||
| 1 | //===-- sanitizer_symbolizer_libbacktrace.h ---------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer | ||
| 10 | // run-time libraries. | ||
| 11 | // Header for libbacktrace symbolizer. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | #ifndef SANITIZER_SYMBOLIZER_LIBBACKTRACE_H | ||
| 14 | #define SANITIZER_SYMBOLIZER_LIBBACKTRACE_H | ||
| 15 | |||
| 16 | #include "sanitizer_platform.h" | ||
| 17 | #include "sanitizer_common.h" | ||
| 18 | #include "sanitizer_allocator_internal.h" | ||
| 19 | #include "sanitizer_symbolizer_internal.h" | ||
| 20 | |||
| 21 | #ifndef SANITIZER_LIBBACKTRACE | ||
| 22 | # define SANITIZER_LIBBACKTRACE 0 | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #ifndef SANITIZER_CP_DEMANGLE | ||
| 26 | # define SANITIZER_CP_DEMANGLE 0 | ||
| 27 | #endif | ||
| 28 | |||
| 29 | namespace __sanitizer { | ||
| 30 | |||
| 31 | class LibbacktraceSymbolizer : public SymbolizerTool { | ||
| 32 | public: | ||
| 33 | static LibbacktraceSymbolizer *get(LowLevelAllocator *alloc); | ||
| 34 | |||
| 35 | bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; | ||
| 36 | |||
| 37 | bool SymbolizeData(uptr addr, DataInfo *info) override; | ||
| 38 | |||
| 39 | // May return NULL if demangling failed. | ||
| 40 | const char *Demangle(const char *name) override; | ||
| 41 | |||
| 42 | private: | ||
| 43 | explicit LibbacktraceSymbolizer(void *state) : state_(state) {} | ||
| 44 | |||
| 45 | void *state_; // Leaked. | ||
| 46 | }; | ||
| 47 | |||
| 48 | } // namespace __sanitizer | ||
| 49 | #endif // SANITIZER_SYMBOLIZER_LIBBACKTRACE_H | ||
lib/tsan/sanitizer_common/sanitizer_symbolizer_mac.h created+48| ... | @@ -0,0 +1,48 @@ | ||
| 1 | //===-- sanitizer_symbolizer_mac.h ------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between various sanitizers' runtime libraries. | ||
| 10 | // | ||
| 11 | // Header for Mac-specific "atos" symbolizer. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_SYMBOLIZER_MAC_H | ||
| 15 | #define SANITIZER_SYMBOLIZER_MAC_H | ||
| 16 | |||
| 17 | #include "sanitizer_platform.h" | ||
| 18 | #if SANITIZER_MAC | ||
| 19 | |||
| 20 | #include "sanitizer_symbolizer_internal.h" | ||
| 21 | |||
| 22 | namespace __sanitizer { | ||
| 23 | |||
| 24 | class DlAddrSymbolizer : public SymbolizerTool { | ||
| 25 | public: | ||
| 26 | bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; | ||
| 27 | bool SymbolizeData(uptr addr, DataInfo *info) override; | ||
| 28 | }; | ||
| 29 | |||
| 30 | class AtosSymbolizerProcess; | ||
| 31 | |||
| 32 | class AtosSymbolizer : public SymbolizerTool { | ||
| 33 | public: | ||
| 34 | explicit AtosSymbolizer(const char *path, LowLevelAllocator *allocator); | ||
| 35 | |||
| 36 | bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; | ||
| 37 | bool SymbolizeData(uptr addr, DataInfo *info) override; | ||
| 38 | void LateInitialize() override; | ||
| 39 | |||
| 40 | private: | ||
| 41 | AtosSymbolizerProcess *process_; | ||
| 42 | }; | ||
| 43 | |||
| 44 | } // namespace __sanitizer | ||
| 45 | |||
| 46 | #endif // SANITIZER_MAC | ||
| 47 | |||
| 48 | #endif // SANITIZER_SYMBOLIZER_MAC_H | ||
lib/tsan/sanitizer_common/sanitizer_symbolizer_rtems.h created+40| ... | @@ -0,0 +1,40 @@ | ||
| 1 | //===-- sanitizer_symbolizer_rtems.h -----------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between various sanitizers' runtime libraries. | ||
| 10 | // | ||
| 11 | // Define RTEMS's string formats and limits for the markup symbolizer. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | #ifndef SANITIZER_SYMBOLIZER_RTEMS_H | ||
| 14 | #define SANITIZER_SYMBOLIZER_RTEMS_H | ||
| 15 | |||
| 16 | #include "sanitizer_internal_defs.h" | ||
| 17 | |||
| 18 | namespace __sanitizer { | ||
| 19 | |||
| 20 | // The Myriad RTEMS symbolizer currently only parses backtrace lines, | ||
| 21 | // so use a format that the symbolizer understands. For other | ||
| 22 | // markups, keep them the same as the Fuchsia's. | ||
| 23 | |||
| 24 | // This is used by UBSan for type names, and by ASan for global variable names. | ||
| 25 | constexpr const char *kFormatDemangle = "{{{symbol:%s}}}"; | ||
| 26 | constexpr uptr kFormatDemangleMax = 1024; // Arbitrary. | ||
| 27 | |||
| 28 | // Function name or equivalent from PC location. | ||
| 29 | constexpr const char *kFormatFunction = "{{{pc:%p}}}"; | ||
| 30 | constexpr uptr kFormatFunctionMax = 64; // More than big enough for 64-bit hex. | ||
| 31 | |||
| 32 | // Global variable name or equivalent from data memory address. | ||
| 33 | constexpr const char *kFormatData = "{{{data:%p}}}"; | ||
| 34 | |||
| 35 | // One frame in a backtrace (printed on a line by itself). | ||
| 36 | constexpr const char *kFormatFrame = " [%u] IP: %p"; | ||
| 37 | |||
| 38 | } // namespace __sanitizer | ||
| 39 | |||
| 40 | #endif // SANITIZER_SYMBOLIZER_RTEMS_H | ||
lib/tsan/sanitizer_common/sanitizer_syscall_generic.inc created+38| ... | @@ -0,0 +1,38 @@ | ||
| 1 | //===-- sanitizer_syscall_generic.inc ---------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Generic implementations of internal_syscall* and internal_iserror. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | // NetBSD uses libc calls directly | ||
| 14 | #if !SANITIZER_NETBSD | ||
| 15 | |||
| 16 | #if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_SOLARIS | ||
| 17 | # define SYSCALL(name) SYS_ ## name | ||
| 18 | #else | ||
| 19 | # define SYSCALL(name) __NR_ ## name | ||
| 20 | #endif | ||
| 21 | |||
| 22 | #if defined(__x86_64__) && (SANITIZER_FREEBSD || SANITIZER_MAC) | ||
| 23 | # define internal_syscall __syscall | ||
| 24 | # else | ||
| 25 | # define internal_syscall syscall | ||
| 26 | #endif | ||
| 27 | |||
| 28 | #endif | ||
| 29 | |||
| 30 | bool internal_iserror(uptr retval, int *rverrno) { | ||
| 31 | if (retval == (uptr)-1) { | ||
| 32 | if (rverrno) | ||
| 33 | *rverrno = errno; | ||
| 34 | return true; | ||
| 35 | } else { | ||
| 36 | return false; | ||
| 37 | } | ||
| 38 | } | ||
lib/tsan/sanitizer_common/sanitizer_syscall_linux_aarch64.inc created+137| ... | @@ -0,0 +1,137 @@ | ||
| 1 | //===-- sanitizer_syscall_linux_aarch64.inc --------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Implementations of internal_syscall and internal_iserror for Linux/aarch64. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #define SYSCALL(name) __NR_ ## name | ||
| 14 | |||
| 15 | static uptr __internal_syscall(u64 nr) { | ||
| 16 | register u64 x8 asm("x8") = nr; | ||
| 17 | register u64 x0 asm("x0"); | ||
| 18 | asm volatile("svc 0" | ||
| 19 | : "=r"(x0) | ||
| 20 | : "r"(x8) | ||
| 21 | : "memory", "cc"); | ||
| 22 | return x0; | ||
| 23 | } | ||
| 24 | #define __internal_syscall0(n) \ | ||
| 25 | (__internal_syscall)(n) | ||
| 26 | |||
| 27 | static uptr __internal_syscall(u64 nr, u64 arg1) { | ||
| 28 | register u64 x8 asm("x8") = nr; | ||
| 29 | register u64 x0 asm("x0") = arg1; | ||
| 30 | asm volatile("svc 0" | ||
| 31 | : "=r"(x0) | ||
| 32 | : "r"(x8), "0"(x0) | ||
| 33 | : "memory", "cc"); | ||
| 34 | return x0; | ||
| 35 | } | ||
| 36 | #define __internal_syscall1(n, a1) \ | ||
| 37 | (__internal_syscall)(n, (u64)(a1)) | ||
| 38 | |||
| 39 | static uptr __internal_syscall(u64 nr, u64 arg1, long arg2) { | ||
| 40 | register u64 x8 asm("x8") = nr; | ||
| 41 | register u64 x0 asm("x0") = arg1; | ||
| 42 | register u64 x1 asm("x1") = arg2; | ||
| 43 | asm volatile("svc 0" | ||
| 44 | : "=r"(x0) | ||
| 45 | : "r"(x8), "0"(x0), "r"(x1) | ||
| 46 | : "memory", "cc"); | ||
| 47 | return x0; | ||
| 48 | } | ||
| 49 | #define __internal_syscall2(n, a1, a2) \ | ||
| 50 | (__internal_syscall)(n, (u64)(a1), (long)(a2)) | ||
| 51 | |||
| 52 | static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3) { | ||
| 53 | register u64 x8 asm("x8") = nr; | ||
| 54 | register u64 x0 asm("x0") = arg1; | ||
| 55 | register u64 x1 asm("x1") = arg2; | ||
| 56 | register u64 x2 asm("x2") = arg3; | ||
| 57 | asm volatile("svc 0" | ||
| 58 | : "=r"(x0) | ||
| 59 | : "r"(x8), "0"(x0), "r"(x1), "r"(x2) | ||
| 60 | : "memory", "cc"); | ||
| 61 | return x0; | ||
| 62 | } | ||
| 63 | #define __internal_syscall3(n, a1, a2, a3) \ | ||
| 64 | (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3)) | ||
| 65 | |||
| 66 | static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, | ||
| 67 | u64 arg4) { | ||
| 68 | register u64 x8 asm("x8") = nr; | ||
| 69 | register u64 x0 asm("x0") = arg1; | ||
| 70 | register u64 x1 asm("x1") = arg2; | ||
| 71 | register u64 x2 asm("x2") = arg3; | ||
| 72 | register u64 x3 asm("x3") = arg4; | ||
| 73 | asm volatile("svc 0" | ||
| 74 | : "=r"(x0) | ||
| 75 | : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3) | ||
| 76 | : "memory", "cc"); | ||
| 77 | return x0; | ||
| 78 | } | ||
| 79 | #define __internal_syscall4(n, a1, a2, a3, a4) \ | ||
| 80 | (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4)) | ||
| 81 | |||
| 82 | static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, | ||
| 83 | u64 arg4, long arg5) { | ||
| 84 | register u64 x8 asm("x8") = nr; | ||
| 85 | register u64 x0 asm("x0") = arg1; | ||
| 86 | register u64 x1 asm("x1") = arg2; | ||
| 87 | register u64 x2 asm("x2") = arg3; | ||
| 88 | register u64 x3 asm("x3") = arg4; | ||
| 89 | register u64 x4 asm("x4") = arg5; | ||
| 90 | asm volatile("svc 0" | ||
| 91 | : "=r"(x0) | ||
| 92 | : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4) | ||
| 93 | : "memory", "cc"); | ||
| 94 | return x0; | ||
| 95 | } | ||
| 96 | #define __internal_syscall5(n, a1, a2, a3, a4, a5) \ | ||
| 97 | (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \ | ||
| 98 | (u64)(a5)) | ||
| 99 | |||
| 100 | static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, | ||
| 101 | u64 arg4, long arg5, long arg6) { | ||
| 102 | register u64 x8 asm("x8") = nr; | ||
| 103 | register u64 x0 asm("x0") = arg1; | ||
| 104 | register u64 x1 asm("x1") = arg2; | ||
| 105 | register u64 x2 asm("x2") = arg3; | ||
| 106 | register u64 x3 asm("x3") = arg4; | ||
| 107 | register u64 x4 asm("x4") = arg5; | ||
| 108 | register u64 x5 asm("x5") = arg6; | ||
| 109 | asm volatile("svc 0" | ||
| 110 | : "=r"(x0) | ||
| 111 | : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5) | ||
| 112 | : "memory", "cc"); | ||
| 113 | return x0; | ||
| 114 | } | ||
| 115 | #define __internal_syscall6(n, a1, a2, a3, a4, a5, a6) \ | ||
| 116 | (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \ | ||
| 117 | (u64)(a5), (long)(a6)) | ||
| 118 | |||
| 119 | #define __SYSCALL_NARGS_X(a1, a2, a3, a4, a5, a6, a7, a8, n, ...) n | ||
| 120 | #define __SYSCALL_NARGS(...) \ | ||
| 121 | __SYSCALL_NARGS_X(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0, ) | ||
| 122 | #define __SYSCALL_CONCAT_X(a, b) a##b | ||
| 123 | #define __SYSCALL_CONCAT(a, b) __SYSCALL_CONCAT_X(a, b) | ||
| 124 | #define __SYSCALL_DISP(b, ...) \ | ||
| 125 | __SYSCALL_CONCAT(b, __SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) | ||
| 126 | |||
| 127 | #define internal_syscall(...) __SYSCALL_DISP(__internal_syscall, __VA_ARGS__) | ||
| 128 | |||
| 129 | // Helper function used to avoid cobbler errno. | ||
| 130 | bool internal_iserror(uptr retval, int *rverrno) { | ||
| 131 | if (retval >= (uptr)-4095) { | ||
| 132 | if (rverrno) | ||
| 133 | *rverrno = -retval; | ||
| 134 | return true; | ||
| 135 | } | ||
| 136 | return false; | ||
| 137 | } | ||
lib/tsan/sanitizer_common/sanitizer_syscall_linux_arm.inc created+137| ... | @@ -0,0 +1,137 @@ | ||
| 1 | //===-- sanitizer_syscall_linux_arm.inc -------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Implementations of internal_syscall and internal_iserror for Linux/arm. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #define SYSCALL(name) __NR_ ## name | ||
| 14 | |||
| 15 | static uptr __internal_syscall(u32 nr) { | ||
| 16 | register u32 r8 asm("r7") = nr; | ||
| 17 | register u32 r0 asm("r0"); | ||
| 18 | asm volatile("swi #0" | ||
| 19 | : "=r"(r0) | ||
| 20 | : "r"(r8) | ||
| 21 | : "memory", "cc"); | ||
| 22 | return r0; | ||
| 23 | } | ||
| 24 | #define __internal_syscall0(n) \ | ||
| 25 | (__internal_syscall)(n) | ||
| 26 | |||
| 27 | static uptr __internal_syscall(u32 nr, u32 arg1) { | ||
| 28 | register u32 r8 asm("r7") = nr; | ||
| 29 | register u32 r0 asm("r0") = arg1; | ||
| 30 | asm volatile("swi #0" | ||
| 31 | : "=r"(r0) | ||
| 32 | : "r"(r8), "0"(r0) | ||
| 33 | : "memory", "cc"); | ||
| 34 | return r0; | ||
| 35 | } | ||
| 36 | #define __internal_syscall1(n, a1) \ | ||
| 37 | (__internal_syscall)(n, (u32)(a1)) | ||
| 38 | |||
| 39 | static uptr __internal_syscall(u32 nr, u32 arg1, long arg2) { | ||
| 40 | register u32 r8 asm("r7") = nr; | ||
| 41 | register u32 r0 asm("r0") = arg1; | ||
| 42 | register u32 r1 asm("r1") = arg2; | ||
| 43 | asm volatile("swi #0" | ||
| 44 | : "=r"(r0) | ||
| 45 | : "r"(r8), "0"(r0), "r"(r1) | ||
| 46 | : "memory", "cc"); | ||
| 47 | return r0; | ||
| 48 | } | ||
| 49 | #define __internal_syscall2(n, a1, a2) \ | ||
| 50 | (__internal_syscall)(n, (u32)(a1), (long)(a2)) | ||
| 51 | |||
| 52 | static uptr __internal_syscall(u32 nr, u32 arg1, long arg2, long arg3) { | ||
| 53 | register u32 r8 asm("r7") = nr; | ||
| 54 | register u32 r0 asm("r0") = arg1; | ||
| 55 | register u32 r1 asm("r1") = arg2; | ||
| 56 | register u32 r2 asm("r2") = arg3; | ||
| 57 | asm volatile("swi #0" | ||
| 58 | : "=r"(r0) | ||
| 59 | : "r"(r8), "0"(r0), "r"(r1), "r"(r2) | ||
| 60 | : "memory", "cc"); | ||
| 61 | return r0; | ||
| 62 | } | ||
| 63 | #define __internal_syscall3(n, a1, a2, a3) \ | ||
| 64 | (__internal_syscall)(n, (u32)(a1), (long)(a2), (long)(a3)) | ||
| 65 | |||
| 66 | static uptr __internal_syscall(u32 nr, u32 arg1, long arg2, long arg3, | ||
| 67 | u32 arg4) { | ||
| 68 | register u32 r8 asm("r7") = nr; | ||
| 69 | register u32 r0 asm("r0") = arg1; | ||
| 70 | register u32 r1 asm("r1") = arg2; | ||
| 71 | register u32 r2 asm("r2") = arg3; | ||
| 72 | register u32 r3 asm("r3") = arg4; | ||
| 73 | asm volatile("swi #0" | ||
| 74 | : "=r"(r0) | ||
| 75 | : "r"(r8), "0"(r0), "r"(r1), "r"(r2), "r"(r3) | ||
| 76 | : "memory", "cc"); | ||
| 77 | return r0; | ||
| 78 | } | ||
| 79 | #define __internal_syscall4(n, a1, a2, a3, a4) \ | ||
| 80 | (__internal_syscall)(n, (u32)(a1), (long)(a2), (long)(a3), (long)(a4)) | ||
| 81 | |||
| 82 | static uptr __internal_syscall(u32 nr, u32 arg1, long arg2, long arg3, | ||
| 83 | u32 arg4, long arg5) { | ||
| 84 | register u32 r8 asm("r7") = nr; | ||
| 85 | register u32 r0 asm("r0") = arg1; | ||
| 86 | register u32 r1 asm("r1") = arg2; | ||
| 87 | register u32 r2 asm("r2") = arg3; | ||
| 88 | register u32 r3 asm("r3") = arg4; | ||
| 89 | register u32 r4 asm("r4") = arg5; | ||
| 90 | asm volatile("swi #0" | ||
| 91 | : "=r"(r0) | ||
| 92 | : "r"(r8), "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4) | ||
| 93 | : "memory", "cc"); | ||
| 94 | return r0; | ||
| 95 | } | ||
| 96 | #define __internal_syscall5(n, a1, a2, a3, a4, a5) \ | ||
| 97 | (__internal_syscall)(n, (u32)(a1), (long)(a2), (long)(a3), (long)(a4), \ | ||
| 98 | (u32)(a5)) | ||
| 99 | |||
| 100 | static uptr __internal_syscall(u32 nr, u32 arg1, long arg2, long arg3, | ||
| 101 | u32 arg4, long arg5, long arg6) { | ||
| 102 | register u32 r8 asm("r7") = nr; | ||
| 103 | register u32 r0 asm("r0") = arg1; | ||
| 104 | register u32 r1 asm("r1") = arg2; | ||
| 105 | register u32 r2 asm("r2") = arg3; | ||
| 106 | register u32 r3 asm("r3") = arg4; | ||
| 107 | register u32 r4 asm("r4") = arg5; | ||
| 108 | register u32 r5 asm("r5") = arg6; | ||
| 109 | asm volatile("swi #0" | ||
| 110 | : "=r"(r0) | ||
| 111 | : "r"(r8), "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5) | ||
| 112 | : "memory", "cc"); | ||
| 113 | return r0; | ||
| 114 | } | ||
| 115 | #define __internal_syscall6(n, a1, a2, a3, a4, a5, a6) \ | ||
| 116 | (__internal_syscall)(n, (u32)(a1), (long)(a2), (long)(a3), (long)(a4), \ | ||
| 117 | (u32)(a5), (long)(a6)) | ||
| 118 | |||
| 119 | #define __SYSCALL_NARGS_X(a1, a2, a3, a4, a5, a6, a7, a8, n, ...) n | ||
| 120 | #define __SYSCALL_NARGS(...) \ | ||
| 121 | __SYSCALL_NARGS_X(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0, ) | ||
| 122 | #define __SYSCALL_CONCAT_X(a, b) a##b | ||
| 123 | #define __SYSCALL_CONCAT(a, b) __SYSCALL_CONCAT_X(a, b) | ||
| 124 | #define __SYSCALL_DISP(b, ...) \ | ||
| 125 | __SYSCALL_CONCAT(b, __SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) | ||
| 126 | |||
| 127 | #define internal_syscall(...) __SYSCALL_DISP(__internal_syscall, __VA_ARGS__) | ||
| 128 | |||
| 129 | // Helper function used to avoid cobbler errno. | ||
| 130 | bool internal_iserror(uptr retval, int *rverrno) { | ||
| 131 | if (retval >= (uptr)-4095) { | ||
| 132 | if (rverrno) | ||
| 133 | *rverrno = -retval; | ||
| 134 | return true; | ||
| 135 | } | ||
| 136 | return false; | ||
| 137 | } | ||
lib/tsan/sanitizer_common/sanitizer_syscall_linux_x86_64.inc created+90| ... | @@ -0,0 +1,90 @@ | ||
| 1 | //===-- sanitizer_syscall_linux_x86_64.inc ----------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Implementations of internal_syscall and internal_iserror for Linux/x86_64. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #define SYSCALL(name) __NR_ ## name | ||
| 14 | |||
| 15 | static uptr internal_syscall(u64 nr) { | ||
| 16 | u64 retval; | ||
| 17 | asm volatile("syscall" : "=a"(retval) : "a"(nr) : "rcx", "r11", | ||
| 18 | "memory", "cc"); | ||
| 19 | return retval; | ||
| 20 | } | ||
| 21 | |||
| 22 | template <typename T1> | ||
| 23 | static uptr internal_syscall(u64 nr, T1 arg1) { | ||
| 24 | u64 retval; | ||
| 25 | asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1) : | ||
| 26 | "rcx", "r11", "memory", "cc"); | ||
| 27 | return retval; | ||
| 28 | } | ||
| 29 | |||
| 30 | template <typename T1, typename T2> | ||
| 31 | static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2) { | ||
| 32 | u64 retval; | ||
| 33 | asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1), | ||
| 34 | "S"((u64)arg2) : "rcx", "r11", "memory", "cc"); | ||
| 35 | return retval; | ||
| 36 | } | ||
| 37 | |||
| 38 | template <typename T1, typename T2, typename T3> | ||
| 39 | static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3) { | ||
| 40 | u64 retval; | ||
| 41 | asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1), | ||
| 42 | "S"((u64)arg2), "d"((u64)arg3) : "rcx", "r11", "memory", "cc"); | ||
| 43 | return retval; | ||
| 44 | } | ||
| 45 | |||
| 46 | template <typename T1, typename T2, typename T3, typename T4> | ||
| 47 | static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4) { | ||
| 48 | u64 retval; | ||
| 49 | asm volatile("mov %5, %%r10;" | ||
| 50 | "syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1), | ||
| 51 | "S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4) : | ||
| 52 | "rcx", "r11", "r10", "memory", "cc"); | ||
| 53 | return retval; | ||
| 54 | } | ||
| 55 | |||
| 56 | template <typename T1, typename T2, typename T3, typename T4, typename T5> | ||
| 57 | static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4, | ||
| 58 | T5 arg5) { | ||
| 59 | u64 retval; | ||
| 60 | asm volatile("mov %5, %%r10;" | ||
| 61 | "mov %6, %%r8;" | ||
| 62 | "syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1), | ||
| 63 | "S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5) : | ||
| 64 | "rcx", "r11", "r10", "r8", "memory", "cc"); | ||
| 65 | return retval; | ||
| 66 | } | ||
| 67 | |||
| 68 | template <typename T1, typename T2, typename T3, typename T4, typename T5, | ||
| 69 | typename T6> | ||
| 70 | static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4, | ||
| 71 | T5 arg5, T6 arg6) { | ||
| 72 | u64 retval; | ||
| 73 | asm volatile("mov %5, %%r10;" | ||
| 74 | "mov %6, %%r8;" | ||
| 75 | "mov %7, %%r9;" | ||
| 76 | "syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1), | ||
| 77 | "S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5), | ||
| 78 | "r"((u64)arg6) : "rcx", "r11", "r10", "r8", "r9", | ||
| 79 | "memory", "cc"); | ||
| 80 | return retval; | ||
| 81 | } | ||
| 82 | |||
| 83 | bool internal_iserror(uptr retval, int *rverrno) { | ||
| 84 | if (retval >= (uptr)-4095) { | ||
| 85 | if (rverrno) | ||
| 86 | *rverrno = -retval; | ||
| 87 | return true; | ||
| 88 | } | ||
| 89 | return false; | ||
| 90 | } | ||
lib/tsan/sanitizer_common/sanitizer_syscalls_netbsd.inc created+3837| ... | @@ -0,0 +1,3837 @@ | ||
| 1 | //===-- sanitizer_syscalls_netbsd.inc ---------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Common syscalls handlers for tools like AddressSanitizer, | ||
| 10 | // ThreadSanitizer, MemorySanitizer, etc. | ||
| 11 | // | ||
| 12 | // This file should be included into the tool's interceptor file, | ||
| 13 | // which has to define it's own macros: | ||
| 14 | // COMMON_SYSCALL_PRE_READ_RANGE | ||
| 15 | // Called in prehook for regions that will be read by the kernel and | ||
| 16 | // must be initialized. | ||
| 17 | // COMMON_SYSCALL_PRE_WRITE_RANGE | ||
| 18 | // Called in prehook for regions that will be written to by the kernel | ||
| 19 | // and must be addressable. The actual write range may be smaller than | ||
| 20 | // reported in the prehook. See POST_WRITE_RANGE. | ||
| 21 | // COMMON_SYSCALL_POST_READ_RANGE | ||
| 22 | // Called in posthook for regions that were read by the kernel. Does | ||
| 23 | // not make much sense. | ||
| 24 | // COMMON_SYSCALL_POST_WRITE_RANGE | ||
| 25 | // Called in posthook for regions that were written to by the kernel | ||
| 26 | // and are now initialized. | ||
| 27 | // COMMON_SYSCALL_ACQUIRE(addr) | ||
| 28 | // Acquire memory visibility from addr. | ||
| 29 | // COMMON_SYSCALL_RELEASE(addr) | ||
| 30 | // Release memory visibility to addr. | ||
| 31 | // COMMON_SYSCALL_FD_CLOSE(fd) | ||
| 32 | // Called before closing file descriptor fd. | ||
| 33 | // COMMON_SYSCALL_FD_ACQUIRE(fd) | ||
| 34 | // Acquire memory visibility from fd. | ||
| 35 | // COMMON_SYSCALL_FD_RELEASE(fd) | ||
| 36 | // Release memory visibility to fd. | ||
| 37 | // COMMON_SYSCALL_PRE_FORK() | ||
| 38 | // Called before fork syscall. | ||
| 39 | // COMMON_SYSCALL_POST_FORK(long long res) | ||
| 40 | // Called after fork syscall. | ||
| 41 | // | ||
| 42 | // DO NOT EDIT! THIS FILE HAS BEEN GENERATED! | ||
| 43 | // | ||
| 44 | // Generated with: generate_netbsd_syscalls.awk | ||
| 45 | // Generated date: 2019-12-24 | ||
| 46 | // Generated from: syscalls.master,v 1.296 2019/09/22 22:59:39 christos Exp | ||
| 47 | // | ||
| 48 | //===----------------------------------------------------------------------===// | ||
| 49 | |||
| 50 | #include "sanitizer_platform.h" | ||
| 51 | #if SANITIZER_NETBSD | ||
| 52 | |||
| 53 | #include "sanitizer_libc.h" | ||
| 54 | |||
| 55 | #define PRE_SYSCALL(name) \ | ||
| 56 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name | ||
| 57 | #define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s) | ||
| 58 | #define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) | ||
| 59 | |||
| 60 | #define POST_SYSCALL(name) \ | ||
| 61 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_impl_##name | ||
| 62 | #define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s) | ||
| 63 | #define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s) | ||
| 64 | |||
| 65 | #ifndef COMMON_SYSCALL_ACQUIRE | ||
| 66 | #define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr)) | ||
| 67 | #endif | ||
| 68 | |||
| 69 | #ifndef COMMON_SYSCALL_RELEASE | ||
| 70 | #define COMMON_SYSCALL_RELEASE(addr) ((void)(addr)) | ||
| 71 | #endif | ||
| 72 | |||
| 73 | #ifndef COMMON_SYSCALL_FD_CLOSE | ||
| 74 | #define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd)) | ||
| 75 | #endif | ||
| 76 | |||
| 77 | #ifndef COMMON_SYSCALL_FD_ACQUIRE | ||
| 78 | #define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd)) | ||
| 79 | #endif | ||
| 80 | |||
| 81 | #ifndef COMMON_SYSCALL_FD_RELEASE | ||
| 82 | #define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd)) | ||
| 83 | #endif | ||
| 84 | |||
| 85 | #ifndef COMMON_SYSCALL_PRE_FORK | ||
| 86 | #define COMMON_SYSCALL_PRE_FORK() \ | ||
| 87 | {} | ||
| 88 | #endif | ||
| 89 | |||
| 90 | #ifndef COMMON_SYSCALL_POST_FORK | ||
| 91 | #define COMMON_SYSCALL_POST_FORK(res) \ | ||
| 92 | {} | ||
| 93 | #endif | ||
| 94 | |||
| 95 | // FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such). | ||
| 96 | |||
| 97 | extern "C" { | ||
| 98 | #define SYS_MAXSYSARGS 8 | ||
| 99 | PRE_SYSCALL(syscall)(long long code_, long long args_[SYS_MAXSYSARGS]) { | ||
| 100 | /* Nothing to do */ | ||
| 101 | } | ||
| 102 | POST_SYSCALL(syscall) | ||
| 103 | (long long res, long long code_, long long args_[SYS_MAXSYSARGS]) { | ||
| 104 | /* Nothing to do */ | ||
| 105 | } | ||
| 106 | PRE_SYSCALL(exit)(long long rval_) { /* Nothing to do */ } | ||
| 107 | POST_SYSCALL(exit)(long long res, long long rval_) { /* Nothing to do */ } | ||
| 108 | PRE_SYSCALL(fork)(void) { COMMON_SYSCALL_PRE_FORK(); } | ||
| 109 | POST_SYSCALL(fork)(long long res) { COMMON_SYSCALL_POST_FORK(res); } | ||
| 110 | PRE_SYSCALL(read)(long long fd_, void *buf_, long long nbyte_) { | ||
| 111 | if (buf_) { | ||
| 112 | PRE_WRITE(buf_, nbyte_); | ||
| 113 | } | ||
| 114 | } | ||
| 115 | POST_SYSCALL(read)(long long res, long long fd_, void *buf_, long long nbyte_) { | ||
| 116 | if (res > 0) { | ||
| 117 | POST_WRITE(buf_, res); | ||
| 118 | } | ||
| 119 | } | ||
| 120 | PRE_SYSCALL(write)(long long fd_, void *buf_, long long nbyte_) { | ||
| 121 | if (buf_) { | ||
| 122 | PRE_READ(buf_, nbyte_); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | POST_SYSCALL(write) | ||
| 126 | (long long res, long long fd_, void *buf_, long long nbyte_) { | ||
| 127 | if (res > 0) { | ||
| 128 | POST_READ(buf_, res); | ||
| 129 | } | ||
| 130 | } | ||
| 131 | PRE_SYSCALL(open)(void *path_, long long flags_, long long mode_) { | ||
| 132 | const char *path = (const char *)path_; | ||
| 133 | if (path) { | ||
| 134 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | POST_SYSCALL(open) | ||
| 138 | (long long res, void *path_, long long flags_, long long mode_) { | ||
| 139 | if (res > 0) { | ||
| 140 | const char *path = (const char *)path_; | ||
| 141 | if (path) { | ||
| 142 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | } | ||
| 146 | PRE_SYSCALL(close)(long long fd_) { COMMON_SYSCALL_FD_CLOSE((int)fd_); } | ||
| 147 | POST_SYSCALL(close)(long long res, long long fd_) { /* Nothing to do */ } | ||
| 148 | PRE_SYSCALL(compat_50_wait4) | ||
| 149 | (long long pid_, void *status_, long long options_, void *rusage_) { | ||
| 150 | /* TODO */ | ||
| 151 | } | ||
| 152 | POST_SYSCALL(compat_50_wait4) | ||
| 153 | (long long res, long long pid_, void *status_, long long options_, | ||
| 154 | void *rusage_) { | ||
| 155 | /* TODO */ | ||
| 156 | } | ||
| 157 | PRE_SYSCALL(compat_43_ocreat)(void *path_, long long mode_) { /* TODO */ } | ||
| 158 | POST_SYSCALL(compat_43_ocreat)(long long res, void *path_, long long mode_) { | ||
| 159 | /* TODO */ | ||
| 160 | } | ||
| 161 | PRE_SYSCALL(link)(void *path_, void *link_) { | ||
| 162 | const char *path = (const char *)path_; | ||
| 163 | const char *link = (const char *)link_; | ||
| 164 | if (path) { | ||
| 165 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 166 | } | ||
| 167 | if (link) { | ||
| 168 | PRE_READ(path, __sanitizer::internal_strlen(link) + 1); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | POST_SYSCALL(link)(long long res, void *path_, void *link_) { | ||
| 172 | if (res == 0) { | ||
| 173 | const char *path = (const char *)path_; | ||
| 174 | const char *link = (const char *)link_; | ||
| 175 | if (path) { | ||
| 176 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 177 | } | ||
| 178 | if (link) { | ||
| 179 | POST_READ(path, __sanitizer::internal_strlen(link) + 1); | ||
| 180 | } | ||
| 181 | } | ||
| 182 | } | ||
| 183 | PRE_SYSCALL(unlink)(void *path_) { | ||
| 184 | const char *path = (const char *)path_; | ||
| 185 | if (path) { | ||
| 186 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 187 | } | ||
| 188 | } | ||
| 189 | POST_SYSCALL(unlink)(long long res, void *path_) { | ||
| 190 | if (res == 0) { | ||
| 191 | const char *path = (const char *)path_; | ||
| 192 | if (path) { | ||
| 193 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 194 | } | ||
| 195 | } | ||
| 196 | } | ||
| 197 | /* syscall 11 has been skipped */ | ||
| 198 | PRE_SYSCALL(chdir)(void *path_) { | ||
| 199 | const char *path = (const char *)path_; | ||
| 200 | if (path) { | ||
| 201 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 202 | } | ||
| 203 | } | ||
| 204 | POST_SYSCALL(chdir)(long long res, void *path_) { | ||
| 205 | if (res == 0) { | ||
| 206 | const char *path = (const char *)path_; | ||
| 207 | if (path) { | ||
| 208 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 209 | } | ||
| 210 | } | ||
| 211 | } | ||
| 212 | PRE_SYSCALL(fchdir)(long long fd_) { /* Nothing to do */ } | ||
| 213 | POST_SYSCALL(fchdir)(long long res, long long fd_) { /* Nothing to do */ } | ||
| 214 | PRE_SYSCALL(compat_50_mknod)(void *path_, long long mode_, long long dev_) { | ||
| 215 | /* TODO */ | ||
| 216 | } | ||
| 217 | POST_SYSCALL(compat_50_mknod) | ||
| 218 | (long long res, void *path_, long long mode_, long long dev_) { | ||
| 219 | /* TODO */ | ||
| 220 | } | ||
| 221 | PRE_SYSCALL(chmod)(void *path_, long long mode_) { | ||
| 222 | const char *path = (const char *)path_; | ||
| 223 | if (path) { | ||
| 224 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | POST_SYSCALL(chmod)(long long res, void *path_, long long mode_) { | ||
| 228 | if (res == 0) { | ||
| 229 | const char *path = (const char *)path_; | ||
| 230 | if (path) { | ||
| 231 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 232 | } | ||
| 233 | } | ||
| 234 | } | ||
| 235 | PRE_SYSCALL(chown)(void *path_, long long uid_, long long gid_) { | ||
| 236 | const char *path = (const char *)path_; | ||
| 237 | if (path) { | ||
| 238 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | POST_SYSCALL(chown) | ||
| 242 | (long long res, void *path_, long long uid_, long long gid_) { | ||
| 243 | if (res == 0) { | ||
| 244 | const char *path = (const char *)path_; | ||
| 245 | if (path) { | ||
| 246 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 247 | } | ||
| 248 | } | ||
| 249 | } | ||
| 250 | PRE_SYSCALL(break)(void *nsize_) { /* Nothing to do */ } | ||
| 251 | POST_SYSCALL(break)(long long res, void *nsize_) { /* Nothing to do */ } | ||
| 252 | PRE_SYSCALL(compat_20_getfsstat) | ||
| 253 | (void *buf_, long long bufsize_, long long flags_) { | ||
| 254 | /* TODO */ | ||
| 255 | } | ||
| 256 | POST_SYSCALL(compat_20_getfsstat) | ||
| 257 | (long long res, void *buf_, long long bufsize_, long long flags_) { | ||
| 258 | /* TODO */ | ||
| 259 | } | ||
| 260 | PRE_SYSCALL(compat_43_olseek) | ||
| 261 | (long long fd_, long long offset_, long long whence_) { | ||
| 262 | /* TODO */ | ||
| 263 | } | ||
| 264 | POST_SYSCALL(compat_43_olseek) | ||
| 265 | (long long res, long long fd_, long long offset_, long long whence_) { | ||
| 266 | /* TODO */ | ||
| 267 | } | ||
| 268 | PRE_SYSCALL(getpid)(void) { /* Nothing to do */ } | ||
| 269 | POST_SYSCALL(getpid)(long long res) { /* Nothing to do */ } | ||
| 270 | PRE_SYSCALL(compat_40_mount) | ||
| 271 | (void *type_, void *path_, long long flags_, void *data_) { | ||
| 272 | /* TODO */ | ||
| 273 | } | ||
| 274 | POST_SYSCALL(compat_40_mount) | ||
| 275 | (long long res, void *type_, void *path_, long long flags_, void *data_) { | ||
| 276 | /* TODO */ | ||
| 277 | } | ||
| 278 | PRE_SYSCALL(unmount)(void *path_, long long flags_) { | ||
| 279 | const char *path = (const char *)path_; | ||
| 280 | if (path) { | ||
| 281 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 282 | } | ||
| 283 | } | ||
| 284 | POST_SYSCALL(unmount)(long long res, void *path_, long long flags_) { | ||
| 285 | if (res == 0) { | ||
| 286 | const char *path = (const char *)path_; | ||
| 287 | if (path) { | ||
| 288 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 289 | } | ||
| 290 | } | ||
| 291 | } | ||
| 292 | PRE_SYSCALL(setuid)(long long uid_) { /* Nothing to do */ } | ||
| 293 | POST_SYSCALL(setuid)(long long res, long long uid_) { /* Nothing to do */ } | ||
| 294 | PRE_SYSCALL(getuid)(void) { /* Nothing to do */ } | ||
| 295 | POST_SYSCALL(getuid)(long long res) { /* Nothing to do */ } | ||
| 296 | PRE_SYSCALL(geteuid)(void) { /* Nothing to do */ } | ||
| 297 | POST_SYSCALL(geteuid)(long long res) { /* Nothing to do */ } | ||
| 298 | PRE_SYSCALL(ptrace) | ||
| 299 | (long long req_, long long pid_, void *addr_, long long data_) { | ||
| 300 | if (req_ == ptrace_pt_io) { | ||
| 301 | struct __sanitizer_ptrace_io_desc *addr = | ||
| 302 | (struct __sanitizer_ptrace_io_desc *)addr_; | ||
| 303 | PRE_READ(addr, struct_ptrace_ptrace_io_desc_struct_sz); | ||
| 304 | if (addr->piod_op == ptrace_piod_write_d || | ||
| 305 | addr->piod_op == ptrace_piod_write_i) { | ||
| 306 | PRE_READ(addr->piod_addr, addr->piod_len); | ||
| 307 | } | ||
| 308 | if (addr->piod_op == ptrace_piod_read_d || | ||
| 309 | addr->piod_op == ptrace_piod_read_i || | ||
| 310 | addr->piod_op == ptrace_piod_read_auxv) { | ||
| 311 | PRE_WRITE(addr->piod_addr, addr->piod_len); | ||
| 312 | } | ||
| 313 | } else if (req_ == ptrace_pt_lwpinfo) { | ||
| 314 | struct __sanitizer_ptrace_lwpinfo *addr = | ||
| 315 | (struct __sanitizer_ptrace_lwpinfo *)addr_; | ||
| 316 | PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); | ||
| 317 | PRE_WRITE(addr, struct_ptrace_ptrace_lwpinfo_struct_sz); | ||
| 318 | } else if (req_ == ptrace_pt_set_event_mask) { | ||
| 319 | PRE_READ(addr_, struct_ptrace_ptrace_event_struct_sz); | ||
| 320 | } else if (req_ == ptrace_pt_get_event_mask) { | ||
| 321 | PRE_WRITE(addr_, struct_ptrace_ptrace_event_struct_sz); | ||
| 322 | } else if (req_ == ptrace_pt_set_siginfo) { | ||
| 323 | PRE_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz); | ||
| 324 | } else if (req_ == ptrace_pt_get_siginfo) { | ||
| 325 | PRE_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz); | ||
| 326 | } else if (req_ == ptrace_pt_lwpstatus) { | ||
| 327 | struct __sanitizer_ptrace_lwpstatus *addr = | ||
| 328 | (struct __sanitizer_ptrace_lwpstatus *)addr_; | ||
| 329 | PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); | ||
| 330 | PRE_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz); | ||
| 331 | } else if (req_ == ptrace_pt_lwpnext) { | ||
| 332 | struct __sanitizer_ptrace_lwpstatus *addr = | ||
| 333 | (struct __sanitizer_ptrace_lwpstatus *)addr_; | ||
| 334 | PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); | ||
| 335 | PRE_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz); | ||
| 336 | } else if (req_ == ptrace_pt_setregs) { | ||
| 337 | PRE_READ(addr_, struct_ptrace_reg_struct_sz); | ||
| 338 | } else if (req_ == ptrace_pt_getregs) { | ||
| 339 | PRE_WRITE(addr_, struct_ptrace_reg_struct_sz); | ||
| 340 | } else if (req_ == ptrace_pt_setfpregs) { | ||
| 341 | PRE_READ(addr_, struct_ptrace_fpreg_struct_sz); | ||
| 342 | } else if (req_ == ptrace_pt_getfpregs) { | ||
| 343 | PRE_WRITE(addr_, struct_ptrace_fpreg_struct_sz); | ||
| 344 | } else if (req_ == ptrace_pt_setdbregs) { | ||
| 345 | PRE_READ(addr_, struct_ptrace_dbreg_struct_sz); | ||
| 346 | } else if (req_ == ptrace_pt_getdbregs) { | ||
| 347 | PRE_WRITE(addr_, struct_ptrace_dbreg_struct_sz); | ||
| 348 | } | ||
| 349 | } | ||
| 350 | POST_SYSCALL(ptrace) | ||
| 351 | (long long res, long long req_, long long pid_, void *addr_, long long data_) { | ||
| 352 | if (res == 0) { | ||
| 353 | if (req_ == ptrace_pt_io) { | ||
| 354 | struct __sanitizer_ptrace_io_desc *addr = | ||
| 355 | (struct __sanitizer_ptrace_io_desc *)addr_; | ||
| 356 | POST_READ(addr, struct_ptrace_ptrace_io_desc_struct_sz); | ||
| 357 | if (addr->piod_op == ptrace_piod_write_d || | ||
| 358 | addr->piod_op == ptrace_piod_write_i) { | ||
| 359 | POST_READ(addr->piod_addr, addr->piod_len); | ||
| 360 | } | ||
| 361 | if (addr->piod_op == ptrace_piod_read_d || | ||
| 362 | addr->piod_op == ptrace_piod_read_i || | ||
| 363 | addr->piod_op == ptrace_piod_read_auxv) { | ||
| 364 | POST_WRITE(addr->piod_addr, addr->piod_len); | ||
| 365 | } | ||
| 366 | } else if (req_ == ptrace_pt_lwpinfo) { | ||
| 367 | struct __sanitizer_ptrace_lwpinfo *addr = | ||
| 368 | (struct __sanitizer_ptrace_lwpinfo *)addr_; | ||
| 369 | POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); | ||
| 370 | POST_WRITE(addr, struct_ptrace_ptrace_lwpinfo_struct_sz); | ||
| 371 | } else if (req_ == ptrace_pt_set_event_mask) { | ||
| 372 | POST_READ(addr_, struct_ptrace_ptrace_event_struct_sz); | ||
| 373 | } else if (req_ == ptrace_pt_get_event_mask) { | ||
| 374 | POST_WRITE(addr_, struct_ptrace_ptrace_event_struct_sz); | ||
| 375 | } else if (req_ == ptrace_pt_set_siginfo) { | ||
| 376 | POST_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz); | ||
| 377 | } else if (req_ == ptrace_pt_get_siginfo) { | ||
| 378 | POST_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz); | ||
| 379 | } else if (req_ == ptrace_pt_lwpstatus) { | ||
| 380 | struct __sanitizer_ptrace_lwpstatus *addr = | ||
| 381 | (struct __sanitizer_ptrace_lwpstatus *)addr_; | ||
| 382 | POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); | ||
| 383 | POST_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz); | ||
| 384 | } else if (req_ == ptrace_pt_lwpnext) { | ||
| 385 | struct __sanitizer_ptrace_lwpstatus *addr = | ||
| 386 | (struct __sanitizer_ptrace_lwpstatus *)addr_; | ||
| 387 | POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); | ||
| 388 | POST_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz); | ||
| 389 | } else if (req_ == ptrace_pt_setregs) { | ||
| 390 | POST_READ(addr_, struct_ptrace_reg_struct_sz); | ||
| 391 | } else if (req_ == ptrace_pt_getregs) { | ||
| 392 | POST_WRITE(addr_, struct_ptrace_reg_struct_sz); | ||
| 393 | } else if (req_ == ptrace_pt_setfpregs) { | ||
| 394 | POST_READ(addr_, struct_ptrace_fpreg_struct_sz); | ||
| 395 | } else if (req_ == ptrace_pt_getfpregs) { | ||
| 396 | POST_WRITE(addr_, struct_ptrace_fpreg_struct_sz); | ||
| 397 | } else if (req_ == ptrace_pt_setdbregs) { | ||
| 398 | POST_READ(addr_, struct_ptrace_dbreg_struct_sz); | ||
| 399 | } else if (req_ == ptrace_pt_getdbregs) { | ||
| 400 | POST_WRITE(addr_, struct_ptrace_dbreg_struct_sz); | ||
| 401 | } | ||
| 402 | } | ||
| 403 | } | ||
| 404 | PRE_SYSCALL(recvmsg)(long long s_, void *msg_, long long flags_) { | ||
| 405 | PRE_WRITE(msg_, sizeof(__sanitizer_msghdr)); | ||
| 406 | } | ||
| 407 | POST_SYSCALL(recvmsg) | ||
| 408 | (long long res, long long s_, void *msg_, long long flags_) { | ||
| 409 | if (res > 0) { | ||
| 410 | POST_WRITE(msg_, sizeof(__sanitizer_msghdr)); | ||
| 411 | } | ||
| 412 | } | ||
| 413 | PRE_SYSCALL(sendmsg)(long long s_, void *msg_, long long flags_) { | ||
| 414 | PRE_READ(msg_, sizeof(__sanitizer_msghdr)); | ||
| 415 | } | ||
| 416 | POST_SYSCALL(sendmsg) | ||
| 417 | (long long res, long long s_, void *msg_, long long flags_) { | ||
| 418 | if (res > 0) { | ||
| 419 | POST_READ(msg_, sizeof(__sanitizer_msghdr)); | ||
| 420 | } | ||
| 421 | } | ||
| 422 | PRE_SYSCALL(recvfrom) | ||
| 423 | (long long s_, void *buf_, long long len_, long long flags_, void *from_, | ||
| 424 | void *fromlenaddr_) { | ||
| 425 | PRE_WRITE(buf_, len_); | ||
| 426 | PRE_WRITE(from_, struct_sockaddr_sz); | ||
| 427 | PRE_WRITE(fromlenaddr_, sizeof(__sanitizer_socklen_t)); | ||
| 428 | } | ||
| 429 | POST_SYSCALL(recvfrom) | ||
| 430 | (long long res, long long s_, void *buf_, long long len_, long long flags_, | ||
| 431 | void *from_, void *fromlenaddr_) { | ||
| 432 | if (res >= 0) { | ||
| 433 | POST_WRITE(buf_, res); | ||
| 434 | POST_WRITE(from_, struct_sockaddr_sz); | ||
| 435 | POST_WRITE(fromlenaddr_, sizeof(__sanitizer_socklen_t)); | ||
| 436 | } | ||
| 437 | } | ||
| 438 | PRE_SYSCALL(accept)(long long s_, void *name_, void *anamelen_) { | ||
| 439 | PRE_WRITE(name_, struct_sockaddr_sz); | ||
| 440 | PRE_WRITE(anamelen_, sizeof(__sanitizer_socklen_t)); | ||
| 441 | } | ||
| 442 | POST_SYSCALL(accept) | ||
| 443 | (long long res, long long s_, void *name_, void *anamelen_) { | ||
| 444 | if (res == 0) { | ||
| 445 | POST_WRITE(name_, struct_sockaddr_sz); | ||
| 446 | POST_WRITE(anamelen_, sizeof(__sanitizer_socklen_t)); | ||
| 447 | } | ||
| 448 | } | ||
| 449 | PRE_SYSCALL(getpeername)(long long fdes_, void *asa_, void *alen_) { | ||
| 450 | PRE_WRITE(asa_, struct_sockaddr_sz); | ||
| 451 | PRE_WRITE(alen_, sizeof(__sanitizer_socklen_t)); | ||
| 452 | } | ||
| 453 | POST_SYSCALL(getpeername) | ||
| 454 | (long long res, long long fdes_, void *asa_, void *alen_) { | ||
| 455 | if (res == 0) { | ||
| 456 | POST_WRITE(asa_, struct_sockaddr_sz); | ||
| 457 | POST_WRITE(alen_, sizeof(__sanitizer_socklen_t)); | ||
| 458 | } | ||
| 459 | } | ||
| 460 | PRE_SYSCALL(getsockname)(long long fdes_, void *asa_, void *alen_) { | ||
| 461 | PRE_WRITE(asa_, struct_sockaddr_sz); | ||
| 462 | PRE_WRITE(alen_, sizeof(__sanitizer_socklen_t)); | ||
| 463 | } | ||
| 464 | POST_SYSCALL(getsockname) | ||
| 465 | (long long res, long long fdes_, void *asa_, void *alen_) { | ||
| 466 | if (res == 0) { | ||
| 467 | POST_WRITE(asa_, struct_sockaddr_sz); | ||
| 468 | POST_WRITE(alen_, sizeof(__sanitizer_socklen_t)); | ||
| 469 | } | ||
| 470 | } | ||
| 471 | PRE_SYSCALL(access)(void *path_, long long flags_) { | ||
| 472 | const char *path = (const char *)path_; | ||
| 473 | if (path) { | ||
| 474 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 475 | } | ||
| 476 | } | ||
| 477 | POST_SYSCALL(access)(long long res, void *path_, long long flags_) { | ||
| 478 | if (res == 0) { | ||
| 479 | const char *path = (const char *)path_; | ||
| 480 | if (path) { | ||
| 481 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 482 | } | ||
| 483 | } | ||
| 484 | } | ||
| 485 | PRE_SYSCALL(chflags)(void *path_, long long flags_) { | ||
| 486 | const char *path = (const char *)path_; | ||
| 487 | if (path) { | ||
| 488 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 489 | } | ||
| 490 | } | ||
| 491 | POST_SYSCALL(chflags)(long long res, void *path_, long long flags_) { | ||
| 492 | if (res == 0) { | ||
| 493 | const char *path = (const char *)path_; | ||
| 494 | if (path) { | ||
| 495 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 496 | } | ||
| 497 | } | ||
| 498 | } | ||
| 499 | PRE_SYSCALL(fchflags)(long long fd_, long long flags_) { /* Nothing to do */ } | ||
| 500 | POST_SYSCALL(fchflags)(long long res, long long fd_, long long flags_) { | ||
| 501 | /* Nothing to do */ | ||
| 502 | } | ||
| 503 | PRE_SYSCALL(sync)(void) { /* Nothing to do */ } | ||
| 504 | POST_SYSCALL(sync)(long long res) { /* Nothing to do */ } | ||
| 505 | PRE_SYSCALL(kill)(long long pid_, long long signum_) { /* Nothing to do */ } | ||
| 506 | POST_SYSCALL(kill)(long long res, long long pid_, long long signum_) { | ||
| 507 | /* Nothing to do */ | ||
| 508 | } | ||
| 509 | PRE_SYSCALL(compat_43_stat43)(void *path_, void *ub_) { /* TODO */ } | ||
| 510 | POST_SYSCALL(compat_43_stat43)(long long res, void *path_, void *ub_) { | ||
| 511 | /* TODO */ | ||
| 512 | } | ||
| 513 | PRE_SYSCALL(getppid)(void) { /* Nothing to do */ } | ||
| 514 | POST_SYSCALL(getppid)(long long res) { /* Nothing to do */ } | ||
| 515 | PRE_SYSCALL(compat_43_lstat43)(void *path_, void *ub_) { /* TODO */ } | ||
| 516 | POST_SYSCALL(compat_43_lstat43)(long long res, void *path_, void *ub_) { | ||
| 517 | /* TODO */ | ||
| 518 | } | ||
| 519 | PRE_SYSCALL(dup)(long long fd_) { /* Nothing to do */ } | ||
| 520 | POST_SYSCALL(dup)(long long res, long long fd_) { /* Nothing to do */ } | ||
| 521 | PRE_SYSCALL(pipe)(void) { | ||
| 522 | /* pipe returns two descriptors through two returned values */ | ||
| 523 | } | ||
| 524 | POST_SYSCALL(pipe)(long long res) { | ||
| 525 | /* pipe returns two descriptors through two returned values */ | ||
| 526 | } | ||
| 527 | PRE_SYSCALL(getegid)(void) { /* Nothing to do */ } | ||
| 528 | POST_SYSCALL(getegid)(long long res) { /* Nothing to do */ } | ||
| 529 | PRE_SYSCALL(profil) | ||
| 530 | (void *samples_, long long size_, long long offset_, long long scale_) { | ||
| 531 | if (samples_) { | ||
| 532 | PRE_WRITE(samples_, size_); | ||
| 533 | } | ||
| 534 | } | ||
| 535 | POST_SYSCALL(profil) | ||
| 536 | (long long res, void *samples_, long long size_, long long offset_, | ||
| 537 | long long scale_) { | ||
| 538 | if (res == 0) { | ||
| 539 | if (samples_) { | ||
| 540 | POST_WRITE(samples_, size_); | ||
| 541 | } | ||
| 542 | } | ||
| 543 | } | ||
| 544 | PRE_SYSCALL(ktrace) | ||
| 545 | (void *fname_, long long ops_, long long facs_, long long pid_) { | ||
| 546 | const char *fname = (const char *)fname_; | ||
| 547 | if (fname) { | ||
| 548 | PRE_READ(fname, __sanitizer::internal_strlen(fname) + 1); | ||
| 549 | } | ||
| 550 | } | ||
| 551 | POST_SYSCALL(ktrace) | ||
| 552 | (long long res, void *fname_, long long ops_, long long facs_, long long pid_) { | ||
| 553 | const char *fname = (const char *)fname_; | ||
| 554 | if (res == 0) { | ||
| 555 | if (fname) { | ||
| 556 | POST_READ(fname, __sanitizer::internal_strlen(fname) + 1); | ||
| 557 | } | ||
| 558 | } | ||
| 559 | } | ||
| 560 | PRE_SYSCALL(compat_13_sigaction13)(long long signum_, void *nsa_, void *osa_) { | ||
| 561 | /* TODO */ | ||
| 562 | } | ||
| 563 | POST_SYSCALL(compat_13_sigaction13) | ||
| 564 | (long long res, long long signum_, void *nsa_, void *osa_) { | ||
| 565 | /* TODO */ | ||
| 566 | } | ||
| 567 | PRE_SYSCALL(getgid)(void) { /* Nothing to do */ } | ||
| 568 | POST_SYSCALL(getgid)(long long res) { /* Nothing to do */ } | ||
| 569 | PRE_SYSCALL(compat_13_sigprocmask13)(long long how_, long long mask_) { | ||
| 570 | /* TODO */ | ||
| 571 | } | ||
| 572 | POST_SYSCALL(compat_13_sigprocmask13) | ||
| 573 | (long long res, long long how_, long long mask_) { | ||
| 574 | /* TODO */ | ||
| 575 | } | ||
| 576 | PRE_SYSCALL(__getlogin)(void *namebuf_, long long namelen_) { | ||
| 577 | if (namebuf_) { | ||
| 578 | PRE_WRITE(namebuf_, namelen_); | ||
| 579 | } | ||
| 580 | } | ||
| 581 | POST_SYSCALL(__getlogin)(long long res, void *namebuf_, long long namelen_) { | ||
| 582 | if (res == 0) { | ||
| 583 | if (namebuf_) { | ||
| 584 | POST_WRITE(namebuf_, namelen_); | ||
| 585 | } | ||
| 586 | } | ||
| 587 | } | ||
| 588 | PRE_SYSCALL(__setlogin)(void *namebuf_) { | ||
| 589 | const char *namebuf = (const char *)namebuf_; | ||
| 590 | if (namebuf) { | ||
| 591 | PRE_READ(namebuf, __sanitizer::internal_strlen(namebuf) + 1); | ||
| 592 | } | ||
| 593 | } | ||
| 594 | POST_SYSCALL(__setlogin)(long long res, void *namebuf_) { | ||
| 595 | if (res == 0) { | ||
| 596 | const char *namebuf = (const char *)namebuf_; | ||
| 597 | if (namebuf) { | ||
| 598 | POST_READ(namebuf, __sanitizer::internal_strlen(namebuf) + 1); | ||
| 599 | } | ||
| 600 | } | ||
| 601 | } | ||
| 602 | PRE_SYSCALL(acct)(void *path_) { | ||
| 603 | const char *path = (const char *)path_; | ||
| 604 | if (path) { | ||
| 605 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 606 | } | ||
| 607 | } | ||
| 608 | POST_SYSCALL(acct)(long long res, void *path_) { | ||
| 609 | if (res == 0) { | ||
| 610 | const char *path = (const char *)path_; | ||
| 611 | if (path) { | ||
| 612 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 613 | } | ||
| 614 | } | ||
| 615 | } | ||
| 616 | PRE_SYSCALL(compat_13_sigpending13)(void) { /* TODO */ } | ||
| 617 | POST_SYSCALL(compat_13_sigpending13)(long long res) { /* TODO */ } | ||
| 618 | PRE_SYSCALL(compat_13_sigaltstack13)(void *nss_, void *oss_) { /* TODO */ } | ||
| 619 | POST_SYSCALL(compat_13_sigaltstack13)(long long res, void *nss_, void *oss_) { | ||
| 620 | /* TODO */ | ||
| 621 | } | ||
| 622 | PRE_SYSCALL(ioctl)(long long fd_, long long com_, void *data_) { | ||
| 623 | /* Nothing to do */ | ||
| 624 | } | ||
| 625 | POST_SYSCALL(ioctl)(long long res, long long fd_, long long com_, void *data_) { | ||
| 626 | /* Nothing to do */ | ||
| 627 | } | ||
| 628 | PRE_SYSCALL(compat_12_oreboot)(long long opt_) { /* TODO */ } | ||
| 629 | POST_SYSCALL(compat_12_oreboot)(long long res, long long opt_) { /* TODO */ } | ||
| 630 | PRE_SYSCALL(revoke)(void *path_) { | ||
| 631 | const char *path = (const char *)path_; | ||
| 632 | if (path) { | ||
| 633 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 634 | } | ||
| 635 | } | ||
| 636 | POST_SYSCALL(revoke)(long long res, void *path_) { | ||
| 637 | if (res == 0) { | ||
| 638 | const char *path = (const char *)path_; | ||
| 639 | if (path) { | ||
| 640 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 641 | } | ||
| 642 | } | ||
| 643 | } | ||
| 644 | PRE_SYSCALL(symlink)(void *path_, void *link_) { | ||
| 645 | const char *path = (const char *)path_; | ||
| 646 | const char *link = (const char *)link_; | ||
| 647 | if (path) { | ||
| 648 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 649 | } | ||
| 650 | if (link) { | ||
| 651 | PRE_READ(link, __sanitizer::internal_strlen(link) + 1); | ||
| 652 | } | ||
| 653 | } | ||
| 654 | POST_SYSCALL(symlink)(long long res, void *path_, void *link_) { | ||
| 655 | if (res == 0) { | ||
| 656 | const char *path = (const char *)path_; | ||
| 657 | const char *link = (const char *)link_; | ||
| 658 | if (path) { | ||
| 659 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 660 | } | ||
| 661 | if (link) { | ||
| 662 | POST_READ(link, __sanitizer::internal_strlen(link) + 1); | ||
| 663 | } | ||
| 664 | } | ||
| 665 | } | ||
| 666 | PRE_SYSCALL(readlink)(void *path_, void *buf_, long long count_) { | ||
| 667 | const char *path = (const char *)path_; | ||
| 668 | if (path) { | ||
| 669 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 670 | } | ||
| 671 | if (buf_) { | ||
| 672 | PRE_WRITE(buf_, count_); | ||
| 673 | } | ||
| 674 | } | ||
| 675 | POST_SYSCALL(readlink) | ||
| 676 | (long long res, void *path_, void *buf_, long long count_) { | ||
| 677 | if (res > 0) { | ||
| 678 | const char *path = (const char *)path_; | ||
| 679 | if (path) { | ||
| 680 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 681 | } | ||
| 682 | if (buf_) { | ||
| 683 | PRE_WRITE(buf_, res); | ||
| 684 | } | ||
| 685 | } | ||
| 686 | } | ||
| 687 | PRE_SYSCALL(execve)(void *path_, void *argp_, void *envp_) { | ||
| 688 | const char *path = (const char *)path_; | ||
| 689 | char **argp = (char **)argp_; | ||
| 690 | char **envp = (char **)envp_; | ||
| 691 | if (path) { | ||
| 692 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 693 | } | ||
| 694 | if (argp && argp[0]) { | ||
| 695 | char *a = argp[0]; | ||
| 696 | while (a++) { | ||
| 697 | PRE_READ(a, __sanitizer::internal_strlen(a) + 1); | ||
| 698 | } | ||
| 699 | } | ||
| 700 | if (envp && envp[0]) { | ||
| 701 | char *e = envp[0]; | ||
| 702 | while (e++) { | ||
| 703 | PRE_READ(e, __sanitizer::internal_strlen(e) + 1); | ||
| 704 | } | ||
| 705 | } | ||
| 706 | } | ||
| 707 | POST_SYSCALL(execve)(long long res, void *path_, void *argp_, void *envp_) { | ||
| 708 | /* If we are here, something went wrong */ | ||
| 709 | const char *path = (const char *)path_; | ||
| 710 | char **argp = (char **)argp_; | ||
| 711 | char **envp = (char **)envp_; | ||
| 712 | if (path) { | ||
| 713 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 714 | } | ||
| 715 | if (argp && argp[0]) { | ||
| 716 | char *a = argp[0]; | ||
| 717 | while (a++) { | ||
| 718 | POST_READ(a, __sanitizer::internal_strlen(a) + 1); | ||
| 719 | } | ||
| 720 | } | ||
| 721 | if (envp && envp[0]) { | ||
| 722 | char *e = envp[0]; | ||
| 723 | while (e++) { | ||
| 724 | POST_READ(e, __sanitizer::internal_strlen(e) + 1); | ||
| 725 | } | ||
| 726 | } | ||
| 727 | } | ||
| 728 | PRE_SYSCALL(umask)(long long newmask_) { /* Nothing to do */ } | ||
| 729 | POST_SYSCALL(umask)(long long res, long long newmask_) { /* Nothing to do */ } | ||
| 730 | PRE_SYSCALL(chroot)(void *path_) { | ||
| 731 | const char *path = (const char *)path_; | ||
| 732 | if (path) { | ||
| 733 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 734 | } | ||
| 735 | } | ||
| 736 | POST_SYSCALL(chroot)(long long res, void *path_) { | ||
| 737 | if (res == 0) { | ||
| 738 | const char *path = (const char *)path_; | ||
| 739 | if (path) { | ||
| 740 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 741 | } | ||
| 742 | } | ||
| 743 | } | ||
| 744 | PRE_SYSCALL(compat_43_fstat43)(long long fd_, void *sb_) { /* TODO */ } | ||
| 745 | POST_SYSCALL(compat_43_fstat43)(long long res, long long fd_, void *sb_) { | ||
| 746 | /* TODO */ | ||
| 747 | } | ||
| 748 | PRE_SYSCALL(compat_43_ogetkerninfo) | ||
| 749 | (long long op_, void *where_, void *size_, long long arg_) { | ||
| 750 | /* TODO */ | ||
| 751 | } | ||
| 752 | POST_SYSCALL(compat_43_ogetkerninfo) | ||
| 753 | (long long res, long long op_, void *where_, void *size_, long long arg_) { | ||
| 754 | /* TODO */ | ||
| 755 | } | ||
| 756 | PRE_SYSCALL(compat_43_ogetpagesize)(void) { /* TODO */ } | ||
| 757 | POST_SYSCALL(compat_43_ogetpagesize)(long long res) { /* TODO */ } | ||
| 758 | PRE_SYSCALL(compat_12_msync)(void *addr_, long long len_) { /* TODO */ } | ||
| 759 | POST_SYSCALL(compat_12_msync)(long long res, void *addr_, long long len_) { | ||
| 760 | /* TODO */ | ||
| 761 | } | ||
| 762 | PRE_SYSCALL(vfork)(void) { /* Nothing to do */ } | ||
| 763 | POST_SYSCALL(vfork)(long long res) { /* Nothing to do */ } | ||
| 764 | /* syscall 67 has been skipped */ | ||
| 765 | /* syscall 68 has been skipped */ | ||
| 766 | /* syscall 69 has been skipped */ | ||
| 767 | /* syscall 70 has been skipped */ | ||
| 768 | PRE_SYSCALL(compat_43_ommap) | ||
| 769 | (void *addr_, long long len_, long long prot_, long long flags_, long long fd_, | ||
| 770 | long long pos_) { | ||
| 771 | /* TODO */ | ||
| 772 | } | ||
| 773 | POST_SYSCALL(compat_43_ommap) | ||
| 774 | (long long res, void *addr_, long long len_, long long prot_, long long flags_, | ||
| 775 | long long fd_, long long pos_) { | ||
| 776 | /* TODO */ | ||
| 777 | } | ||
| 778 | PRE_SYSCALL(vadvise)(long long anom_) { /* Nothing to do */ } | ||
| 779 | POST_SYSCALL(vadvise)(long long res, long long anom_) { /* Nothing to do */ } | ||
| 780 | PRE_SYSCALL(munmap)(void *addr_, long long len_) { /* Nothing to do */ } | ||
| 781 | POST_SYSCALL(munmap)(long long res, void *addr_, long long len_) { | ||
| 782 | /* Nothing to do */ | ||
| 783 | } | ||
| 784 | PRE_SYSCALL(mprotect)(void *addr_, long long len_, long long prot_) { | ||
| 785 | /* Nothing to do */ | ||
| 786 | } | ||
| 787 | POST_SYSCALL(mprotect) | ||
| 788 | (long long res, void *addr_, long long len_, long long prot_) { | ||
| 789 | /* Nothing to do */ | ||
| 790 | } | ||
| 791 | PRE_SYSCALL(madvise)(void *addr_, long long len_, long long behav_) { | ||
| 792 | /* Nothing to do */ | ||
| 793 | } | ||
| 794 | POST_SYSCALL(madvise) | ||
| 795 | (long long res, void *addr_, long long len_, long long behav_) { | ||
| 796 | /* Nothing to do */ | ||
| 797 | } | ||
| 798 | /* syscall 76 has been skipped */ | ||
| 799 | /* syscall 77 has been skipped */ | ||
| 800 | PRE_SYSCALL(mincore)(void *addr_, long long len_, void *vec_) { | ||
| 801 | /* Nothing to do */ | ||
| 802 | } | ||
| 803 | POST_SYSCALL(mincore)(long long res, void *addr_, long long len_, void *vec_) { | ||
| 804 | /* Nothing to do */ | ||
| 805 | } | ||
| 806 | PRE_SYSCALL(getgroups)(long long gidsetsize_, void *gidset_) { | ||
| 807 | unsigned int *gidset = (unsigned int *)gidset_; | ||
| 808 | if (gidset) { | ||
| 809 | PRE_WRITE(gidset, sizeof(*gidset) * gidsetsize_); | ||
| 810 | } | ||
| 811 | } | ||
| 812 | POST_SYSCALL(getgroups)(long long res, long long gidsetsize_, void *gidset_) { | ||
| 813 | if (res == 0) { | ||
| 814 | unsigned int *gidset = (unsigned int *)gidset_; | ||
| 815 | if (gidset) { | ||
| 816 | POST_WRITE(gidset, sizeof(*gidset) * gidsetsize_); | ||
| 817 | } | ||
| 818 | } | ||
| 819 | } | ||
| 820 | PRE_SYSCALL(setgroups)(long long gidsetsize_, void *gidset_) { | ||
| 821 | unsigned int *gidset = (unsigned int *)gidset_; | ||
| 822 | if (gidset) { | ||
| 823 | PRE_READ(gidset, sizeof(*gidset) * gidsetsize_); | ||
| 824 | } | ||
| 825 | } | ||
| 826 | POST_SYSCALL(setgroups)(long long res, long long gidsetsize_, void *gidset_) { | ||
| 827 | if (res == 0) { | ||
| 828 | unsigned int *gidset = (unsigned int *)gidset_; | ||
| 829 | if (gidset) { | ||
| 830 | POST_READ(gidset, sizeof(*gidset) * gidsetsize_); | ||
| 831 | } | ||
| 832 | } | ||
| 833 | } | ||
| 834 | PRE_SYSCALL(getpgrp)(void) { /* Nothing to do */ } | ||
| 835 | POST_SYSCALL(getpgrp)(long long res) { /* Nothing to do */ } | ||
| 836 | PRE_SYSCALL(setpgid)(long long pid_, long long pgid_) { /* Nothing to do */ } | ||
| 837 | POST_SYSCALL(setpgid)(long long res, long long pid_, long long pgid_) { | ||
| 838 | /* Nothing to do */ | ||
| 839 | } | ||
| 840 | PRE_SYSCALL(compat_50_setitimer)(long long which_, void *itv_, void *oitv_) { | ||
| 841 | /* TODO */ | ||
| 842 | } | ||
| 843 | POST_SYSCALL(compat_50_setitimer) | ||
| 844 | (long long res, long long which_, void *itv_, void *oitv_) { | ||
| 845 | /* TODO */ | ||
| 846 | } | ||
| 847 | PRE_SYSCALL(compat_43_owait)(void) { /* TODO */ } | ||
| 848 | POST_SYSCALL(compat_43_owait)(long long res) { /* TODO */ } | ||
| 849 | PRE_SYSCALL(compat_12_oswapon)(void *name_) { /* TODO */ } | ||
| 850 | POST_SYSCALL(compat_12_oswapon)(long long res, void *name_) { /* TODO */ } | ||
| 851 | PRE_SYSCALL(compat_50_getitimer)(long long which_, void *itv_) { /* TODO */ } | ||
| 852 | POST_SYSCALL(compat_50_getitimer)(long long res, long long which_, void *itv_) { | ||
| 853 | /* TODO */ | ||
| 854 | } | ||
| 855 | PRE_SYSCALL(compat_43_ogethostname)(void *hostname_, long long len_) { | ||
| 856 | /* TODO */ | ||
| 857 | } | ||
| 858 | POST_SYSCALL(compat_43_ogethostname) | ||
| 859 | (long long res, void *hostname_, long long len_) { | ||
| 860 | /* TODO */ | ||
| 861 | } | ||
| 862 | PRE_SYSCALL(compat_43_osethostname)(void *hostname_, long long len_) { | ||
| 863 | /* TODO */ | ||
| 864 | } | ||
| 865 | POST_SYSCALL(compat_43_osethostname) | ||
| 866 | (long long res, void *hostname_, long long len_) { | ||
| 867 | /* TODO */ | ||
| 868 | } | ||
| 869 | PRE_SYSCALL(compat_43_ogetdtablesize)(void) { /* TODO */ } | ||
| 870 | POST_SYSCALL(compat_43_ogetdtablesize)(long long res) { /* TODO */ } | ||
| 871 | PRE_SYSCALL(dup2)(long long from_, long long to_) { /* Nothing to do */ } | ||
| 872 | POST_SYSCALL(dup2)(long long res, long long from_, long long to_) { | ||
| 873 | /* Nothing to do */ | ||
| 874 | } | ||
| 875 | /* syscall 91 has been skipped */ | ||
| 876 | PRE_SYSCALL(fcntl)(long long fd_, long long cmd_, void *arg_) { | ||
| 877 | /* Nothing to do */ | ||
| 878 | } | ||
| 879 | POST_SYSCALL(fcntl)(long long res, long long fd_, long long cmd_, void *arg_) { | ||
| 880 | /* Nothing to do */ | ||
| 881 | } | ||
| 882 | PRE_SYSCALL(compat_50_select) | ||
| 883 | (long long nd_, void *in_, void *ou_, void *ex_, void *tv_) { | ||
| 884 | /* TODO */ | ||
| 885 | } | ||
| 886 | POST_SYSCALL(compat_50_select) | ||
| 887 | (long long res, long long nd_, void *in_, void *ou_, void *ex_, void *tv_) { | ||
| 888 | /* TODO */ | ||
| 889 | } | ||
| 890 | /* syscall 94 has been skipped */ | ||
| 891 | PRE_SYSCALL(fsync)(long long fd_) { /* Nothing to do */ } | ||
| 892 | POST_SYSCALL(fsync)(long long res, long long fd_) { /* Nothing to do */ } | ||
| 893 | PRE_SYSCALL(setpriority)(long long which_, long long who_, long long prio_) { | ||
| 894 | /* Nothing to do */ | ||
| 895 | } | ||
| 896 | POST_SYSCALL(setpriority) | ||
| 897 | (long long res, long long which_, long long who_, long long prio_) { | ||
| 898 | /* Nothing to do */ | ||
| 899 | } | ||
| 900 | PRE_SYSCALL(compat_30_socket) | ||
| 901 | (long long domain_, long long type_, long long protocol_) { | ||
| 902 | /* TODO */ | ||
| 903 | } | ||
| 904 | POST_SYSCALL(compat_30_socket) | ||
| 905 | (long long res, long long domain_, long long type_, long long protocol_) { | ||
| 906 | /* TODO */ | ||
| 907 | } | ||
| 908 | PRE_SYSCALL(connect)(long long s_, void *name_, long long namelen_) { | ||
| 909 | PRE_READ(name_, namelen_); | ||
| 910 | } | ||
| 911 | POST_SYSCALL(connect) | ||
| 912 | (long long res, long long s_, void *name_, long long namelen_) { | ||
| 913 | if (res == 0) { | ||
| 914 | POST_READ(name_, namelen_); | ||
| 915 | } | ||
| 916 | } | ||
| 917 | PRE_SYSCALL(compat_43_oaccept)(long long s_, void *name_, void *anamelen_) { | ||
| 918 | /* TODO */ | ||
| 919 | } | ||
| 920 | POST_SYSCALL(compat_43_oaccept) | ||
| 921 | (long long res, long long s_, void *name_, void *anamelen_) { | ||
| 922 | /* TODO */ | ||
| 923 | } | ||
| 924 | PRE_SYSCALL(getpriority)(long long which_, long long who_) { | ||
| 925 | /* Nothing to do */ | ||
| 926 | } | ||
| 927 | POST_SYSCALL(getpriority)(long long res, long long which_, long long who_) { | ||
| 928 | /* Nothing to do */ | ||
| 929 | } | ||
| 930 | PRE_SYSCALL(compat_43_osend) | ||
| 931 | (long long s_, void *buf_, long long len_, long long flags_) { | ||
| 932 | /* TODO */ | ||
| 933 | } | ||
| 934 | POST_SYSCALL(compat_43_osend) | ||
| 935 | (long long res, long long s_, void *buf_, long long len_, long long flags_) { | ||
| 936 | /* TODO */ | ||
| 937 | } | ||
| 938 | PRE_SYSCALL(compat_43_orecv) | ||
| 939 | (long long s_, void *buf_, long long len_, long long flags_) { | ||
| 940 | /* TODO */ | ||
| 941 | } | ||
| 942 | POST_SYSCALL(compat_43_orecv) | ||
| 943 | (long long res, long long s_, void *buf_, long long len_, long long flags_) { | ||
| 944 | /* TODO */ | ||
| 945 | } | ||
| 946 | PRE_SYSCALL(compat_13_sigreturn13)(void *sigcntxp_) { /* TODO */ } | ||
| 947 | POST_SYSCALL(compat_13_sigreturn13)(long long res, void *sigcntxp_) { | ||
| 948 | /* TODO */ | ||
| 949 | } | ||
| 950 | PRE_SYSCALL(bind)(long long s_, void *name_, long long namelen_) { | ||
| 951 | PRE_READ(name_, namelen_); | ||
| 952 | } | ||
| 953 | POST_SYSCALL(bind) | ||
| 954 | (long long res, long long s_, void *name_, long long namelen_) { | ||
| 955 | if (res == 0) { | ||
| 956 | PRE_READ(name_, namelen_); | ||
| 957 | } | ||
| 958 | } | ||
| 959 | PRE_SYSCALL(setsockopt) | ||
| 960 | (long long s_, long long level_, long long name_, void *val_, | ||
| 961 | long long valsize_) { | ||
| 962 | if (val_) { | ||
| 963 | PRE_READ(val_, valsize_); | ||
| 964 | } | ||
| 965 | } | ||
| 966 | POST_SYSCALL(setsockopt) | ||
| 967 | (long long res, long long s_, long long level_, long long name_, void *val_, | ||
| 968 | long long valsize_) { | ||
| 969 | if (res == 0) { | ||
| 970 | if (val_) { | ||
| 971 | POST_READ(val_, valsize_); | ||
| 972 | } | ||
| 973 | } | ||
| 974 | } | ||
| 975 | PRE_SYSCALL(listen)(long long s_, long long backlog_) { /* Nothing to do */ } | ||
| 976 | POST_SYSCALL(listen)(long long res, long long s_, long long backlog_) { | ||
| 977 | /* Nothing to do */ | ||
| 978 | } | ||
| 979 | /* syscall 107 has been skipped */ | ||
| 980 | PRE_SYSCALL(compat_43_osigvec)(long long signum_, void *nsv_, void *osv_) { | ||
| 981 | /* TODO */ | ||
| 982 | } | ||
| 983 | POST_SYSCALL(compat_43_osigvec) | ||
| 984 | (long long res, long long signum_, void *nsv_, void *osv_) { | ||
| 985 | /* TODO */ | ||
| 986 | } | ||
| 987 | PRE_SYSCALL(compat_43_osigblock)(long long mask_) { /* TODO */ } | ||
| 988 | POST_SYSCALL(compat_43_osigblock)(long long res, long long mask_) { /* TODO */ } | ||
| 989 | PRE_SYSCALL(compat_43_osigsetmask)(long long mask_) { /* TODO */ } | ||
| 990 | POST_SYSCALL(compat_43_osigsetmask)(long long res, long long mask_) { | ||
| 991 | /* TODO */ | ||
| 992 | } | ||
| 993 | PRE_SYSCALL(compat_13_sigsuspend13)(long long mask_) { /* TODO */ } | ||
| 994 | POST_SYSCALL(compat_13_sigsuspend13)(long long res, long long mask_) { | ||
| 995 | /* TODO */ | ||
| 996 | } | ||
| 997 | PRE_SYSCALL(compat_43_osigstack)(void *nss_, void *oss_) { /* TODO */ } | ||
| 998 | POST_SYSCALL(compat_43_osigstack)(long long res, void *nss_, void *oss_) { | ||
| 999 | /* TODO */ | ||
| 1000 | } | ||
| 1001 | PRE_SYSCALL(compat_43_orecvmsg)(long long s_, void *msg_, long long flags_) { | ||
| 1002 | /* TODO */ | ||
| 1003 | } | ||
| 1004 | POST_SYSCALL(compat_43_orecvmsg) | ||
| 1005 | (long long res, long long s_, void *msg_, long long flags_) { | ||
| 1006 | /* TODO */ | ||
| 1007 | } | ||
| 1008 | PRE_SYSCALL(compat_43_osendmsg)(long long s_, void *msg_, long long flags_) { | ||
| 1009 | /* TODO */ | ||
| 1010 | } | ||
| 1011 | POST_SYSCALL(compat_43_osendmsg) | ||
| 1012 | (long long res, long long s_, void *msg_, long long flags_) { | ||
| 1013 | /* TODO */ | ||
| 1014 | } | ||
| 1015 | /* syscall 115 has been skipped */ | ||
| 1016 | PRE_SYSCALL(compat_50_gettimeofday)(void *tp_, void *tzp_) { /* TODO */ } | ||
| 1017 | POST_SYSCALL(compat_50_gettimeofday)(long long res, void *tp_, void *tzp_) { | ||
| 1018 | /* TODO */ | ||
| 1019 | } | ||
| 1020 | PRE_SYSCALL(compat_50_getrusage)(long long who_, void *rusage_) { /* TODO */ } | ||
| 1021 | POST_SYSCALL(compat_50_getrusage) | ||
| 1022 | (long long res, long long who_, void *rusage_) { | ||
| 1023 | /* TODO */ | ||
| 1024 | } | ||
| 1025 | PRE_SYSCALL(getsockopt) | ||
| 1026 | (long long s_, long long level_, long long name_, void *val_, void *avalsize_) { | ||
| 1027 | /* TODO */ | ||
| 1028 | } | ||
| 1029 | POST_SYSCALL(getsockopt) | ||
| 1030 | (long long res, long long s_, long long level_, long long name_, void *val_, | ||
| 1031 | void *avalsize_) { | ||
| 1032 | /* TODO */ | ||
| 1033 | } | ||
| 1034 | /* syscall 119 has been skipped */ | ||
| 1035 | PRE_SYSCALL(readv)(long long fd_, void *iovp_, long long iovcnt_) { | ||
| 1036 | struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_; | ||
| 1037 | int i; | ||
| 1038 | if (iovp) { | ||
| 1039 | PRE_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_); | ||
| 1040 | for (i = 0; i < iovcnt_; i++) { | ||
| 1041 | PRE_WRITE(iovp[i].iov_base, iovp[i].iov_len); | ||
| 1042 | } | ||
| 1043 | } | ||
| 1044 | } | ||
| 1045 | POST_SYSCALL(readv) | ||
| 1046 | (long long res, long long fd_, void *iovp_, long long iovcnt_) { | ||
| 1047 | struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_; | ||
| 1048 | int i; | ||
| 1049 | uptr m, n = res; | ||
| 1050 | if (res > 0) { | ||
| 1051 | if (iovp) { | ||
| 1052 | POST_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_); | ||
| 1053 | for (i = 0; i < iovcnt_ && n > 0; i++) { | ||
| 1054 | m = n > iovp[i].iov_len ? iovp[i].iov_len : n; | ||
| 1055 | POST_WRITE(iovp[i].iov_base, m); | ||
| 1056 | n -= m; | ||
| 1057 | } | ||
| 1058 | } | ||
| 1059 | } | ||
| 1060 | } | ||
| 1061 | PRE_SYSCALL(writev)(long long fd_, void *iovp_, long long iovcnt_) { | ||
| 1062 | struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_; | ||
| 1063 | int i; | ||
| 1064 | if (iovp) { | ||
| 1065 | PRE_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_); | ||
| 1066 | for (i = 0; i < iovcnt_; i++) { | ||
| 1067 | PRE_READ(iovp[i].iov_base, iovp[i].iov_len); | ||
| 1068 | } | ||
| 1069 | } | ||
| 1070 | } | ||
| 1071 | POST_SYSCALL(writev) | ||
| 1072 | (long long res, long long fd_, void *iovp_, long long iovcnt_) { | ||
| 1073 | struct __sanitizer_iovec *iovp = (struct __sanitizer_iovec *)iovp_; | ||
| 1074 | int i; | ||
| 1075 | uptr m, n = res; | ||
| 1076 | if (res > 0) { | ||
| 1077 | if (iovp) { | ||
| 1078 | POST_READ(iovp, sizeof(struct __sanitizer_iovec) * iovcnt_); | ||
| 1079 | for (i = 0; i < iovcnt_ && n > 0; i++) { | ||
| 1080 | m = n > iovp[i].iov_len ? iovp[i].iov_len : n; | ||
| 1081 | POST_READ(iovp[i].iov_base, m); | ||
| 1082 | n -= m; | ||
| 1083 | } | ||
| 1084 | } | ||
| 1085 | } | ||
| 1086 | } | ||
| 1087 | PRE_SYSCALL(compat_50_settimeofday)(void *tv_, void *tzp_) { /* TODO */ } | ||
| 1088 | POST_SYSCALL(compat_50_settimeofday)(long long res, void *tv_, void *tzp_) { | ||
| 1089 | /* TODO */ | ||
| 1090 | } | ||
| 1091 | PRE_SYSCALL(fchown)(long long fd_, long long uid_, long long gid_) { | ||
| 1092 | /* Nothing to do */ | ||
| 1093 | } | ||
| 1094 | POST_SYSCALL(fchown) | ||
| 1095 | (long long res, long long fd_, long long uid_, long long gid_) { | ||
| 1096 | /* Nothing to do */ | ||
| 1097 | } | ||
| 1098 | PRE_SYSCALL(fchmod)(long long fd_, long long mode_) { /* Nothing to do */ } | ||
| 1099 | POST_SYSCALL(fchmod)(long long res, long long fd_, long long mode_) { | ||
| 1100 | /* Nothing to do */ | ||
| 1101 | } | ||
| 1102 | PRE_SYSCALL(compat_43_orecvfrom) | ||
| 1103 | (long long s_, void *buf_, long long len_, long long flags_, void *from_, | ||
| 1104 | void *fromlenaddr_) { | ||
| 1105 | /* TODO */ | ||
| 1106 | } | ||
| 1107 | POST_SYSCALL(compat_43_orecvfrom) | ||
| 1108 | (long long res, long long s_, void *buf_, long long len_, long long flags_, | ||
| 1109 | void *from_, void *fromlenaddr_) { | ||
| 1110 | /* TODO */ | ||
| 1111 | } | ||
| 1112 | PRE_SYSCALL(setreuid)(long long ruid_, long long euid_) { /* Nothing to do */ } | ||
| 1113 | POST_SYSCALL(setreuid)(long long res, long long ruid_, long long euid_) { | ||
| 1114 | /* Nothing to do */ | ||
| 1115 | } | ||
| 1116 | PRE_SYSCALL(setregid)(long long rgid_, long long egid_) { /* Nothing to do */ } | ||
| 1117 | POST_SYSCALL(setregid)(long long res, long long rgid_, long long egid_) { | ||
| 1118 | /* Nothing to do */ | ||
| 1119 | } | ||
| 1120 | PRE_SYSCALL(rename)(void *from_, void *to_) { | ||
| 1121 | const char *from = (const char *)from_; | ||
| 1122 | const char *to = (const char *)to_; | ||
| 1123 | if (from) { | ||
| 1124 | PRE_READ(from, __sanitizer::internal_strlen(from) + 1); | ||
| 1125 | } | ||
| 1126 | if (to) { | ||
| 1127 | PRE_READ(to, __sanitizer::internal_strlen(to) + 1); | ||
| 1128 | } | ||
| 1129 | } | ||
| 1130 | POST_SYSCALL(rename)(long long res, void *from_, void *to_) { | ||
| 1131 | if (res == 0) { | ||
| 1132 | const char *from = (const char *)from_; | ||
| 1133 | const char *to = (const char *)to_; | ||
| 1134 | if (from) { | ||
| 1135 | POST_READ(from, __sanitizer::internal_strlen(from) + 1); | ||
| 1136 | } | ||
| 1137 | if (to) { | ||
| 1138 | POST_READ(to, __sanitizer::internal_strlen(to) + 1); | ||
| 1139 | } | ||
| 1140 | } | ||
| 1141 | } | ||
| 1142 | PRE_SYSCALL(compat_43_otruncate)(void *path_, long long length_) { /* TODO */ } | ||
| 1143 | POST_SYSCALL(compat_43_otruncate) | ||
| 1144 | (long long res, void *path_, long long length_) { | ||
| 1145 | /* TODO */ | ||
| 1146 | } | ||
| 1147 | PRE_SYSCALL(compat_43_oftruncate)(long long fd_, long long length_) { | ||
| 1148 | /* TODO */ | ||
| 1149 | } | ||
| 1150 | POST_SYSCALL(compat_43_oftruncate) | ||
| 1151 | (long long res, long long fd_, long long length_) { | ||
| 1152 | /* TODO */ | ||
| 1153 | } | ||
| 1154 | PRE_SYSCALL(flock)(long long fd_, long long how_) { /* Nothing to do */ } | ||
| 1155 | POST_SYSCALL(flock)(long long res, long long fd_, long long how_) { | ||
| 1156 | /* Nothing to do */ | ||
| 1157 | } | ||
| 1158 | PRE_SYSCALL(mkfifo)(void *path_, long long mode_) { | ||
| 1159 | const char *path = (const char *)path_; | ||
| 1160 | if (path) { | ||
| 1161 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 1162 | } | ||
| 1163 | } | ||
| 1164 | POST_SYSCALL(mkfifo)(long long res, void *path_, long long mode_) { | ||
| 1165 | if (res == 0) { | ||
| 1166 | const char *path = (const char *)path_; | ||
| 1167 | if (path) { | ||
| 1168 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 1169 | } | ||
| 1170 | } | ||
| 1171 | } | ||
| 1172 | PRE_SYSCALL(sendto) | ||
| 1173 | (long long s_, void *buf_, long long len_, long long flags_, void *to_, | ||
| 1174 | long long tolen_) { | ||
| 1175 | PRE_READ(buf_, len_); | ||
| 1176 | PRE_READ(to_, tolen_); | ||
| 1177 | } | ||
| 1178 | POST_SYSCALL(sendto) | ||
| 1179 | (long long res, long long s_, void *buf_, long long len_, long long flags_, | ||
| 1180 | void *to_, long long tolen_) { | ||
| 1181 | if (res >= 0) { | ||
| 1182 | POST_READ(buf_, len_); | ||
| 1183 | POST_READ(to_, tolen_); | ||
| 1184 | } | ||
| 1185 | } | ||
| 1186 | PRE_SYSCALL(shutdown)(long long s_, long long how_) { /* Nothing to do */ } | ||
| 1187 | POST_SYSCALL(shutdown)(long long res, long long s_, long long how_) { | ||
| 1188 | /* Nothing to do */ | ||
| 1189 | } | ||
| 1190 | PRE_SYSCALL(socketpair) | ||
| 1191 | (long long domain_, long long type_, long long protocol_, void *rsv_) { | ||
| 1192 | PRE_WRITE(rsv_, 2 * sizeof(int)); | ||
| 1193 | } | ||
| 1194 | POST_SYSCALL(socketpair) | ||
| 1195 | (long long res, long long domain_, long long type_, long long protocol_, | ||
| 1196 | void *rsv_) { | ||
| 1197 | if (res == 0) { | ||
| 1198 | POST_WRITE(rsv_, 2 * sizeof(int)); | ||
| 1199 | } | ||
| 1200 | } | ||
| 1201 | PRE_SYSCALL(mkdir)(void *path_, long long mode_) { | ||
| 1202 | const char *path = (const char *)path_; | ||
| 1203 | if (path) { | ||
| 1204 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 1205 | } | ||
| 1206 | } | ||
| 1207 | POST_SYSCALL(mkdir)(long long res, void *path_, long long mode_) { | ||
| 1208 | if (res == 0) { | ||
| 1209 | const char *path = (const char *)path_; | ||
| 1210 | if (path) { | ||
| 1211 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 1212 | } | ||
| 1213 | } | ||
| 1214 | } | ||
| 1215 | PRE_SYSCALL(rmdir)(void *path_) { | ||
| 1216 | const char *path = (const char *)path_; | ||
| 1217 | if (path) { | ||
| 1218 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 1219 | } | ||
| 1220 | } | ||
| 1221 | POST_SYSCALL(rmdir)(long long res, void *path_) { | ||
| 1222 | if (res == 0) { | ||
| 1223 | const char *path = (const char *)path_; | ||
| 1224 | if (path) { | ||
| 1225 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 1226 | } | ||
| 1227 | } | ||
| 1228 | } | ||
| 1229 | PRE_SYSCALL(compat_50_utimes)(void *path_, void *tptr_) { /* TODO */ } | ||
| 1230 | POST_SYSCALL(compat_50_utimes)(long long res, void *path_, void *tptr_) { | ||
| 1231 | /* TODO */ | ||
| 1232 | } | ||
| 1233 | /* syscall 139 has been skipped */ | ||
| 1234 | PRE_SYSCALL(compat_50_adjtime)(void *delta_, void *olddelta_) { /* TODO */ } | ||
| 1235 | POST_SYSCALL(compat_50_adjtime)(long long res, void *delta_, void *olddelta_) { | ||
| 1236 | /* TODO */ | ||
| 1237 | } | ||
| 1238 | PRE_SYSCALL(compat_43_ogetpeername)(long long fdes_, void *asa_, void *alen_) { | ||
| 1239 | /* TODO */ | ||
| 1240 | } | ||
| 1241 | POST_SYSCALL(compat_43_ogetpeername) | ||
| 1242 | (long long res, long long fdes_, void *asa_, void *alen_) { | ||
| 1243 | /* TODO */ | ||
| 1244 | } | ||
| 1245 | PRE_SYSCALL(compat_43_ogethostid)(void) { /* TODO */ } | ||
| 1246 | POST_SYSCALL(compat_43_ogethostid)(long long res) { /* TODO */ } | ||
| 1247 | PRE_SYSCALL(compat_43_osethostid)(long long hostid_) { /* TODO */ } | ||
| 1248 | POST_SYSCALL(compat_43_osethostid)(long long res, long long hostid_) { | ||
| 1249 | /* TODO */ | ||
| 1250 | } | ||
| 1251 | PRE_SYSCALL(compat_43_ogetrlimit)(long long which_, void *rlp_) { /* TODO */ } | ||
| 1252 | POST_SYSCALL(compat_43_ogetrlimit) | ||
| 1253 | (long long res, long long which_, void *rlp_) { | ||
| 1254 | /* TODO */ | ||
| 1255 | } | ||
| 1256 | PRE_SYSCALL(compat_43_osetrlimit)(long long which_, void *rlp_) { /* TODO */ } | ||
| 1257 | POST_SYSCALL(compat_43_osetrlimit) | ||
| 1258 | (long long res, long long which_, void *rlp_) { | ||
| 1259 | /* TODO */ | ||
| 1260 | } | ||
| 1261 | PRE_SYSCALL(compat_43_okillpg)(long long pgid_, long long signum_) { | ||
| 1262 | /* TODO */ | ||
| 1263 | } | ||
| 1264 | POST_SYSCALL(compat_43_okillpg) | ||
| 1265 | (long long res, long long pgid_, long long signum_) { | ||
| 1266 | /* TODO */ | ||
| 1267 | } | ||
| 1268 | PRE_SYSCALL(setsid)(void) { /* Nothing to do */ } | ||
| 1269 | POST_SYSCALL(setsid)(long long res) { /* Nothing to do */ } | ||
| 1270 | PRE_SYSCALL(compat_50_quotactl) | ||
| 1271 | (void *path_, long long cmd_, long long uid_, void *arg_) { | ||
| 1272 | /* TODO */ | ||
| 1273 | } | ||
| 1274 | POST_SYSCALL(compat_50_quotactl) | ||
| 1275 | (long long res, void *path_, long long cmd_, long long uid_, void *arg_) { | ||
| 1276 | /* TODO */ | ||
| 1277 | } | ||
| 1278 | PRE_SYSCALL(compat_43_oquota)(void) { /* TODO */ } | ||
| 1279 | POST_SYSCALL(compat_43_oquota)(long long res) { /* TODO */ } | ||
| 1280 | PRE_SYSCALL(compat_43_ogetsockname)(long long fdec_, void *asa_, void *alen_) { | ||
| 1281 | /* TODO */ | ||
| 1282 | } | ||
| 1283 | POST_SYSCALL(compat_43_ogetsockname) | ||
| 1284 | (long long res, long long fdec_, void *asa_, void *alen_) { | ||
| 1285 | /* TODO */ | ||
| 1286 | } | ||
| 1287 | /* syscall 151 has been skipped */ | ||
| 1288 | /* syscall 152 has been skipped */ | ||
| 1289 | /* syscall 153 has been skipped */ | ||
| 1290 | /* syscall 154 has been skipped */ | ||
| 1291 | PRE_SYSCALL(nfssvc)(long long flag_, void *argp_) { /* Nothing to do */ } | ||
| 1292 | POST_SYSCALL(nfssvc)(long long res, long long flag_, void *argp_) { | ||
| 1293 | /* Nothing to do */ | ||
| 1294 | } | ||
| 1295 | PRE_SYSCALL(compat_43_ogetdirentries) | ||
| 1296 | (long long fd_, void *buf_, long long count_, void *basep_) { | ||
| 1297 | /* TODO */ | ||
| 1298 | } | ||
| 1299 | POST_SYSCALL(compat_43_ogetdirentries) | ||
| 1300 | (long long res, long long fd_, void *buf_, long long count_, void *basep_) { | ||
| 1301 | /* TODO */ | ||
| 1302 | } | ||
| 1303 | PRE_SYSCALL(compat_20_statfs)(void *path_, void *buf_) { /* TODO */ } | ||
| 1304 | POST_SYSCALL(compat_20_statfs)(long long res, void *path_, void *buf_) { | ||
| 1305 | /* TODO */ | ||
| 1306 | } | ||
| 1307 | PRE_SYSCALL(compat_20_fstatfs)(long long fd_, void *buf_) { /* TODO */ } | ||
| 1308 | POST_SYSCALL(compat_20_fstatfs)(long long res, long long fd_, void *buf_) { | ||
| 1309 | /* TODO */ | ||
| 1310 | } | ||
| 1311 | /* syscall 159 has been skipped */ | ||
| 1312 | /* syscall 160 has been skipped */ | ||
| 1313 | PRE_SYSCALL(compat_30_getfh)(void *fname_, void *fhp_) { /* TODO */ } | ||
| 1314 | POST_SYSCALL(compat_30_getfh)(long long res, void *fname_, void *fhp_) { | ||
| 1315 | /* TODO */ | ||
| 1316 | } | ||
| 1317 | PRE_SYSCALL(compat_09_ogetdomainname)(void *domainname_, long long len_) { | ||
| 1318 | /* TODO */ | ||
| 1319 | } | ||
| 1320 | POST_SYSCALL(compat_09_ogetdomainname) | ||
| 1321 | (long long res, void *domainname_, long long len_) { | ||
| 1322 | /* TODO */ | ||
| 1323 | } | ||
| 1324 | PRE_SYSCALL(compat_09_osetdomainname)(void *domainname_, long long len_) { | ||
| 1325 | /* TODO */ | ||
| 1326 | } | ||
| 1327 | POST_SYSCALL(compat_09_osetdomainname) | ||
| 1328 | (long long res, void *domainname_, long long len_) { | ||
| 1329 | /* TODO */ | ||
| 1330 | } | ||
| 1331 | PRE_SYSCALL(compat_09_ouname)(void *name_) { /* TODO */ } | ||
| 1332 | POST_SYSCALL(compat_09_ouname)(long long res, void *name_) { /* TODO */ } | ||
| 1333 | PRE_SYSCALL(sysarch)(long long op_, void *parms_) { /* TODO */ } | ||
| 1334 | POST_SYSCALL(sysarch)(long long res, long long op_, void *parms_) { /* TODO */ } | ||
| 1335 | /* syscall 166 has been skipped */ | ||
| 1336 | /* syscall 167 has been skipped */ | ||
| 1337 | /* syscall 168 has been skipped */ | ||
| 1338 | #if !defined(_LP64) | ||
| 1339 | PRE_SYSCALL(compat_10_osemsys) | ||
| 1340 | (long long which_, long long a2_, long long a3_, long long a4_, long long a5_) { | ||
| 1341 | /* TODO */ | ||
| 1342 | } | ||
| 1343 | POST_SYSCALL(compat_10_osemsys) | ||
| 1344 | (long long res, long long which_, long long a2_, long long a3_, long long a4_, | ||
| 1345 | long long a5_) { | ||
| 1346 | /* TODO */ | ||
| 1347 | } | ||
| 1348 | #else | ||
| 1349 | /* syscall 169 has been skipped */ | ||
| 1350 | #endif | ||
| 1351 | #if !defined(_LP64) | ||
| 1352 | PRE_SYSCALL(compat_10_omsgsys) | ||
| 1353 | (long long which_, long long a2_, long long a3_, long long a4_, long long a5_, | ||
| 1354 | long long a6_) { | ||
| 1355 | /* TODO */ | ||
| 1356 | } | ||
| 1357 | POST_SYSCALL(compat_10_omsgsys) | ||
| 1358 | (long long res, long long which_, long long a2_, long long a3_, long long a4_, | ||
| 1359 | long long a5_, long long a6_) { | ||
| 1360 | /* TODO */ | ||
| 1361 | } | ||
| 1362 | #else | ||
| 1363 | /* syscall 170 has been skipped */ | ||
| 1364 | #endif | ||
| 1365 | #if !defined(_LP64) | ||
| 1366 | PRE_SYSCALL(compat_10_oshmsys) | ||
| 1367 | (long long which_, long long a2_, long long a3_, long long a4_) { | ||
| 1368 | /* TODO */ | ||
| 1369 | } | ||
| 1370 | POST_SYSCALL(compat_10_oshmsys) | ||
| 1371 | (long long res, long long which_, long long a2_, long long a3_, long long a4_) { | ||
| 1372 | /* TODO */ | ||
| 1373 | } | ||
| 1374 | #else | ||
| 1375 | /* syscall 171 has been skipped */ | ||
| 1376 | #endif | ||
| 1377 | /* syscall 172 has been skipped */ | ||
| 1378 | PRE_SYSCALL(pread) | ||
| 1379 | (long long fd_, void *buf_, long long nbyte_, long long PAD_, | ||
| 1380 | long long offset_) { | ||
| 1381 | if (buf_) { | ||
| 1382 | PRE_WRITE(buf_, nbyte_); | ||
| 1383 | } | ||
| 1384 | } | ||
| 1385 | POST_SYSCALL(pread) | ||
| 1386 | (long long res, long long fd_, void *buf_, long long nbyte_, long long PAD_, | ||
| 1387 | long long offset_) { | ||
| 1388 | if (res > 0) { | ||
| 1389 | POST_WRITE(buf_, res); | ||
| 1390 | } | ||
| 1391 | } | ||
| 1392 | PRE_SYSCALL(pwrite) | ||
| 1393 | (long long fd_, void *buf_, long long nbyte_, long long PAD_, | ||
| 1394 | long long offset_) { | ||
| 1395 | if (buf_) { | ||
| 1396 | PRE_READ(buf_, nbyte_); | ||
| 1397 | } | ||
| 1398 | } | ||
| 1399 | POST_SYSCALL(pwrite) | ||
| 1400 | (long long res, long long fd_, void *buf_, long long nbyte_, long long PAD_, | ||
| 1401 | long long offset_) { | ||
| 1402 | if (res > 0) { | ||
| 1403 | POST_READ(buf_, res); | ||
| 1404 | } | ||
| 1405 | } | ||
| 1406 | PRE_SYSCALL(compat_30_ntp_gettime)(void *ntvp_) { /* TODO */ } | ||
| 1407 | POST_SYSCALL(compat_30_ntp_gettime)(long long res, void *ntvp_) { /* TODO */ } | ||
| 1408 | #if defined(NTP) || !defined(_KERNEL_OPT) | ||
| 1409 | PRE_SYSCALL(ntp_adjtime)(void *tp_) { /* Nothing to do */ } | ||
| 1410 | POST_SYSCALL(ntp_adjtime)(long long res, void *tp_) { /* Nothing to do */ } | ||
| 1411 | #else | ||
| 1412 | /* syscall 176 has been skipped */ | ||
| 1413 | #endif | ||
| 1414 | /* syscall 177 has been skipped */ | ||
| 1415 | /* syscall 178 has been skipped */ | ||
| 1416 | /* syscall 179 has been skipped */ | ||
| 1417 | /* syscall 180 has been skipped */ | ||
| 1418 | PRE_SYSCALL(setgid)(long long gid_) { /* Nothing to do */ } | ||
| 1419 | POST_SYSCALL(setgid)(long long res, long long gid_) { /* Nothing to do */ } | ||
| 1420 | PRE_SYSCALL(setegid)(long long egid_) { /* Nothing to do */ } | ||
| 1421 | POST_SYSCALL(setegid)(long long res, long long egid_) { /* Nothing to do */ } | ||
| 1422 | PRE_SYSCALL(seteuid)(long long euid_) { /* Nothing to do */ } | ||
| 1423 | POST_SYSCALL(seteuid)(long long res, long long euid_) { /* Nothing to do */ } | ||
| 1424 | PRE_SYSCALL(lfs_bmapv)(void *fsidp_, void *blkiov_, long long blkcnt_) { | ||
| 1425 | /* TODO */ | ||
| 1426 | } | ||
| 1427 | POST_SYSCALL(lfs_bmapv) | ||
| 1428 | (long long res, void *fsidp_, void *blkiov_, long long blkcnt_) { | ||
| 1429 | /* TODO */ | ||
| 1430 | } | ||
| 1431 | PRE_SYSCALL(lfs_markv)(void *fsidp_, void *blkiov_, long long blkcnt_) { | ||
| 1432 | /* TODO */ | ||
| 1433 | } | ||
| 1434 | POST_SYSCALL(lfs_markv) | ||
| 1435 | (long long res, void *fsidp_, void *blkiov_, long long blkcnt_) { | ||
| 1436 | /* TODO */ | ||
| 1437 | } | ||
| 1438 | PRE_SYSCALL(lfs_segclean)(void *fsidp_, long long segment_) { /* TODO */ } | ||
| 1439 | POST_SYSCALL(lfs_segclean)(long long res, void *fsidp_, long long segment_) { | ||
| 1440 | /* TODO */ | ||
| 1441 | } | ||
| 1442 | PRE_SYSCALL(compat_50_lfs_segwait)(void *fsidp_, void *tv_) { /* TODO */ } | ||
| 1443 | POST_SYSCALL(compat_50_lfs_segwait)(long long res, void *fsidp_, void *tv_) { | ||
| 1444 | /* TODO */ | ||
| 1445 | } | ||
| 1446 | PRE_SYSCALL(compat_12_stat12)(void *path_, void *ub_) { /* TODO */ } | ||
| 1447 | POST_SYSCALL(compat_12_stat12)(long long res, void *path_, void *ub_) { | ||
| 1448 | /* TODO */ | ||
| 1449 | } | ||
| 1450 | PRE_SYSCALL(compat_12_fstat12)(long long fd_, void *sb_) { /* TODO */ } | ||
| 1451 | POST_SYSCALL(compat_12_fstat12)(long long res, long long fd_, void *sb_) { | ||
| 1452 | /* TODO */ | ||
| 1453 | } | ||
| 1454 | PRE_SYSCALL(compat_12_lstat12)(void *path_, void *ub_) { /* TODO */ } | ||
| 1455 | POST_SYSCALL(compat_12_lstat12)(long long res, void *path_, void *ub_) { | ||
| 1456 | /* TODO */ | ||
| 1457 | } | ||
| 1458 | PRE_SYSCALL(pathconf)(void *path_, long long name_) { | ||
| 1459 | const char *path = (const char *)path_; | ||
| 1460 | if (path) { | ||
| 1461 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 1462 | } | ||
| 1463 | } | ||
| 1464 | POST_SYSCALL(pathconf)(long long res, void *path_, long long name_) { | ||
| 1465 | if (res != -1) { | ||
| 1466 | const char *path = (const char *)path_; | ||
| 1467 | if (path) { | ||
| 1468 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 1469 | } | ||
| 1470 | } | ||
| 1471 | } | ||
| 1472 | PRE_SYSCALL(fpathconf)(long long fd_, long long name_) { /* Nothing to do */ } | ||
| 1473 | POST_SYSCALL(fpathconf)(long long res, long long fd_, long long name_) { | ||
| 1474 | /* Nothing to do */ | ||
| 1475 | } | ||
| 1476 | PRE_SYSCALL(getsockopt2) | ||
| 1477 | (long long s_, long long level_, long long name_, void *val_, void *avalsize_) { | ||
| 1478 | /* TODO */ | ||
| 1479 | } | ||
| 1480 | POST_SYSCALL(getsockopt2) | ||
| 1481 | (long long res, long long s_, long long level_, long long name_, void *val_, | ||
| 1482 | void *avalsize_) { | ||
| 1483 | /* TODO */ | ||
| 1484 | } | ||
| 1485 | PRE_SYSCALL(getrlimit)(long long which_, void *rlp_) { | ||
| 1486 | PRE_WRITE(rlp_, struct_rlimit_sz); | ||
| 1487 | } | ||
| 1488 | POST_SYSCALL(getrlimit)(long long res, long long which_, void *rlp_) { | ||
| 1489 | if (res == 0) { | ||
| 1490 | POST_WRITE(rlp_, struct_rlimit_sz); | ||
| 1491 | } | ||
| 1492 | } | ||
| 1493 | PRE_SYSCALL(setrlimit)(long long which_, void *rlp_) { | ||
| 1494 | PRE_READ(rlp_, struct_rlimit_sz); | ||
| 1495 | } | ||
| 1496 | POST_SYSCALL(setrlimit)(long long res, long long which_, void *rlp_) { | ||
| 1497 | if (res == 0) { | ||
| 1498 | POST_READ(rlp_, struct_rlimit_sz); | ||
| 1499 | } | ||
| 1500 | } | ||
| 1501 | PRE_SYSCALL(compat_12_getdirentries) | ||
| 1502 | (long long fd_, void *buf_, long long count_, void *basep_) { | ||
| 1503 | /* TODO */ | ||
| 1504 | } | ||
| 1505 | POST_SYSCALL(compat_12_getdirentries) | ||
| 1506 | (long long res, long long fd_, void *buf_, long long count_, void *basep_) { | ||
| 1507 | /* TODO */ | ||
| 1508 | } | ||
| 1509 | PRE_SYSCALL(mmap) | ||
| 1510 | (void *addr_, long long len_, long long prot_, long long flags_, long long fd_, | ||
| 1511 | long long PAD_, long long pos_) { | ||
| 1512 | /* Nothing to do */ | ||
| 1513 | } | ||
| 1514 | POST_SYSCALL(mmap) | ||
| 1515 | (long long res, void *addr_, long long len_, long long prot_, long long flags_, | ||
| 1516 | long long fd_, long long PAD_, long long pos_) { | ||
| 1517 | /* Nothing to do */ | ||
| 1518 | } | ||
| 1519 | PRE_SYSCALL(__syscall)(long long code_, long long args_[SYS_MAXSYSARGS]) { | ||
| 1520 | /* Nothing to do */ | ||
| 1521 | } | ||
| 1522 | POST_SYSCALL(__syscall) | ||
| 1523 | (long long res, long long code_, long long args_[SYS_MAXSYSARGS]) { | ||
| 1524 | /* Nothing to do */ | ||
| 1525 | } | ||
| 1526 | PRE_SYSCALL(lseek) | ||
| 1527 | (long long fd_, long long PAD_, long long offset_, long long whence_) { | ||
| 1528 | /* Nothing to do */ | ||
| 1529 | } | ||
| 1530 | POST_SYSCALL(lseek) | ||
| 1531 | (long long res, long long fd_, long long PAD_, long long offset_, | ||
| 1532 | long long whence_) { | ||
| 1533 | /* Nothing to do */ | ||
| 1534 | } | ||
| 1535 | PRE_SYSCALL(truncate)(void *path_, long long PAD_, long long length_) { | ||
| 1536 | const char *path = (const char *)path_; | ||
| 1537 | if (path) { | ||
| 1538 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 1539 | } | ||
| 1540 | } | ||
| 1541 | POST_SYSCALL(truncate) | ||
| 1542 | (long long res, void *path_, long long PAD_, long long length_) { | ||
| 1543 | if (res == 0) { | ||
| 1544 | const char *path = (const char *)path_; | ||
| 1545 | if (path) { | ||
| 1546 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 1547 | } | ||
| 1548 | } | ||
| 1549 | } | ||
| 1550 | PRE_SYSCALL(ftruncate)(long long fd_, long long PAD_, long long length_) { | ||
| 1551 | /* Nothing to do */ | ||
| 1552 | } | ||
| 1553 | POST_SYSCALL(ftruncate) | ||
| 1554 | (long long res, long long fd_, long long PAD_, long long length_) { | ||
| 1555 | /* Nothing to do */ | ||
| 1556 | } | ||
| 1557 | PRE_SYSCALL(__sysctl) | ||
| 1558 | (void *name_, long long namelen_, void *oldv_, void *oldlenp_, void *newv_, | ||
| 1559 | long long newlen_) { | ||
| 1560 | const int *name = (const int *)name_; | ||
| 1561 | if (name) { | ||
| 1562 | PRE_READ(name, namelen_ * sizeof(*name)); | ||
| 1563 | } | ||
| 1564 | if (newv_) { | ||
| 1565 | PRE_READ(name, newlen_); | ||
| 1566 | } | ||
| 1567 | } | ||
| 1568 | POST_SYSCALL(__sysctl) | ||
| 1569 | (long long res, void *name_, long long namelen_, void *oldv_, void *oldlenp_, | ||
| 1570 | void *newv_, long long newlen_) { | ||
| 1571 | if (res == 0) { | ||
| 1572 | const int *name = (const int *)name_; | ||
| 1573 | if (name) { | ||
| 1574 | POST_READ(name, namelen_ * sizeof(*name)); | ||
| 1575 | } | ||
| 1576 | if (newv_) { | ||
| 1577 | POST_READ(name, newlen_); | ||
| 1578 | } | ||
| 1579 | } | ||
| 1580 | } | ||
| 1581 | PRE_SYSCALL(mlock)(void *addr_, long long len_) { /* Nothing to do */ } | ||
| 1582 | POST_SYSCALL(mlock)(long long res, void *addr_, long long len_) { | ||
| 1583 | /* Nothing to do */ | ||
| 1584 | } | ||
| 1585 | PRE_SYSCALL(munlock)(void *addr_, long long len_) { /* Nothing to do */ } | ||
| 1586 | POST_SYSCALL(munlock)(long long res, void *addr_, long long len_) { | ||
| 1587 | /* Nothing to do */ | ||
| 1588 | } | ||
| 1589 | PRE_SYSCALL(undelete)(void *path_) { | ||
| 1590 | const char *path = (const char *)path_; | ||
| 1591 | if (path) { | ||
| 1592 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 1593 | } | ||
| 1594 | } | ||
| 1595 | POST_SYSCALL(undelete)(long long res, void *path_) { | ||
| 1596 | if (res == 0) { | ||
| 1597 | const char *path = (const char *)path_; | ||
| 1598 | if (path) { | ||
| 1599 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 1600 | } | ||
| 1601 | } | ||
| 1602 | } | ||
| 1603 | PRE_SYSCALL(compat_50_futimes)(long long fd_, void *tptr_) { /* TODO */ } | ||
| 1604 | POST_SYSCALL(compat_50_futimes)(long long res, long long fd_, void *tptr_) { | ||
| 1605 | /* TODO */ | ||
| 1606 | } | ||
| 1607 | PRE_SYSCALL(getpgid)(long long pid_) { /* Nothing to do */ } | ||
| 1608 | POST_SYSCALL(getpgid)(long long res, long long pid_) { /* Nothing to do */ } | ||
| 1609 | PRE_SYSCALL(reboot)(long long opt_, void *bootstr_) { | ||
| 1610 | const char *bootstr = (const char *)bootstr_; | ||
| 1611 | if (bootstr) { | ||
| 1612 | PRE_READ(bootstr, __sanitizer::internal_strlen(bootstr) + 1); | ||
| 1613 | } | ||
| 1614 | } | ||
| 1615 | POST_SYSCALL(reboot)(long long res, long long opt_, void *bootstr_) { | ||
| 1616 | /* This call should never return */ | ||
| 1617 | const char *bootstr = (const char *)bootstr_; | ||
| 1618 | if (bootstr) { | ||
| 1619 | POST_READ(bootstr, __sanitizer::internal_strlen(bootstr) + 1); | ||
| 1620 | } | ||
| 1621 | } | ||
| 1622 | PRE_SYSCALL(poll)(void *fds_, long long nfds_, long long timeout_) { | ||
| 1623 | /* Nothing to do */ | ||
| 1624 | } | ||
| 1625 | POST_SYSCALL(poll) | ||
| 1626 | (long long res, void *fds_, long long nfds_, long long timeout_) { | ||
| 1627 | /* Nothing to do */ | ||
| 1628 | } | ||
| 1629 | PRE_SYSCALL(afssys) | ||
| 1630 | (long long id_, long long a1_, long long a2_, long long a3_, long long a4_, | ||
| 1631 | long long a5_, long long a6_) { | ||
| 1632 | /* TODO */ | ||
| 1633 | } | ||
| 1634 | POST_SYSCALL(afssys) | ||
| 1635 | (long long res, long long id_, long long a1_, long long a2_, long long a3_, | ||
| 1636 | long long a4_, long long a5_, long long a6_) { | ||
| 1637 | /* TODO */ | ||
| 1638 | } | ||
| 1639 | /* syscall 211 has been skipped */ | ||
| 1640 | /* syscall 212 has been skipped */ | ||
| 1641 | /* syscall 213 has been skipped */ | ||
| 1642 | /* syscall 214 has been skipped */ | ||
| 1643 | /* syscall 215 has been skipped */ | ||
| 1644 | /* syscall 216 has been skipped */ | ||
| 1645 | /* syscall 217 has been skipped */ | ||
| 1646 | /* syscall 218 has been skipped */ | ||
| 1647 | /* syscall 219 has been skipped */ | ||
| 1648 | PRE_SYSCALL(compat_14___semctl) | ||
| 1649 | (long long semid_, long long semnum_, long long cmd_, void *arg_) { | ||
| 1650 | /* TODO */ | ||
| 1651 | } | ||
| 1652 | POST_SYSCALL(compat_14___semctl) | ||
| 1653 | (long long res, long long semid_, long long semnum_, long long cmd_, | ||
| 1654 | void *arg_) { | ||
| 1655 | /* TODO */ | ||
| 1656 | } | ||
| 1657 | PRE_SYSCALL(semget)(long long key_, long long nsems_, long long semflg_) { | ||
| 1658 | /* Nothing to do */ | ||
| 1659 | } | ||
| 1660 | POST_SYSCALL(semget) | ||
| 1661 | (long long res, long long key_, long long nsems_, long long semflg_) { | ||
| 1662 | /* Nothing to do */ | ||
| 1663 | } | ||
| 1664 | PRE_SYSCALL(semop)(long long semid_, void *sops_, long long nsops_) { | ||
| 1665 | if (sops_) { | ||
| 1666 | PRE_READ(sops_, nsops_ * struct_sembuf_sz); | ||
| 1667 | } | ||
| 1668 | } | ||
| 1669 | POST_SYSCALL(semop) | ||
| 1670 | (long long res, long long semid_, void *sops_, long long nsops_) { | ||
| 1671 | if (res == 0) { | ||
| 1672 | if (sops_) { | ||
| 1673 | POST_READ(sops_, nsops_ * struct_sembuf_sz); | ||
| 1674 | } | ||
| 1675 | } | ||
| 1676 | } | ||
| 1677 | PRE_SYSCALL(semconfig)(long long flag_) { /* Nothing to do */ } | ||
| 1678 | POST_SYSCALL(semconfig)(long long res, long long flag_) { /* Nothing to do */ } | ||
| 1679 | PRE_SYSCALL(compat_14_msgctl)(long long msqid_, long long cmd_, void *buf_) { | ||
| 1680 | /* TODO */ | ||
| 1681 | } | ||
| 1682 | POST_SYSCALL(compat_14_msgctl) | ||
| 1683 | (long long res, long long msqid_, long long cmd_, void *buf_) { | ||
| 1684 | /* TODO */ | ||
| 1685 | } | ||
| 1686 | PRE_SYSCALL(msgget)(long long key_, long long msgflg_) { /* Nothing to do */ } | ||
| 1687 | POST_SYSCALL(msgget)(long long res, long long key_, long long msgflg_) { | ||
| 1688 | /* Nothing to do */ | ||
| 1689 | } | ||
| 1690 | PRE_SYSCALL(msgsnd) | ||
| 1691 | (long long msqid_, void *msgp_, long long msgsz_, long long msgflg_) { | ||
| 1692 | if (msgp_) { | ||
| 1693 | PRE_READ(msgp_, msgsz_); | ||
| 1694 | } | ||
| 1695 | } | ||
| 1696 | POST_SYSCALL(msgsnd) | ||
| 1697 | (long long res, long long msqid_, void *msgp_, long long msgsz_, | ||
| 1698 | long long msgflg_) { | ||
| 1699 | if (res == 0) { | ||
| 1700 | if (msgp_) { | ||
| 1701 | POST_READ(msgp_, msgsz_); | ||
| 1702 | } | ||
| 1703 | } | ||
| 1704 | } | ||
| 1705 | PRE_SYSCALL(msgrcv) | ||
| 1706 | (long long msqid_, void *msgp_, long long msgsz_, long long msgtyp_, | ||
| 1707 | long long msgflg_) { | ||
| 1708 | /* Nothing to do */ | ||
| 1709 | } | ||
| 1710 | POST_SYSCALL(msgrcv) | ||
| 1711 | (long long res, long long msqid_, void *msgp_, long long msgsz_, | ||
| 1712 | long long msgtyp_, long long msgflg_) { | ||
| 1713 | /* Nothing to do */ | ||
| 1714 | } | ||
| 1715 | PRE_SYSCALL(shmat)(long long shmid_, void *shmaddr_, long long shmflg_) { | ||
| 1716 | /* Nothing to do */ | ||
| 1717 | } | ||
| 1718 | POST_SYSCALL(shmat) | ||
| 1719 | (long long res, long long shmid_, void *shmaddr_, long long shmflg_) { | ||
| 1720 | /* Nothing to do */ | ||
| 1721 | } | ||
| 1722 | PRE_SYSCALL(compat_14_shmctl)(long long shmid_, long long cmd_, void *buf_) { | ||
| 1723 | /* TODO */ | ||
| 1724 | } | ||
| 1725 | POST_SYSCALL(compat_14_shmctl) | ||
| 1726 | (long long res, long long shmid_, long long cmd_, void *buf_) { | ||
| 1727 | /* TODO */ | ||
| 1728 | } | ||
| 1729 | PRE_SYSCALL(shmdt)(void *shmaddr_) { /* Nothing to do */ } | ||
| 1730 | POST_SYSCALL(shmdt)(long long res, void *shmaddr_) { /* Nothing to do */ } | ||
| 1731 | PRE_SYSCALL(shmget)(long long key_, long long size_, long long shmflg_) { | ||
| 1732 | /* Nothing to do */ | ||
| 1733 | } | ||
| 1734 | POST_SYSCALL(shmget) | ||
| 1735 | (long long res, long long key_, long long size_, long long shmflg_) { | ||
| 1736 | /* Nothing to do */ | ||
| 1737 | } | ||
| 1738 | PRE_SYSCALL(compat_50_clock_gettime)(long long clock_id_, void *tp_) { | ||
| 1739 | /* TODO */ | ||
| 1740 | } | ||
| 1741 | POST_SYSCALL(compat_50_clock_gettime) | ||
| 1742 | (long long res, long long clock_id_, void *tp_) { | ||
| 1743 | /* TODO */ | ||
| 1744 | } | ||
| 1745 | PRE_SYSCALL(compat_50_clock_settime)(long long clock_id_, void *tp_) { | ||
| 1746 | /* TODO */ | ||
| 1747 | } | ||
| 1748 | POST_SYSCALL(compat_50_clock_settime) | ||
| 1749 | (long long res, long long clock_id_, void *tp_) { | ||
| 1750 | /* TODO */ | ||
| 1751 | } | ||
| 1752 | PRE_SYSCALL(compat_50_clock_getres)(long long clock_id_, void *tp_) { | ||
| 1753 | /* TODO */ | ||
| 1754 | } | ||
| 1755 | POST_SYSCALL(compat_50_clock_getres) | ||
| 1756 | (long long res, long long clock_id_, void *tp_) { | ||
| 1757 | /* TODO */ | ||
| 1758 | } | ||
| 1759 | PRE_SYSCALL(timer_create)(long long clock_id_, void *evp_, void *timerid_) { | ||
| 1760 | /* Nothing to do */ | ||
| 1761 | } | ||
| 1762 | POST_SYSCALL(timer_create) | ||
| 1763 | (long long res, long long clock_id_, void *evp_, void *timerid_) { | ||
| 1764 | /* Nothing to do */ | ||
| 1765 | } | ||
| 1766 | PRE_SYSCALL(timer_delete)(long long timerid_) { /* Nothing to do */ } | ||
| 1767 | POST_SYSCALL(timer_delete)(long long res, long long timerid_) { | ||
| 1768 | /* Nothing to do */ | ||
| 1769 | } | ||
| 1770 | PRE_SYSCALL(compat_50_timer_settime) | ||
| 1771 | (long long timerid_, long long flags_, void *value_, void *ovalue_) { | ||
| 1772 | /* TODO */ | ||
| 1773 | } | ||
| 1774 | POST_SYSCALL(compat_50_timer_settime) | ||
| 1775 | (long long res, long long timerid_, long long flags_, void *value_, | ||
| 1776 | void *ovalue_) { | ||
| 1777 | /* TODO */ | ||
| 1778 | } | ||
| 1779 | PRE_SYSCALL(compat_50_timer_gettime)(long long timerid_, void *value_) { | ||
| 1780 | /* TODO */ | ||
| 1781 | } | ||
| 1782 | POST_SYSCALL(compat_50_timer_gettime) | ||
| 1783 | (long long res, long long timerid_, void *value_) { | ||
| 1784 | /* TODO */ | ||
| 1785 | } | ||
| 1786 | PRE_SYSCALL(timer_getoverrun)(long long timerid_) { /* Nothing to do */ } | ||
| 1787 | POST_SYSCALL(timer_getoverrun)(long long res, long long timerid_) { | ||
| 1788 | /* Nothing to do */ | ||
| 1789 | } | ||
| 1790 | PRE_SYSCALL(compat_50_nanosleep)(void *rqtp_, void *rmtp_) { /* TODO */ } | ||
| 1791 | POST_SYSCALL(compat_50_nanosleep)(long long res, void *rqtp_, void *rmtp_) { | ||
| 1792 | /* TODO */ | ||
| 1793 | } | ||
| 1794 | PRE_SYSCALL(fdatasync)(long long fd_) { /* Nothing to do */ } | ||
| 1795 | POST_SYSCALL(fdatasync)(long long res, long long fd_) { /* Nothing to do */ } | ||
| 1796 | PRE_SYSCALL(mlockall)(long long flags_) { /* Nothing to do */ } | ||
| 1797 | POST_SYSCALL(mlockall)(long long res, long long flags_) { /* Nothing to do */ } | ||
| 1798 | PRE_SYSCALL(munlockall)(void) { /* Nothing to do */ } | ||
| 1799 | POST_SYSCALL(munlockall)(long long res) { /* Nothing to do */ } | ||
| 1800 | PRE_SYSCALL(compat_50___sigtimedwait)(void *set_, void *info_, void *timeout_) { | ||
| 1801 | /* TODO */ | ||
| 1802 | } | ||
| 1803 | POST_SYSCALL(compat_50___sigtimedwait) | ||
| 1804 | (long long res, void *set_, void *info_, void *timeout_) { | ||
| 1805 | /* TODO */ | ||
| 1806 | } | ||
| 1807 | PRE_SYSCALL(sigqueueinfo)(long long pid_, void *info_) { | ||
| 1808 | if (info_) { | ||
| 1809 | PRE_READ(info_, siginfo_t_sz); | ||
| 1810 | } | ||
| 1811 | } | ||
| 1812 | POST_SYSCALL(sigqueueinfo)(long long res, long long pid_, void *info_) {} | ||
| 1813 | PRE_SYSCALL(modctl)(long long cmd_, void *arg_) { /* TODO */ } | ||
| 1814 | POST_SYSCALL(modctl)(long long res, long long cmd_, void *arg_) { /* TODO */ } | ||
| 1815 | PRE_SYSCALL(_ksem_init)(long long value_, void *idp_) { /* Nothing to do */ } | ||
| 1816 | POST_SYSCALL(_ksem_init)(long long res, long long value_, void *idp_) { | ||
| 1817 | /* Nothing to do */ | ||
| 1818 | } | ||
| 1819 | PRE_SYSCALL(_ksem_open) | ||
| 1820 | (void *name_, long long oflag_, long long mode_, long long value_, void *idp_) { | ||
| 1821 | const char *name = (const char *)name_; | ||
| 1822 | if (name) { | ||
| 1823 | PRE_READ(name, __sanitizer::internal_strlen(name) + 1); | ||
| 1824 | } | ||
| 1825 | } | ||
| 1826 | POST_SYSCALL(_ksem_open) | ||
| 1827 | (long long res, void *name_, long long oflag_, long long mode_, | ||
| 1828 | long long value_, void *idp_) { | ||
| 1829 | const char *name = (const char *)name_; | ||
| 1830 | if (name) { | ||
| 1831 | POST_READ(name, __sanitizer::internal_strlen(name) + 1); | ||
| 1832 | } | ||
| 1833 | } | ||
| 1834 | PRE_SYSCALL(_ksem_unlink)(void *name_) { | ||
| 1835 | const char *name = (const char *)name_; | ||
| 1836 | if (name) { | ||
| 1837 | PRE_READ(name, __sanitizer::internal_strlen(name) + 1); | ||
| 1838 | } | ||
| 1839 | } | ||
| 1840 | POST_SYSCALL(_ksem_unlink)(long long res, void *name_) { | ||
| 1841 | const char *name = (const char *)name_; | ||
| 1842 | if (name) { | ||
| 1843 | POST_READ(name, __sanitizer::internal_strlen(name) + 1); | ||
| 1844 | } | ||
| 1845 | } | ||
| 1846 | PRE_SYSCALL(_ksem_close)(long long id_) { /* Nothing to do */ } | ||
| 1847 | POST_SYSCALL(_ksem_close)(long long res, long long id_) { /* Nothing to do */ } | ||
| 1848 | PRE_SYSCALL(_ksem_post)(long long id_) { /* Nothing to do */ } | ||
| 1849 | POST_SYSCALL(_ksem_post)(long long res, long long id_) { /* Nothing to do */ } | ||
| 1850 | PRE_SYSCALL(_ksem_wait)(long long id_) { /* Nothing to do */ } | ||
| 1851 | POST_SYSCALL(_ksem_wait)(long long res, long long id_) { /* Nothing to do */ } | ||
| 1852 | PRE_SYSCALL(_ksem_trywait)(long long id_) { /* Nothing to do */ } | ||
| 1853 | POST_SYSCALL(_ksem_trywait)(long long res, long long id_) { | ||
| 1854 | /* Nothing to do */ | ||
| 1855 | } | ||
| 1856 | PRE_SYSCALL(_ksem_getvalue)(long long id_, void *value_) { /* Nothing to do */ } | ||
| 1857 | POST_SYSCALL(_ksem_getvalue)(long long res, long long id_, void *value_) { | ||
| 1858 | /* Nothing to do */ | ||
| 1859 | } | ||
| 1860 | PRE_SYSCALL(_ksem_destroy)(long long id_) { /* Nothing to do */ } | ||
| 1861 | POST_SYSCALL(_ksem_destroy)(long long res, long long id_) { | ||
| 1862 | /* Nothing to do */ | ||
| 1863 | } | ||
| 1864 | PRE_SYSCALL(_ksem_timedwait)(long long id_, void *abstime_) { | ||
| 1865 | if (abstime_) { | ||
| 1866 | PRE_READ(abstime_, struct_timespec_sz); | ||
| 1867 | } | ||
| 1868 | } | ||
| 1869 | POST_SYSCALL(_ksem_timedwait)(long long res, long long id_, void *abstime_) {} | ||
| 1870 | PRE_SYSCALL(mq_open) | ||
| 1871 | (void *name_, long long oflag_, long long mode_, void *attr_) { | ||
| 1872 | const char *name = (const char *)name_; | ||
| 1873 | if (name) { | ||
| 1874 | PRE_READ(name, __sanitizer::internal_strlen(name) + 1); | ||
| 1875 | } | ||
| 1876 | } | ||
| 1877 | POST_SYSCALL(mq_open) | ||
| 1878 | (long long res, void *name_, long long oflag_, long long mode_, void *attr_) { | ||
| 1879 | const char *name = (const char *)name_; | ||
| 1880 | if (name) { | ||
| 1881 | POST_READ(name, __sanitizer::internal_strlen(name) + 1); | ||
| 1882 | } | ||
| 1883 | } | ||
| 1884 | PRE_SYSCALL(mq_close)(long long mqdes_) { /* Nothing to do */ } | ||
| 1885 | POST_SYSCALL(mq_close)(long long res, long long mqdes_) { /* Nothing to do */ } | ||
| 1886 | PRE_SYSCALL(mq_unlink)(void *name_) { | ||
| 1887 | const char *name = (const char *)name_; | ||
| 1888 | if (name) { | ||
| 1889 | PRE_READ(name, __sanitizer::internal_strlen(name) + 1); | ||
| 1890 | } | ||
| 1891 | } | ||
| 1892 | POST_SYSCALL(mq_unlink)(long long res, void *name_) { | ||
| 1893 | const char *name = (const char *)name_; | ||
| 1894 | if (name) { | ||
| 1895 | POST_READ(name, __sanitizer::internal_strlen(name) + 1); | ||
| 1896 | } | ||
| 1897 | } | ||
| 1898 | PRE_SYSCALL(mq_getattr)(long long mqdes_, void *mqstat_) { /* Nothing to do */ } | ||
| 1899 | POST_SYSCALL(mq_getattr)(long long res, long long mqdes_, void *mqstat_) { | ||
| 1900 | /* Nothing to do */ | ||
| 1901 | } | ||
| 1902 | PRE_SYSCALL(mq_setattr)(long long mqdes_, void *mqstat_, void *omqstat_) { | ||
| 1903 | if (mqstat_) { | ||
| 1904 | PRE_READ(mqstat_, struct_mq_attr_sz); | ||
| 1905 | } | ||
| 1906 | } | ||
| 1907 | POST_SYSCALL(mq_setattr) | ||
| 1908 | (long long res, long long mqdes_, void *mqstat_, void *omqstat_) {} | ||
| 1909 | PRE_SYSCALL(mq_notify)(long long mqdes_, void *notification_) { | ||
| 1910 | if (notification_) { | ||
| 1911 | PRE_READ(notification_, struct_sigevent_sz); | ||
| 1912 | } | ||
| 1913 | } | ||
| 1914 | POST_SYSCALL(mq_notify)(long long res, long long mqdes_, void *notification_) {} | ||
| 1915 | PRE_SYSCALL(mq_send) | ||
| 1916 | (long long mqdes_, void *msg_ptr_, long long msg_len_, long long msg_prio_) { | ||
| 1917 | if (msg_ptr_) { | ||
| 1918 | PRE_READ(msg_ptr_, msg_len_); | ||
| 1919 | } | ||
| 1920 | } | ||
| 1921 | POST_SYSCALL(mq_send) | ||
| 1922 | (long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, | ||
| 1923 | long long msg_prio_) {} | ||
| 1924 | PRE_SYSCALL(mq_receive) | ||
| 1925 | (long long mqdes_, void *msg_ptr_, long long msg_len_, void *msg_prio_) { | ||
| 1926 | /* Nothing to do */ | ||
| 1927 | } | ||
| 1928 | POST_SYSCALL(mq_receive) | ||
| 1929 | (long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, | ||
| 1930 | void *msg_prio_) { | ||
| 1931 | /* Nothing to do */ | ||
| 1932 | } | ||
| 1933 | PRE_SYSCALL(compat_50_mq_timedsend) | ||
| 1934 | (long long mqdes_, void *msg_ptr_, long long msg_len_, long long msg_prio_, | ||
| 1935 | void *abs_timeout_) { | ||
| 1936 | /* TODO */ | ||
| 1937 | } | ||
| 1938 | POST_SYSCALL(compat_50_mq_timedsend) | ||
| 1939 | (long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, | ||
| 1940 | long long msg_prio_, void *abs_timeout_) { | ||
| 1941 | /* TODO */ | ||
| 1942 | } | ||
| 1943 | PRE_SYSCALL(compat_50_mq_timedreceive) | ||
| 1944 | (long long mqdes_, void *msg_ptr_, long long msg_len_, void *msg_prio_, | ||
| 1945 | void *abs_timeout_) { | ||
| 1946 | /* TODO */ | ||
| 1947 | } | ||
| 1948 | POST_SYSCALL(compat_50_mq_timedreceive) | ||
| 1949 | (long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, | ||
| 1950 | void *msg_prio_, void *abs_timeout_) { | ||
| 1951 | /* TODO */ | ||
| 1952 | } | ||
| 1953 | /* syscall 267 has been skipped */ | ||
| 1954 | /* syscall 268 has been skipped */ | ||
| 1955 | /* syscall 269 has been skipped */ | ||
| 1956 | PRE_SYSCALL(__posix_rename)(void *from_, void *to_) { | ||
| 1957 | const char *from = (const char *)from_; | ||
| 1958 | const char *to = (const char *)to_; | ||
| 1959 | if (from_) { | ||
| 1960 | PRE_READ(from, __sanitizer::internal_strlen(from) + 1); | ||
| 1961 | } | ||
| 1962 | if (to) { | ||
| 1963 | PRE_READ(to, __sanitizer::internal_strlen(to) + 1); | ||
| 1964 | } | ||
| 1965 | } | ||
| 1966 | POST_SYSCALL(__posix_rename)(long long res, void *from_, void *to_) { | ||
| 1967 | const char *from = (const char *)from_; | ||
| 1968 | const char *to = (const char *)to_; | ||
| 1969 | if (from) { | ||
| 1970 | POST_READ(from, __sanitizer::internal_strlen(from) + 1); | ||
| 1971 | } | ||
| 1972 | if (to) { | ||
| 1973 | POST_READ(to, __sanitizer::internal_strlen(to) + 1); | ||
| 1974 | } | ||
| 1975 | } | ||
| 1976 | PRE_SYSCALL(swapctl)(long long cmd_, void *arg_, long long misc_) { /* TODO */ } | ||
| 1977 | POST_SYSCALL(swapctl) | ||
| 1978 | (long long res, long long cmd_, void *arg_, long long misc_) { | ||
| 1979 | /* TODO */ | ||
| 1980 | } | ||
| 1981 | PRE_SYSCALL(compat_30_getdents)(long long fd_, void *buf_, long long count_) { | ||
| 1982 | /* TODO */ | ||
| 1983 | } | ||
| 1984 | POST_SYSCALL(compat_30_getdents) | ||
| 1985 | (long long res, long long fd_, void *buf_, long long count_) { | ||
| 1986 | /* TODO */ | ||
| 1987 | } | ||
| 1988 | PRE_SYSCALL(minherit)(void *addr_, long long len_, long long inherit_) { | ||
| 1989 | /* Nothing to do */ | ||
| 1990 | } | ||
| 1991 | POST_SYSCALL(minherit) | ||
| 1992 | (long long res, void *addr_, long long len_, long long inherit_) { | ||
| 1993 | /* Nothing to do */ | ||
| 1994 | } | ||
| 1995 | PRE_SYSCALL(lchmod)(void *path_, long long mode_) { | ||
| 1996 | const char *path = (const char *)path_; | ||
| 1997 | if (path) { | ||
| 1998 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 1999 | } | ||
| 2000 | } | ||
| 2001 | POST_SYSCALL(lchmod)(long long res, void *path_, long long mode_) { | ||
| 2002 | const char *path = (const char *)path_; | ||
| 2003 | if (path) { | ||
| 2004 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2005 | } | ||
| 2006 | } | ||
| 2007 | PRE_SYSCALL(lchown)(void *path_, long long uid_, long long gid_) { | ||
| 2008 | const char *path = (const char *)path_; | ||
| 2009 | if (path) { | ||
| 2010 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2011 | } | ||
| 2012 | } | ||
| 2013 | POST_SYSCALL(lchown) | ||
| 2014 | (long long res, void *path_, long long uid_, long long gid_) { | ||
| 2015 | const char *path = (const char *)path_; | ||
| 2016 | if (path) { | ||
| 2017 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2018 | } | ||
| 2019 | } | ||
| 2020 | PRE_SYSCALL(compat_50_lutimes)(void *path_, void *tptr_) { /* TODO */ } | ||
| 2021 | POST_SYSCALL(compat_50_lutimes)(long long res, void *path_, void *tptr_) { | ||
| 2022 | /* TODO */ | ||
| 2023 | } | ||
| 2024 | PRE_SYSCALL(__msync13)(void *addr_, long long len_, long long flags_) { | ||
| 2025 | /* Nothing to do */ | ||
| 2026 | } | ||
| 2027 | POST_SYSCALL(__msync13) | ||
| 2028 | (long long res, void *addr_, long long len_, long long flags_) { | ||
| 2029 | /* Nothing to do */ | ||
| 2030 | } | ||
| 2031 | PRE_SYSCALL(compat_30___stat13)(void *path_, void *ub_) { /* TODO */ } | ||
| 2032 | POST_SYSCALL(compat_30___stat13)(long long res, void *path_, void *ub_) { | ||
| 2033 | /* TODO */ | ||
| 2034 | } | ||
| 2035 | PRE_SYSCALL(compat_30___fstat13)(long long fd_, void *sb_) { /* TODO */ } | ||
| 2036 | POST_SYSCALL(compat_30___fstat13)(long long res, long long fd_, void *sb_) { | ||
| 2037 | /* TODO */ | ||
| 2038 | } | ||
| 2039 | PRE_SYSCALL(compat_30___lstat13)(void *path_, void *ub_) { /* TODO */ } | ||
| 2040 | POST_SYSCALL(compat_30___lstat13)(long long res, void *path_, void *ub_) { | ||
| 2041 | /* TODO */ | ||
| 2042 | } | ||
| 2043 | PRE_SYSCALL(__sigaltstack14)(void *nss_, void *oss_) { | ||
| 2044 | if (nss_) { | ||
| 2045 | PRE_READ(nss_, struct_sigaltstack_sz); | ||
| 2046 | } | ||
| 2047 | if (oss_) { | ||
| 2048 | PRE_READ(oss_, struct_sigaltstack_sz); | ||
| 2049 | } | ||
| 2050 | } | ||
| 2051 | POST_SYSCALL(__sigaltstack14)(long long res, void *nss_, void *oss_) {} | ||
| 2052 | PRE_SYSCALL(__vfork14)(void) { /* Nothing to do */ } | ||
| 2053 | POST_SYSCALL(__vfork14)(long long res) { /* Nothing to do */ } | ||
| 2054 | PRE_SYSCALL(__posix_chown)(void *path_, long long uid_, long long gid_) { | ||
| 2055 | const char *path = (const char *)path_; | ||
| 2056 | if (path) { | ||
| 2057 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2058 | } | ||
| 2059 | } | ||
| 2060 | POST_SYSCALL(__posix_chown) | ||
| 2061 | (long long res, void *path_, long long uid_, long long gid_) { | ||
| 2062 | const char *path = (const char *)path_; | ||
| 2063 | if (path) { | ||
| 2064 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2065 | } | ||
| 2066 | } | ||
| 2067 | PRE_SYSCALL(__posix_fchown)(long long fd_, long long uid_, long long gid_) { | ||
| 2068 | /* Nothing to do */ | ||
| 2069 | } | ||
| 2070 | POST_SYSCALL(__posix_fchown) | ||
| 2071 | (long long res, long long fd_, long long uid_, long long gid_) { | ||
| 2072 | /* Nothing to do */ | ||
| 2073 | } | ||
| 2074 | PRE_SYSCALL(__posix_lchown)(void *path_, long long uid_, long long gid_) { | ||
| 2075 | const char *path = (const char *)path_; | ||
| 2076 | if (path) { | ||
| 2077 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2078 | } | ||
| 2079 | } | ||
| 2080 | POST_SYSCALL(__posix_lchown) | ||
| 2081 | (long long res, void *path_, long long uid_, long long gid_) { | ||
| 2082 | const char *path = (const char *)path_; | ||
| 2083 | if (path) { | ||
| 2084 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2085 | } | ||
| 2086 | } | ||
| 2087 | PRE_SYSCALL(getsid)(long long pid_) { /* Nothing to do */ } | ||
| 2088 | POST_SYSCALL(getsid)(long long res, long long pid_) { /* Nothing to do */ } | ||
| 2089 | PRE_SYSCALL(__clone)(long long flags_, void *stack_) { /* Nothing to do */ } | ||
| 2090 | POST_SYSCALL(__clone)(long long res, long long flags_, void *stack_) { | ||
| 2091 | /* Nothing to do */ | ||
| 2092 | } | ||
| 2093 | PRE_SYSCALL(fktrace) | ||
| 2094 | (long long fd_, long long ops_, long long facs_, long long pid_) { | ||
| 2095 | /* Nothing to do */ | ||
| 2096 | } | ||
| 2097 | POST_SYSCALL(fktrace) | ||
| 2098 | (long long res, long long fd_, long long ops_, long long facs_, | ||
| 2099 | long long pid_) { | ||
| 2100 | /* Nothing to do */ | ||
| 2101 | } | ||
| 2102 | PRE_SYSCALL(preadv) | ||
| 2103 | (long long fd_, void *iovp_, long long iovcnt_, long long PAD_, | ||
| 2104 | long long offset_) { | ||
| 2105 | /* Nothing to do */ | ||
| 2106 | } | ||
| 2107 | POST_SYSCALL(preadv) | ||
| 2108 | (long long res, long long fd_, void *iovp_, long long iovcnt_, long long PAD_, | ||
| 2109 | long long offset_) { | ||
| 2110 | /* Nothing to do */ | ||
| 2111 | } | ||
| 2112 | PRE_SYSCALL(pwritev) | ||
| 2113 | (long long fd_, void *iovp_, long long iovcnt_, long long PAD_, | ||
| 2114 | long long offset_) { | ||
| 2115 | /* Nothing to do */ | ||
| 2116 | } | ||
| 2117 | POST_SYSCALL(pwritev) | ||
| 2118 | (long long res, long long fd_, void *iovp_, long long iovcnt_, long long PAD_, | ||
| 2119 | long long offset_) { | ||
| 2120 | /* Nothing to do */ | ||
| 2121 | } | ||
| 2122 | PRE_SYSCALL(compat_16___sigaction14) | ||
| 2123 | (long long signum_, void *nsa_, void *osa_) { | ||
| 2124 | /* TODO */ | ||
| 2125 | } | ||
| 2126 | POST_SYSCALL(compat_16___sigaction14) | ||
| 2127 | (long long res, long long signum_, void *nsa_, void *osa_) { | ||
| 2128 | /* TODO */ | ||
| 2129 | } | ||
| 2130 | PRE_SYSCALL(__sigpending14)(void *set_) { /* Nothing to do */ } | ||
| 2131 | POST_SYSCALL(__sigpending14)(long long res, void *set_) { /* Nothing to do */ } | ||
| 2132 | PRE_SYSCALL(__sigprocmask14)(long long how_, void *set_, void *oset_) { | ||
| 2133 | /* Nothing to do */ | ||
| 2134 | } | ||
| 2135 | POST_SYSCALL(__sigprocmask14) | ||
| 2136 | (long long res, long long how_, void *set_, void *oset_) { | ||
| 2137 | /* Nothing to do */ | ||
| 2138 | } | ||
| 2139 | PRE_SYSCALL(__sigsuspend14)(void *set_) { | ||
| 2140 | if (set_) { | ||
| 2141 | PRE_READ(set_, sizeof(__sanitizer_sigset_t)); | ||
| 2142 | } | ||
| 2143 | } | ||
| 2144 | POST_SYSCALL(__sigsuspend14)(long long res, void *set_) { | ||
| 2145 | if (set_) { | ||
| 2146 | PRE_READ(set_, sizeof(__sanitizer_sigset_t)); | ||
| 2147 | } | ||
| 2148 | } | ||
| 2149 | PRE_SYSCALL(compat_16___sigreturn14)(void *sigcntxp_) { /* TODO */ } | ||
| 2150 | POST_SYSCALL(compat_16___sigreturn14)(long long res, void *sigcntxp_) { | ||
| 2151 | /* TODO */ | ||
| 2152 | } | ||
| 2153 | PRE_SYSCALL(__getcwd)(void *bufp_, long long length_) { /* Nothing to do */ } | ||
| 2154 | POST_SYSCALL(__getcwd)(long long res, void *bufp_, long long length_) { | ||
| 2155 | /* Nothing to do */ | ||
| 2156 | } | ||
| 2157 | PRE_SYSCALL(fchroot)(long long fd_) { /* Nothing to do */ } | ||
| 2158 | POST_SYSCALL(fchroot)(long long res, long long fd_) { /* Nothing to do */ } | ||
| 2159 | PRE_SYSCALL(compat_30_fhopen)(void *fhp_, long long flags_) { /* TODO */ } | ||
| 2160 | POST_SYSCALL(compat_30_fhopen)(long long res, void *fhp_, long long flags_) { | ||
| 2161 | /* TODO */ | ||
| 2162 | } | ||
| 2163 | PRE_SYSCALL(compat_30_fhstat)(void *fhp_, void *sb_) { /* TODO */ } | ||
| 2164 | POST_SYSCALL(compat_30_fhstat)(long long res, void *fhp_, void *sb_) { | ||
| 2165 | /* TODO */ | ||
| 2166 | } | ||
| 2167 | PRE_SYSCALL(compat_20_fhstatfs)(void *fhp_, void *buf_) { /* TODO */ } | ||
| 2168 | POST_SYSCALL(compat_20_fhstatfs)(long long res, void *fhp_, void *buf_) { | ||
| 2169 | /* TODO */ | ||
| 2170 | } | ||
| 2171 | PRE_SYSCALL(compat_50_____semctl13) | ||
| 2172 | (long long semid_, long long semnum_, long long cmd_, void *arg_) { | ||
| 2173 | /* TODO */ | ||
| 2174 | } | ||
| 2175 | POST_SYSCALL(compat_50_____semctl13) | ||
| 2176 | (long long res, long long semid_, long long semnum_, long long cmd_, | ||
| 2177 | void *arg_) { | ||
| 2178 | /* TODO */ | ||
| 2179 | } | ||
| 2180 | PRE_SYSCALL(compat_50___msgctl13) | ||
| 2181 | (long long msqid_, long long cmd_, void *buf_) { | ||
| 2182 | /* TODO */ | ||
| 2183 | } | ||
| 2184 | POST_SYSCALL(compat_50___msgctl13) | ||
| 2185 | (long long res, long long msqid_, long long cmd_, void *buf_) { | ||
| 2186 | /* TODO */ | ||
| 2187 | } | ||
| 2188 | PRE_SYSCALL(compat_50___shmctl13) | ||
| 2189 | (long long shmid_, long long cmd_, void *buf_) { | ||
| 2190 | /* TODO */ | ||
| 2191 | } | ||
| 2192 | POST_SYSCALL(compat_50___shmctl13) | ||
| 2193 | (long long res, long long shmid_, long long cmd_, void *buf_) { | ||
| 2194 | /* TODO */ | ||
| 2195 | } | ||
| 2196 | PRE_SYSCALL(lchflags)(void *path_, long long flags_) { | ||
| 2197 | const char *path = (const char *)path_; | ||
| 2198 | if (path) { | ||
| 2199 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2200 | } | ||
| 2201 | } | ||
| 2202 | POST_SYSCALL(lchflags)(long long res, void *path_, long long flags_) { | ||
| 2203 | const char *path = (const char *)path_; | ||
| 2204 | if (path) { | ||
| 2205 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2206 | } | ||
| 2207 | } | ||
| 2208 | PRE_SYSCALL(issetugid)(void) { /* Nothing to do */ } | ||
| 2209 | POST_SYSCALL(issetugid)(long long res) { /* Nothing to do */ } | ||
| 2210 | PRE_SYSCALL(utrace)(void *label_, void *addr_, long long len_) { | ||
| 2211 | const char *label = (const char *)label_; | ||
| 2212 | if (label) { | ||
| 2213 | PRE_READ(label, __sanitizer::internal_strlen(label) + 1); | ||
| 2214 | } | ||
| 2215 | if (addr_) { | ||
| 2216 | PRE_READ(addr_, len_); | ||
| 2217 | } | ||
| 2218 | } | ||
| 2219 | POST_SYSCALL(utrace)(long long res, void *label_, void *addr_, long long len_) { | ||
| 2220 | const char *label = (const char *)label_; | ||
| 2221 | if (label) { | ||
| 2222 | POST_READ(label, __sanitizer::internal_strlen(label) + 1); | ||
| 2223 | } | ||
| 2224 | if (addr_) { | ||
| 2225 | POST_READ(addr_, len_); | ||
| 2226 | } | ||
| 2227 | } | ||
| 2228 | PRE_SYSCALL(getcontext)(void *ucp_) { /* Nothing to do */ } | ||
| 2229 | POST_SYSCALL(getcontext)(long long res, void *ucp_) { /* Nothing to do */ } | ||
| 2230 | PRE_SYSCALL(setcontext)(void *ucp_) { | ||
| 2231 | if (ucp_) { | ||
| 2232 | PRE_READ(ucp_, ucontext_t_sz); | ||
| 2233 | } | ||
| 2234 | } | ||
| 2235 | POST_SYSCALL(setcontext)(long long res, void *ucp_) {} | ||
| 2236 | PRE_SYSCALL(_lwp_create)(void *ucp_, long long flags_, void *new_lwp_) { | ||
| 2237 | if (ucp_) { | ||
| 2238 | PRE_READ(ucp_, ucontext_t_sz); | ||
| 2239 | } | ||
| 2240 | } | ||
| 2241 | POST_SYSCALL(_lwp_create) | ||
| 2242 | (long long res, void *ucp_, long long flags_, void *new_lwp_) {} | ||
| 2243 | PRE_SYSCALL(_lwp_exit)(void) { /* Nothing to do */ } | ||
| 2244 | POST_SYSCALL(_lwp_exit)(long long res) { /* Nothing to do */ } | ||
| 2245 | PRE_SYSCALL(_lwp_self)(void) { /* Nothing to do */ } | ||
| 2246 | POST_SYSCALL(_lwp_self)(long long res) { /* Nothing to do */ } | ||
| 2247 | PRE_SYSCALL(_lwp_wait)(long long wait_for_, void *departed_) { | ||
| 2248 | /* Nothing to do */ | ||
| 2249 | } | ||
| 2250 | POST_SYSCALL(_lwp_wait)(long long res, long long wait_for_, void *departed_) { | ||
| 2251 | /* Nothing to do */ | ||
| 2252 | } | ||
| 2253 | PRE_SYSCALL(_lwp_suspend)(long long target_) { /* Nothing to do */ } | ||
| 2254 | POST_SYSCALL(_lwp_suspend)(long long res, long long target_) { | ||
| 2255 | /* Nothing to do */ | ||
| 2256 | } | ||
| 2257 | PRE_SYSCALL(_lwp_continue)(long long target_) { /* Nothing to do */ } | ||
| 2258 | POST_SYSCALL(_lwp_continue)(long long res, long long target_) { | ||
| 2259 | /* Nothing to do */ | ||
| 2260 | } | ||
| 2261 | PRE_SYSCALL(_lwp_wakeup)(long long target_) { /* Nothing to do */ } | ||
| 2262 | POST_SYSCALL(_lwp_wakeup)(long long res, long long target_) { | ||
| 2263 | /* Nothing to do */ | ||
| 2264 | } | ||
| 2265 | PRE_SYSCALL(_lwp_getprivate)(void) { /* Nothing to do */ } | ||
| 2266 | POST_SYSCALL(_lwp_getprivate)(long long res) { /* Nothing to do */ } | ||
| 2267 | PRE_SYSCALL(_lwp_setprivate)(void *ptr_) { /* Nothing to do */ } | ||
| 2268 | POST_SYSCALL(_lwp_setprivate)(long long res, void *ptr_) { /* Nothing to do */ } | ||
| 2269 | PRE_SYSCALL(_lwp_kill)(long long target_, long long signo_) { | ||
| 2270 | /* Nothing to do */ | ||
| 2271 | } | ||
| 2272 | POST_SYSCALL(_lwp_kill)(long long res, long long target_, long long signo_) { | ||
| 2273 | /* Nothing to do */ | ||
| 2274 | } | ||
| 2275 | PRE_SYSCALL(_lwp_detach)(long long target_) { /* Nothing to do */ } | ||
| 2276 | POST_SYSCALL(_lwp_detach)(long long res, long long target_) { | ||
| 2277 | /* Nothing to do */ | ||
| 2278 | } | ||
| 2279 | PRE_SYSCALL(compat_50__lwp_park) | ||
| 2280 | (void *ts_, long long unpark_, void *hint_, void *unparkhint_) { | ||
| 2281 | /* TODO */ | ||
| 2282 | } | ||
| 2283 | POST_SYSCALL(compat_50__lwp_park) | ||
| 2284 | (long long res, void *ts_, long long unpark_, void *hint_, void *unparkhint_) { | ||
| 2285 | /* TODO */ | ||
| 2286 | } | ||
| 2287 | PRE_SYSCALL(_lwp_unpark)(long long target_, void *hint_) { /* Nothing to do */ } | ||
| 2288 | POST_SYSCALL(_lwp_unpark)(long long res, long long target_, void *hint_) { | ||
| 2289 | /* Nothing to do */ | ||
| 2290 | } | ||
| 2291 | PRE_SYSCALL(_lwp_unpark_all)(void *targets_, long long ntargets_, void *hint_) { | ||
| 2292 | if (targets_) { | ||
| 2293 | PRE_READ(targets_, ntargets_ * sizeof(__sanitizer_lwpid_t)); | ||
| 2294 | } | ||
| 2295 | } | ||
| 2296 | POST_SYSCALL(_lwp_unpark_all) | ||
| 2297 | (long long res, void *targets_, long long ntargets_, void *hint_) {} | ||
| 2298 | PRE_SYSCALL(_lwp_setname)(long long target_, void *name_) { | ||
| 2299 | const char *name = (const char *)name_; | ||
| 2300 | if (name) { | ||
| 2301 | PRE_READ(name, __sanitizer::internal_strlen(name) + 1); | ||
| 2302 | } | ||
| 2303 | } | ||
| 2304 | POST_SYSCALL(_lwp_setname)(long long res, long long target_, void *name_) { | ||
| 2305 | const char *name = (const char *)name_; | ||
| 2306 | if (name) { | ||
| 2307 | POST_READ(name, __sanitizer::internal_strlen(name) + 1); | ||
| 2308 | } | ||
| 2309 | } | ||
| 2310 | PRE_SYSCALL(_lwp_getname)(long long target_, void *name_, long long len_) { | ||
| 2311 | /* Nothing to do */ | ||
| 2312 | } | ||
| 2313 | POST_SYSCALL(_lwp_getname) | ||
| 2314 | (long long res, long long target_, void *name_, long long len_) { | ||
| 2315 | /* Nothing to do */ | ||
| 2316 | } | ||
| 2317 | PRE_SYSCALL(_lwp_ctl)(long long features_, void **address_) { | ||
| 2318 | /* Nothing to do */ | ||
| 2319 | } | ||
| 2320 | POST_SYSCALL(_lwp_ctl)(long long res, long long features_, void **address_) { | ||
| 2321 | /* Nothing to do */ | ||
| 2322 | } | ||
| 2323 | /* syscall 326 has been skipped */ | ||
| 2324 | /* syscall 327 has been skipped */ | ||
| 2325 | /* syscall 328 has been skipped */ | ||
| 2326 | /* syscall 329 has been skipped */ | ||
| 2327 | PRE_SYSCALL(compat_60_sa_register) | ||
| 2328 | (void *newv_, void **oldv_, long long flags_, long long stackinfo_offset_) { | ||
| 2329 | /* TODO */ | ||
| 2330 | } | ||
| 2331 | POST_SYSCALL(compat_60_sa_register) | ||
| 2332 | (long long res, void *newv_, void **oldv_, long long flags_, | ||
| 2333 | long long stackinfo_offset_) { | ||
| 2334 | /* TODO */ | ||
| 2335 | } | ||
| 2336 | PRE_SYSCALL(compat_60_sa_stacks)(long long num_, void *stacks_) { /* TODO */ } | ||
| 2337 | POST_SYSCALL(compat_60_sa_stacks) | ||
| 2338 | (long long res, long long num_, void *stacks_) { | ||
| 2339 | /* TODO */ | ||
| 2340 | } | ||
| 2341 | PRE_SYSCALL(compat_60_sa_enable)(void) { /* TODO */ } | ||
| 2342 | POST_SYSCALL(compat_60_sa_enable)(long long res) { /* TODO */ } | ||
| 2343 | PRE_SYSCALL(compat_60_sa_setconcurrency)(long long concurrency_) { /* TODO */ } | ||
| 2344 | POST_SYSCALL(compat_60_sa_setconcurrency) | ||
| 2345 | (long long res, long long concurrency_) { | ||
| 2346 | /* TODO */ | ||
| 2347 | } | ||
| 2348 | PRE_SYSCALL(compat_60_sa_yield)(void) { /* TODO */ } | ||
| 2349 | POST_SYSCALL(compat_60_sa_yield)(long long res) { /* TODO */ } | ||
| 2350 | PRE_SYSCALL(compat_60_sa_preempt)(long long sa_id_) { /* TODO */ } | ||
| 2351 | POST_SYSCALL(compat_60_sa_preempt)(long long res, long long sa_id_) { | ||
| 2352 | /* TODO */ | ||
| 2353 | } | ||
| 2354 | /* syscall 336 has been skipped */ | ||
| 2355 | /* syscall 337 has been skipped */ | ||
| 2356 | /* syscall 338 has been skipped */ | ||
| 2357 | /* syscall 339 has been skipped */ | ||
| 2358 | PRE_SYSCALL(__sigaction_sigtramp) | ||
| 2359 | (long long signum_, void *nsa_, void *osa_, void *tramp_, long long vers_) { | ||
| 2360 | if (nsa_) { | ||
| 2361 | PRE_READ(nsa_, sizeof(__sanitizer_sigaction)); | ||
| 2362 | } | ||
| 2363 | } | ||
| 2364 | POST_SYSCALL(__sigaction_sigtramp) | ||
| 2365 | (long long res, long long signum_, void *nsa_, void *osa_, void *tramp_, | ||
| 2366 | long long vers_) { | ||
| 2367 | if (nsa_) { | ||
| 2368 | PRE_READ(nsa_, sizeof(__sanitizer_sigaction)); | ||
| 2369 | } | ||
| 2370 | } | ||
| 2371 | /* syscall 341 has been skipped */ | ||
| 2372 | /* syscall 342 has been skipped */ | ||
| 2373 | PRE_SYSCALL(rasctl)(void *addr_, long long len_, long long op_) { | ||
| 2374 | /* Nothing to do */ | ||
| 2375 | } | ||
| 2376 | POST_SYSCALL(rasctl) | ||
| 2377 | (long long res, void *addr_, long long len_, long long op_) { | ||
| 2378 | /* Nothing to do */ | ||
| 2379 | } | ||
| 2380 | PRE_SYSCALL(kqueue)(void) { /* Nothing to do */ } | ||
| 2381 | POST_SYSCALL(kqueue)(long long res) { /* Nothing to do */ } | ||
| 2382 | PRE_SYSCALL(compat_50_kevent) | ||
| 2383 | (long long fd_, void *changelist_, long long nchanges_, void *eventlist_, | ||
| 2384 | long long nevents_, void *timeout_) { | ||
| 2385 | /* TODO */ | ||
| 2386 | } | ||
| 2387 | POST_SYSCALL(compat_50_kevent) | ||
| 2388 | (long long res, long long fd_, void *changelist_, long long nchanges_, | ||
| 2389 | void *eventlist_, long long nevents_, void *timeout_) { | ||
| 2390 | /* TODO */ | ||
| 2391 | } | ||
| 2392 | PRE_SYSCALL(_sched_setparam) | ||
| 2393 | (long long pid_, long long lid_, long long policy_, void *params_) { | ||
| 2394 | if (params_) { | ||
| 2395 | PRE_READ(params_, struct_sched_param_sz); | ||
| 2396 | } | ||
| 2397 | } | ||
| 2398 | POST_SYSCALL(_sched_setparam) | ||
| 2399 | (long long res, long long pid_, long long lid_, long long policy_, | ||
| 2400 | void *params_) { | ||
| 2401 | if (params_) { | ||
| 2402 | PRE_READ(params_, struct_sched_param_sz); | ||
| 2403 | } | ||
| 2404 | } | ||
| 2405 | PRE_SYSCALL(_sched_getparam) | ||
| 2406 | (long long pid_, long long lid_, void *policy_, void *params_) { | ||
| 2407 | /* Nothing to do */ | ||
| 2408 | } | ||
| 2409 | POST_SYSCALL(_sched_getparam) | ||
| 2410 | (long long res, long long pid_, long long lid_, void *policy_, void *params_) { | ||
| 2411 | /* Nothing to do */ | ||
| 2412 | } | ||
| 2413 | PRE_SYSCALL(_sched_setaffinity) | ||
| 2414 | (long long pid_, long long lid_, long long size_, void *cpuset_) { | ||
| 2415 | if (cpuset_) { | ||
| 2416 | PRE_READ(cpuset_, size_); | ||
| 2417 | } | ||
| 2418 | } | ||
| 2419 | POST_SYSCALL(_sched_setaffinity) | ||
| 2420 | (long long res, long long pid_, long long lid_, long long size_, | ||
| 2421 | void *cpuset_) { | ||
| 2422 | if (cpuset_) { | ||
| 2423 | PRE_READ(cpuset_, size_); | ||
| 2424 | } | ||
| 2425 | } | ||
| 2426 | PRE_SYSCALL(_sched_getaffinity) | ||
| 2427 | (long long pid_, long long lid_, long long size_, void *cpuset_) { | ||
| 2428 | /* Nothing to do */ | ||
| 2429 | } | ||
| 2430 | POST_SYSCALL(_sched_getaffinity) | ||
| 2431 | (long long res, long long pid_, long long lid_, long long size_, | ||
| 2432 | void *cpuset_) { | ||
| 2433 | /* Nothing to do */ | ||
| 2434 | } | ||
| 2435 | PRE_SYSCALL(sched_yield)(void) { /* Nothing to do */ } | ||
| 2436 | POST_SYSCALL(sched_yield)(long long res) { /* Nothing to do */ } | ||
| 2437 | PRE_SYSCALL(_sched_protect)(long long priority_) { /* Nothing to do */ } | ||
| 2438 | POST_SYSCALL(_sched_protect)(long long res, long long priority_) { | ||
| 2439 | /* Nothing to do */ | ||
| 2440 | } | ||
| 2441 | /* syscall 352 has been skipped */ | ||
| 2442 | /* syscall 353 has been skipped */ | ||
| 2443 | PRE_SYSCALL(fsync_range) | ||
| 2444 | (long long fd_, long long flags_, long long start_, long long length_) { | ||
| 2445 | /* Nothing to do */ | ||
| 2446 | } | ||
| 2447 | POST_SYSCALL(fsync_range) | ||
| 2448 | (long long res, long long fd_, long long flags_, long long start_, | ||
| 2449 | long long length_) { | ||
| 2450 | /* Nothing to do */ | ||
| 2451 | } | ||
| 2452 | PRE_SYSCALL(uuidgen)(void *store_, long long count_) { /* Nothing to do */ } | ||
| 2453 | POST_SYSCALL(uuidgen)(long long res, void *store_, long long count_) { | ||
| 2454 | /* Nothing to do */ | ||
| 2455 | } | ||
| 2456 | PRE_SYSCALL(compat_90_getvfsstat) | ||
| 2457 | (void *buf_, long long bufsize_, long long flags_) { | ||
| 2458 | /* Nothing to do */ | ||
| 2459 | } | ||
| 2460 | POST_SYSCALL(compat_90_getvfsstat) | ||
| 2461 | (long long res, void *buf_, long long bufsize_, long long flags_) { | ||
| 2462 | /* Nothing to do */ | ||
| 2463 | } | ||
| 2464 | PRE_SYSCALL(compat_90_statvfs1)(void *path_, void *buf_, long long flags_) { | ||
| 2465 | const char *path = (const char *)path_; | ||
| 2466 | if (path) { | ||
| 2467 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2468 | } | ||
| 2469 | } | ||
| 2470 | POST_SYSCALL(compat_90_statvfs1) | ||
| 2471 | (long long res, void *path_, void *buf_, long long flags_) { | ||
| 2472 | const char *path = (const char *)path_; | ||
| 2473 | if (path) { | ||
| 2474 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2475 | } | ||
| 2476 | } | ||
| 2477 | PRE_SYSCALL(compat_90_fstatvfs1)(long long fd_, void *buf_, long long flags_) { | ||
| 2478 | /* Nothing to do */ | ||
| 2479 | } | ||
| 2480 | POST_SYSCALL(compat_90_fstatvfs1) | ||
| 2481 | (long long res, long long fd_, void *buf_, long long flags_) { | ||
| 2482 | /* Nothing to do */ | ||
| 2483 | } | ||
| 2484 | PRE_SYSCALL(compat_30_fhstatvfs1)(void *fhp_, void *buf_, long long flags_) { | ||
| 2485 | /* TODO */ | ||
| 2486 | } | ||
| 2487 | POST_SYSCALL(compat_30_fhstatvfs1) | ||
| 2488 | (long long res, void *fhp_, void *buf_, long long flags_) { | ||
| 2489 | /* TODO */ | ||
| 2490 | } | ||
| 2491 | PRE_SYSCALL(extattrctl) | ||
| 2492 | (void *path_, long long cmd_, void *filename_, long long attrnamespace_, | ||
| 2493 | void *attrname_) { | ||
| 2494 | const char *path = (const char *)path_; | ||
| 2495 | if (path) { | ||
| 2496 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2497 | } | ||
| 2498 | } | ||
| 2499 | POST_SYSCALL(extattrctl) | ||
| 2500 | (long long res, void *path_, long long cmd_, void *filename_, | ||
| 2501 | long long attrnamespace_, void *attrname_) { | ||
| 2502 | const char *path = (const char *)path_; | ||
| 2503 | if (path) { | ||
| 2504 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2505 | } | ||
| 2506 | } | ||
| 2507 | PRE_SYSCALL(extattr_set_file) | ||
| 2508 | (void *path_, long long attrnamespace_, void *attrname_, void *data_, | ||
| 2509 | long long nbytes_) { | ||
| 2510 | const char *path = (const char *)path_; | ||
| 2511 | if (path) { | ||
| 2512 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2513 | } | ||
| 2514 | } | ||
| 2515 | POST_SYSCALL(extattr_set_file) | ||
| 2516 | (long long res, void *path_, long long attrnamespace_, void *attrname_, | ||
| 2517 | void *data_, long long nbytes_) { | ||
| 2518 | const char *path = (const char *)path_; | ||
| 2519 | if (path) { | ||
| 2520 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2521 | } | ||
| 2522 | } | ||
| 2523 | PRE_SYSCALL(extattr_get_file) | ||
| 2524 | (void *path_, long long attrnamespace_, void *attrname_, void *data_, | ||
| 2525 | long long nbytes_) { | ||
| 2526 | const char *path = (const char *)path_; | ||
| 2527 | if (path) { | ||
| 2528 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2529 | } | ||
| 2530 | } | ||
| 2531 | POST_SYSCALL(extattr_get_file) | ||
| 2532 | (long long res, void *path_, long long attrnamespace_, void *attrname_, | ||
| 2533 | void *data_, long long nbytes_) { | ||
| 2534 | const char *path = (const char *)path_; | ||
| 2535 | if (path) { | ||
| 2536 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2537 | } | ||
| 2538 | } | ||
| 2539 | PRE_SYSCALL(extattr_delete_file) | ||
| 2540 | (void *path_, long long attrnamespace_, void *attrname_) { | ||
| 2541 | const char *path = (const char *)path_; | ||
| 2542 | if (path) { | ||
| 2543 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2544 | } | ||
| 2545 | } | ||
| 2546 | POST_SYSCALL(extattr_delete_file) | ||
| 2547 | (long long res, void *path_, long long attrnamespace_, void *attrname_) { | ||
| 2548 | const char *path = (const char *)path_; | ||
| 2549 | if (path) { | ||
| 2550 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2551 | } | ||
| 2552 | } | ||
| 2553 | PRE_SYSCALL(extattr_set_fd) | ||
| 2554 | (long long fd_, long long attrnamespace_, void *attrname_, void *data_, | ||
| 2555 | long long nbytes_) { | ||
| 2556 | /* TODO */ | ||
| 2557 | } | ||
| 2558 | POST_SYSCALL(extattr_set_fd) | ||
| 2559 | (long long res, long long fd_, long long attrnamespace_, void *attrname_, | ||
| 2560 | void *data_, long long nbytes_) { | ||
| 2561 | /* TODO */ | ||
| 2562 | } | ||
| 2563 | PRE_SYSCALL(extattr_get_fd) | ||
| 2564 | (long long fd_, long long attrnamespace_, void *attrname_, void *data_, | ||
| 2565 | long long nbytes_) { | ||
| 2566 | /* TODO */ | ||
| 2567 | } | ||
| 2568 | POST_SYSCALL(extattr_get_fd) | ||
| 2569 | (long long res, long long fd_, long long attrnamespace_, void *attrname_, | ||
| 2570 | void *data_, long long nbytes_) { | ||
| 2571 | /* TODO */ | ||
| 2572 | } | ||
| 2573 | PRE_SYSCALL(extattr_delete_fd) | ||
| 2574 | (long long fd_, long long attrnamespace_, void *attrname_) { | ||
| 2575 | /* TODO */ | ||
| 2576 | } | ||
| 2577 | POST_SYSCALL(extattr_delete_fd) | ||
| 2578 | (long long res, long long fd_, long long attrnamespace_, void *attrname_) { | ||
| 2579 | /* TODO */ | ||
| 2580 | } | ||
| 2581 | PRE_SYSCALL(extattr_set_link) | ||
| 2582 | (void *path_, long long attrnamespace_, void *attrname_, void *data_, | ||
| 2583 | long long nbytes_) { | ||
| 2584 | const char *path = (const char *)path_; | ||
| 2585 | if (path) { | ||
| 2586 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2587 | } | ||
| 2588 | } | ||
| 2589 | POST_SYSCALL(extattr_set_link) | ||
| 2590 | (long long res, void *path_, long long attrnamespace_, void *attrname_, | ||
| 2591 | void *data_, long long nbytes_) { | ||
| 2592 | const char *path = (const char *)path_; | ||
| 2593 | if (path) { | ||
| 2594 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2595 | } | ||
| 2596 | } | ||
| 2597 | PRE_SYSCALL(extattr_get_link) | ||
| 2598 | (void *path_, long long attrnamespace_, void *attrname_, void *data_, | ||
| 2599 | long long nbytes_) { | ||
| 2600 | const char *path = (const char *)path_; | ||
| 2601 | if (path) { | ||
| 2602 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2603 | } | ||
| 2604 | } | ||
| 2605 | POST_SYSCALL(extattr_get_link) | ||
| 2606 | (long long res, void *path_, long long attrnamespace_, void *attrname_, | ||
| 2607 | void *data_, long long nbytes_) { | ||
| 2608 | const char *path = (const char *)path_; | ||
| 2609 | if (path) { | ||
| 2610 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2611 | } | ||
| 2612 | } | ||
| 2613 | PRE_SYSCALL(extattr_delete_link) | ||
| 2614 | (void *path_, long long attrnamespace_, void *attrname_) { | ||
| 2615 | const char *path = (const char *)path_; | ||
| 2616 | if (path) { | ||
| 2617 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2618 | } | ||
| 2619 | } | ||
| 2620 | POST_SYSCALL(extattr_delete_link) | ||
| 2621 | (long long res, void *path_, long long attrnamespace_, void *attrname_) { | ||
| 2622 | const char *path = (const char *)path_; | ||
| 2623 | if (path) { | ||
| 2624 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2625 | } | ||
| 2626 | } | ||
| 2627 | PRE_SYSCALL(extattr_list_fd) | ||
| 2628 | (long long fd_, long long attrnamespace_, void *data_, long long nbytes_) { | ||
| 2629 | /* TODO */ | ||
| 2630 | } | ||
| 2631 | POST_SYSCALL(extattr_list_fd) | ||
| 2632 | (long long res, long long fd_, long long attrnamespace_, void *data_, | ||
| 2633 | long long nbytes_) { | ||
| 2634 | /* TODO */ | ||
| 2635 | } | ||
| 2636 | PRE_SYSCALL(extattr_list_file) | ||
| 2637 | (void *path_, long long attrnamespace_, void *data_, long long nbytes_) { | ||
| 2638 | const char *path = (const char *)path_; | ||
| 2639 | if (path) { | ||
| 2640 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2641 | } | ||
| 2642 | } | ||
| 2643 | POST_SYSCALL(extattr_list_file) | ||
| 2644 | (long long res, void *path_, long long attrnamespace_, void *data_, | ||
| 2645 | long long nbytes_) { | ||
| 2646 | const char *path = (const char *)path_; | ||
| 2647 | if (path) { | ||
| 2648 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2649 | } | ||
| 2650 | } | ||
| 2651 | PRE_SYSCALL(extattr_list_link) | ||
| 2652 | (void *path_, long long attrnamespace_, void *data_, long long nbytes_) { | ||
| 2653 | const char *path = (const char *)path_; | ||
| 2654 | if (path) { | ||
| 2655 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2656 | } | ||
| 2657 | } | ||
| 2658 | POST_SYSCALL(extattr_list_link) | ||
| 2659 | (long long res, void *path_, long long attrnamespace_, void *data_, | ||
| 2660 | long long nbytes_) { | ||
| 2661 | const char *path = (const char *)path_; | ||
| 2662 | if (path) { | ||
| 2663 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2664 | } | ||
| 2665 | } | ||
| 2666 | PRE_SYSCALL(compat_50_pselect) | ||
| 2667 | (long long nd_, void *in_, void *ou_, void *ex_, void *ts_, void *mask_) { | ||
| 2668 | /* TODO */ | ||
| 2669 | } | ||
| 2670 | POST_SYSCALL(compat_50_pselect) | ||
| 2671 | (long long res, long long nd_, void *in_, void *ou_, void *ex_, void *ts_, | ||
| 2672 | void *mask_) { | ||
| 2673 | /* TODO */ | ||
| 2674 | } | ||
| 2675 | PRE_SYSCALL(compat_50_pollts) | ||
| 2676 | (void *fds_, long long nfds_, void *ts_, void *mask_) { | ||
| 2677 | /* TODO */ | ||
| 2678 | } | ||
| 2679 | POST_SYSCALL(compat_50_pollts) | ||
| 2680 | (long long res, void *fds_, long long nfds_, void *ts_, void *mask_) { | ||
| 2681 | /* TODO */ | ||
| 2682 | } | ||
| 2683 | PRE_SYSCALL(setxattr) | ||
| 2684 | (void *path_, void *name_, void *value_, long long size_, long long flags_) { | ||
| 2685 | const char *path = (const char *)path_; | ||
| 2686 | if (path) { | ||
| 2687 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2688 | } | ||
| 2689 | } | ||
| 2690 | POST_SYSCALL(setxattr) | ||
| 2691 | (long long res, void *path_, void *name_, void *value_, long long size_, | ||
| 2692 | long long flags_) { | ||
| 2693 | const char *path = (const char *)path_; | ||
| 2694 | if (path) { | ||
| 2695 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2696 | } | ||
| 2697 | } | ||
| 2698 | PRE_SYSCALL(lsetxattr) | ||
| 2699 | (void *path_, void *name_, void *value_, long long size_, long long flags_) { | ||
| 2700 | const char *path = (const char *)path_; | ||
| 2701 | if (path) { | ||
| 2702 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2703 | } | ||
| 2704 | } | ||
| 2705 | POST_SYSCALL(lsetxattr) | ||
| 2706 | (long long res, void *path_, void *name_, void *value_, long long size_, | ||
| 2707 | long long flags_) { | ||
| 2708 | const char *path = (const char *)path_; | ||
| 2709 | if (path) { | ||
| 2710 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2711 | } | ||
| 2712 | } | ||
| 2713 | PRE_SYSCALL(fsetxattr) | ||
| 2714 | (long long fd_, void *name_, void *value_, long long size_, long long flags_) { | ||
| 2715 | /* Nothing to do */ | ||
| 2716 | } | ||
| 2717 | POST_SYSCALL(fsetxattr) | ||
| 2718 | (long long res, long long fd_, void *name_, void *value_, long long size_, | ||
| 2719 | long long flags_) { | ||
| 2720 | /* Nothing to do */ | ||
| 2721 | } | ||
| 2722 | PRE_SYSCALL(getxattr)(void *path_, void *name_, void *value_, long long size_) { | ||
| 2723 | const char *path = (const char *)path_; | ||
| 2724 | if (path) { | ||
| 2725 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2726 | } | ||
| 2727 | } | ||
| 2728 | POST_SYSCALL(getxattr) | ||
| 2729 | (long long res, void *path_, void *name_, void *value_, long long size_) { | ||
| 2730 | const char *path = (const char *)path_; | ||
| 2731 | if (path) { | ||
| 2732 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2733 | } | ||
| 2734 | } | ||
| 2735 | PRE_SYSCALL(lgetxattr) | ||
| 2736 | (void *path_, void *name_, void *value_, long long size_) { | ||
| 2737 | const char *path = (const char *)path_; | ||
| 2738 | if (path) { | ||
| 2739 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2740 | } | ||
| 2741 | } | ||
| 2742 | POST_SYSCALL(lgetxattr) | ||
| 2743 | (long long res, void *path_, void *name_, void *value_, long long size_) { | ||
| 2744 | const char *path = (const char *)path_; | ||
| 2745 | if (path) { | ||
| 2746 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2747 | } | ||
| 2748 | } | ||
| 2749 | PRE_SYSCALL(fgetxattr) | ||
| 2750 | (long long fd_, void *name_, void *value_, long long size_) { | ||
| 2751 | /* Nothing to do */ | ||
| 2752 | } | ||
| 2753 | POST_SYSCALL(fgetxattr) | ||
| 2754 | (long long res, long long fd_, void *name_, void *value_, long long size_) { | ||
| 2755 | /* Nothing to do */ | ||
| 2756 | } | ||
| 2757 | PRE_SYSCALL(listxattr)(void *path_, void *list_, long long size_) { | ||
| 2758 | const char *path = (const char *)path_; | ||
| 2759 | if (path) { | ||
| 2760 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2761 | } | ||
| 2762 | } | ||
| 2763 | POST_SYSCALL(listxattr) | ||
| 2764 | (long long res, void *path_, void *list_, long long size_) { | ||
| 2765 | const char *path = (const char *)path_; | ||
| 2766 | if (path) { | ||
| 2767 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2768 | } | ||
| 2769 | } | ||
| 2770 | PRE_SYSCALL(llistxattr)(void *path_, void *list_, long long size_) { | ||
| 2771 | const char *path = (const char *)path_; | ||
| 2772 | if (path) { | ||
| 2773 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2774 | } | ||
| 2775 | } | ||
| 2776 | POST_SYSCALL(llistxattr) | ||
| 2777 | (long long res, void *path_, void *list_, long long size_) { | ||
| 2778 | const char *path = (const char *)path_; | ||
| 2779 | if (path) { | ||
| 2780 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2781 | } | ||
| 2782 | } | ||
| 2783 | PRE_SYSCALL(flistxattr)(long long fd_, void *list_, long long size_) { | ||
| 2784 | /* TODO */ | ||
| 2785 | } | ||
| 2786 | POST_SYSCALL(flistxattr) | ||
| 2787 | (long long res, long long fd_, void *list_, long long size_) { | ||
| 2788 | /* TODO */ | ||
| 2789 | } | ||
| 2790 | PRE_SYSCALL(removexattr)(void *path_, void *name_) { | ||
| 2791 | const char *path = (const char *)path_; | ||
| 2792 | if (path) { | ||
| 2793 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2794 | } | ||
| 2795 | } | ||
| 2796 | POST_SYSCALL(removexattr)(long long res, void *path_, void *name_) { | ||
| 2797 | const char *path = (const char *)path_; | ||
| 2798 | if (path) { | ||
| 2799 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2800 | } | ||
| 2801 | } | ||
| 2802 | PRE_SYSCALL(lremovexattr)(void *path_, void *name_) { | ||
| 2803 | const char *path = (const char *)path_; | ||
| 2804 | if (path) { | ||
| 2805 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2806 | } | ||
| 2807 | } | ||
| 2808 | POST_SYSCALL(lremovexattr)(long long res, void *path_, void *name_) { | ||
| 2809 | const char *path = (const char *)path_; | ||
| 2810 | if (path) { | ||
| 2811 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2812 | } | ||
| 2813 | } | ||
| 2814 | PRE_SYSCALL(fremovexattr)(long long fd_, void *name_) { /* TODO */ } | ||
| 2815 | POST_SYSCALL(fremovexattr)(long long res, long long fd_, void *name_) { | ||
| 2816 | /* TODO */ | ||
| 2817 | } | ||
| 2818 | PRE_SYSCALL(compat_50___stat30)(void *path_, void *ub_) { /* TODO */ } | ||
| 2819 | POST_SYSCALL(compat_50___stat30)(long long res, void *path_, void *ub_) { | ||
| 2820 | /* TODO */ | ||
| 2821 | } | ||
| 2822 | PRE_SYSCALL(compat_50___fstat30)(long long fd_, void *sb_) { /* TODO */ } | ||
| 2823 | POST_SYSCALL(compat_50___fstat30)(long long res, long long fd_, void *sb_) { | ||
| 2824 | /* TODO */ | ||
| 2825 | } | ||
| 2826 | PRE_SYSCALL(compat_50___lstat30)(void *path_, void *ub_) { /* TODO */ } | ||
| 2827 | POST_SYSCALL(compat_50___lstat30)(long long res, void *path_, void *ub_) { | ||
| 2828 | /* TODO */ | ||
| 2829 | } | ||
| 2830 | PRE_SYSCALL(__getdents30)(long long fd_, void *buf_, long long count_) { | ||
| 2831 | /* Nothing to do */ | ||
| 2832 | } | ||
| 2833 | POST_SYSCALL(__getdents30) | ||
| 2834 | (long long res, long long fd_, void *buf_, long long count_) { | ||
| 2835 | /* Nothing to do */ | ||
| 2836 | } | ||
| 2837 | PRE_SYSCALL(posix_fadvise)(long long) { /* Nothing to do */ } | ||
| 2838 | POST_SYSCALL(posix_fadvise)(long long res, long long) { /* Nothing to do */ } | ||
| 2839 | PRE_SYSCALL(compat_30___fhstat30)(void *fhp_, void *sb_) { /* TODO */ } | ||
| 2840 | POST_SYSCALL(compat_30___fhstat30)(long long res, void *fhp_, void *sb_) { | ||
| 2841 | /* TODO */ | ||
| 2842 | } | ||
| 2843 | PRE_SYSCALL(compat_50___ntp_gettime30)(void *ntvp_) { /* TODO */ } | ||
| 2844 | POST_SYSCALL(compat_50___ntp_gettime30)(long long res, void *ntvp_) { | ||
| 2845 | /* TODO */ | ||
| 2846 | } | ||
| 2847 | PRE_SYSCALL(__socket30) | ||
| 2848 | (long long domain_, long long type_, long long protocol_) { | ||
| 2849 | /* Nothing to do */ | ||
| 2850 | } | ||
| 2851 | POST_SYSCALL(__socket30) | ||
| 2852 | (long long res, long long domain_, long long type_, long long protocol_) { | ||
| 2853 | /* Nothing to do */ | ||
| 2854 | } | ||
| 2855 | PRE_SYSCALL(__getfh30)(void *fname_, void *fhp_, void *fh_size_) { | ||
| 2856 | const char *fname = (const char *)fname_; | ||
| 2857 | if (fname) { | ||
| 2858 | PRE_READ(fname, __sanitizer::internal_strlen(fname) + 1); | ||
| 2859 | } | ||
| 2860 | } | ||
| 2861 | POST_SYSCALL(__getfh30) | ||
| 2862 | (long long res, void *fname_, void *fhp_, void *fh_size_) { | ||
| 2863 | const char *fname = (const char *)fname_; | ||
| 2864 | if (res == 0) { | ||
| 2865 | if (fname) { | ||
| 2866 | POST_READ(fname, __sanitizer::internal_strlen(fname) + 1); | ||
| 2867 | } | ||
| 2868 | } | ||
| 2869 | } | ||
| 2870 | PRE_SYSCALL(__fhopen40)(void *fhp_, long long fh_size_, long long flags_) { | ||
| 2871 | if (fhp_) { | ||
| 2872 | PRE_READ(fhp_, fh_size_); | ||
| 2873 | } | ||
| 2874 | } | ||
| 2875 | POST_SYSCALL(__fhopen40) | ||
| 2876 | (long long res, void *fhp_, long long fh_size_, long long flags_) {} | ||
| 2877 | PRE_SYSCALL(compat_90_fhstatvfs1) | ||
| 2878 | (void *fhp_, long long fh_size_, void *buf_, long long flags_) { | ||
| 2879 | if (fhp_) { | ||
| 2880 | PRE_READ(fhp_, fh_size_); | ||
| 2881 | } | ||
| 2882 | } | ||
| 2883 | POST_SYSCALL(compat_90_fhstatvfs1) | ||
| 2884 | (long long res, void *fhp_, long long fh_size_, void *buf_, long long flags_) {} | ||
| 2885 | PRE_SYSCALL(compat_50___fhstat40)(void *fhp_, long long fh_size_, void *sb_) { | ||
| 2886 | if (fhp_) { | ||
| 2887 | PRE_READ(fhp_, fh_size_); | ||
| 2888 | } | ||
| 2889 | } | ||
| 2890 | POST_SYSCALL(compat_50___fhstat40) | ||
| 2891 | (long long res, void *fhp_, long long fh_size_, void *sb_) {} | ||
| 2892 | PRE_SYSCALL(aio_cancel)(long long fildes_, void *aiocbp_) { | ||
| 2893 | if (aiocbp_) { | ||
| 2894 | PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); | ||
| 2895 | } | ||
| 2896 | } | ||
| 2897 | POST_SYSCALL(aio_cancel)(long long res, long long fildes_, void *aiocbp_) {} | ||
| 2898 | PRE_SYSCALL(aio_error)(void *aiocbp_) { | ||
| 2899 | if (aiocbp_) { | ||
| 2900 | PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); | ||
| 2901 | } | ||
| 2902 | } | ||
| 2903 | POST_SYSCALL(aio_error)(long long res, void *aiocbp_) {} | ||
| 2904 | PRE_SYSCALL(aio_fsync)(long long op_, void *aiocbp_) { | ||
| 2905 | if (aiocbp_) { | ||
| 2906 | PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); | ||
| 2907 | } | ||
| 2908 | } | ||
| 2909 | POST_SYSCALL(aio_fsync)(long long res, long long op_, void *aiocbp_) {} | ||
| 2910 | PRE_SYSCALL(aio_read)(void *aiocbp_) { | ||
| 2911 | if (aiocbp_) { | ||
| 2912 | PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); | ||
| 2913 | } | ||
| 2914 | } | ||
| 2915 | POST_SYSCALL(aio_read)(long long res, void *aiocbp_) {} | ||
| 2916 | PRE_SYSCALL(aio_return)(void *aiocbp_) { | ||
| 2917 | if (aiocbp_) { | ||
| 2918 | PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); | ||
| 2919 | } | ||
| 2920 | } | ||
| 2921 | POST_SYSCALL(aio_return)(long long res, void *aiocbp_) {} | ||
| 2922 | PRE_SYSCALL(compat_50_aio_suspend) | ||
| 2923 | (void *list_, long long nent_, void *timeout_) { | ||
| 2924 | /* TODO */ | ||
| 2925 | } | ||
| 2926 | POST_SYSCALL(compat_50_aio_suspend) | ||
| 2927 | (long long res, void *list_, long long nent_, void *timeout_) { | ||
| 2928 | /* TODO */ | ||
| 2929 | } | ||
| 2930 | PRE_SYSCALL(aio_write)(void *aiocbp_) { | ||
| 2931 | if (aiocbp_) { | ||
| 2932 | PRE_READ(aiocbp_, sizeof(struct __sanitizer_aiocb)); | ||
| 2933 | } | ||
| 2934 | } | ||
| 2935 | POST_SYSCALL(aio_write)(long long res, void *aiocbp_) {} | ||
| 2936 | PRE_SYSCALL(lio_listio) | ||
| 2937 | (long long mode_, void *list_, long long nent_, void *sig_) { | ||
| 2938 | /* Nothing to do */ | ||
| 2939 | } | ||
| 2940 | POST_SYSCALL(lio_listio) | ||
| 2941 | (long long res, long long mode_, void *list_, long long nent_, void *sig_) { | ||
| 2942 | /* Nothing to do */ | ||
| 2943 | } | ||
| 2944 | /* syscall 407 has been skipped */ | ||
| 2945 | /* syscall 408 has been skipped */ | ||
| 2946 | /* syscall 409 has been skipped */ | ||
| 2947 | PRE_SYSCALL(__mount50) | ||
| 2948 | (void *type_, void *path_, long long flags_, void *data_, long long data_len_) { | ||
| 2949 | const char *type = (const char *)type_; | ||
| 2950 | const char *path = (const char *)path_; | ||
| 2951 | if (type) { | ||
| 2952 | PRE_READ(type, __sanitizer::internal_strlen(type) + 1); | ||
| 2953 | } | ||
| 2954 | if (path) { | ||
| 2955 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2956 | } | ||
| 2957 | if (data_) { | ||
| 2958 | PRE_READ(data_, data_len_); | ||
| 2959 | } | ||
| 2960 | } | ||
| 2961 | POST_SYSCALL(__mount50) | ||
| 2962 | (long long res, void *type_, void *path_, long long flags_, void *data_, | ||
| 2963 | long long data_len_) { | ||
| 2964 | const char *type = (const char *)type_; | ||
| 2965 | const char *path = (const char *)path_; | ||
| 2966 | if (type) { | ||
| 2967 | POST_READ(type, __sanitizer::internal_strlen(type) + 1); | ||
| 2968 | } | ||
| 2969 | if (path) { | ||
| 2970 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 2971 | } | ||
| 2972 | if (data_) { | ||
| 2973 | POST_READ(data_, data_len_); | ||
| 2974 | } | ||
| 2975 | } | ||
| 2976 | PRE_SYSCALL(mremap) | ||
| 2977 | (void *old_address_, long long old_size_, void *new_address_, | ||
| 2978 | long long new_size_, long long flags_) { | ||
| 2979 | /* Nothing to do */ | ||
| 2980 | } | ||
| 2981 | POST_SYSCALL(mremap) | ||
| 2982 | (long long res, void *old_address_, long long old_size_, void *new_address_, | ||
| 2983 | long long new_size_, long long flags_) { | ||
| 2984 | /* Nothing to do */ | ||
| 2985 | } | ||
| 2986 | PRE_SYSCALL(pset_create)(void *psid_) { /* Nothing to do */ } | ||
| 2987 | POST_SYSCALL(pset_create)(long long res, void *psid_) { /* Nothing to do */ } | ||
| 2988 | PRE_SYSCALL(pset_destroy)(long long psid_) { /* Nothing to do */ } | ||
| 2989 | POST_SYSCALL(pset_destroy)(long long res, long long psid_) { | ||
| 2990 | /* Nothing to do */ | ||
| 2991 | } | ||
| 2992 | PRE_SYSCALL(pset_assign)(long long psid_, long long cpuid_, void *opsid_) { | ||
| 2993 | /* Nothing to do */ | ||
| 2994 | } | ||
| 2995 | POST_SYSCALL(pset_assign) | ||
| 2996 | (long long res, long long psid_, long long cpuid_, void *opsid_) { | ||
| 2997 | /* Nothing to do */ | ||
| 2998 | } | ||
| 2999 | PRE_SYSCALL(_pset_bind) | ||
| 3000 | (long long idtype_, long long first_id_, long long second_id_, long long psid_, | ||
| 3001 | void *opsid_) { | ||
| 3002 | /* Nothing to do */ | ||
| 3003 | } | ||
| 3004 | POST_SYSCALL(_pset_bind) | ||
| 3005 | (long long res, long long idtype_, long long first_id_, long long second_id_, | ||
| 3006 | long long psid_, void *opsid_) { | ||
| 3007 | /* Nothing to do */ | ||
| 3008 | } | ||
| 3009 | PRE_SYSCALL(__posix_fadvise50) | ||
| 3010 | (long long fd_, long long PAD_, long long offset_, long long len_, | ||
| 3011 | long long advice_) { | ||
| 3012 | /* Nothing to do */ | ||
| 3013 | } | ||
| 3014 | POST_SYSCALL(__posix_fadvise50) | ||
| 3015 | (long long res, long long fd_, long long PAD_, long long offset_, | ||
| 3016 | long long len_, long long advice_) { | ||
| 3017 | /* Nothing to do */ | ||
| 3018 | } | ||
| 3019 | PRE_SYSCALL(__select50) | ||
| 3020 | (long long nd_, void *in_, void *ou_, void *ex_, void *tv_) { | ||
| 3021 | /* Nothing to do */ | ||
| 3022 | } | ||
| 3023 | POST_SYSCALL(__select50) | ||
| 3024 | (long long res, long long nd_, void *in_, void *ou_, void *ex_, void *tv_) { | ||
| 3025 | /* Nothing to do */ | ||
| 3026 | } | ||
| 3027 | PRE_SYSCALL(__gettimeofday50)(void *tp_, void *tzp_) { /* Nothing to do */ } | ||
| 3028 | POST_SYSCALL(__gettimeofday50)(long long res, void *tp_, void *tzp_) { | ||
| 3029 | /* Nothing to do */ | ||
| 3030 | } | ||
| 3031 | PRE_SYSCALL(__settimeofday50)(void *tv_, void *tzp_) { | ||
| 3032 | if (tv_) { | ||
| 3033 | PRE_READ(tv_, timeval_sz); | ||
| 3034 | } | ||
| 3035 | if (tzp_) { | ||
| 3036 | PRE_READ(tzp_, struct_timezone_sz); | ||
| 3037 | } | ||
| 3038 | } | ||
| 3039 | POST_SYSCALL(__settimeofday50)(long long res, void *tv_, void *tzp_) {} | ||
| 3040 | PRE_SYSCALL(__utimes50)(void *path_, void *tptr_) { | ||
| 3041 | struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; | ||
| 3042 | const char *path = (const char *)path_; | ||
| 3043 | if (path) { | ||
| 3044 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3045 | } | ||
| 3046 | if (tptr) { | ||
| 3047 | PRE_READ(tptr[0], struct_timespec_sz); | ||
| 3048 | PRE_READ(tptr[1], struct_timespec_sz); | ||
| 3049 | } | ||
| 3050 | } | ||
| 3051 | POST_SYSCALL(__utimes50)(long long res, void *path_, void *tptr_) {} | ||
| 3052 | PRE_SYSCALL(__adjtime50)(void *delta_, void *olddelta_) { | ||
| 3053 | if (delta_) { | ||
| 3054 | PRE_READ(delta_, timeval_sz); | ||
| 3055 | } | ||
| 3056 | } | ||
| 3057 | POST_SYSCALL(__adjtime50)(long long res, void *delta_, void *olddelta_) {} | ||
| 3058 | PRE_SYSCALL(__lfs_segwait50)(void *fsidp_, void *tv_) { /* TODO */ } | ||
| 3059 | POST_SYSCALL(__lfs_segwait50)(long long res, void *fsidp_, void *tv_) { | ||
| 3060 | /* TODO */ | ||
| 3061 | } | ||
| 3062 | PRE_SYSCALL(__futimes50)(long long fd_, void *tptr_) { | ||
| 3063 | struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; | ||
| 3064 | if (tptr) { | ||
| 3065 | PRE_READ(tptr[0], struct_timespec_sz); | ||
| 3066 | PRE_READ(tptr[1], struct_timespec_sz); | ||
| 3067 | } | ||
| 3068 | } | ||
| 3069 | POST_SYSCALL(__futimes50)(long long res, long long fd_, void *tptr_) {} | ||
| 3070 | PRE_SYSCALL(__lutimes50)(void *path_, void *tptr_) { | ||
| 3071 | struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; | ||
| 3072 | const char *path = (const char *)path_; | ||
| 3073 | if (path) { | ||
| 3074 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3075 | } | ||
| 3076 | if (tptr) { | ||
| 3077 | PRE_READ(tptr[0], struct_timespec_sz); | ||
| 3078 | PRE_READ(tptr[1], struct_timespec_sz); | ||
| 3079 | } | ||
| 3080 | } | ||
| 3081 | POST_SYSCALL(__lutimes50)(long long res, void *path_, void *tptr_) { | ||
| 3082 | struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; | ||
| 3083 | const char *path = (const char *)path_; | ||
| 3084 | if (path) { | ||
| 3085 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3086 | } | ||
| 3087 | if (tptr) { | ||
| 3088 | POST_READ(tptr[0], struct_timespec_sz); | ||
| 3089 | POST_READ(tptr[1], struct_timespec_sz); | ||
| 3090 | } | ||
| 3091 | } | ||
| 3092 | PRE_SYSCALL(__setitimer50)(long long which_, void *itv_, void *oitv_) { | ||
| 3093 | struct __sanitizer_itimerval *itv = (struct __sanitizer_itimerval *)itv_; | ||
| 3094 | if (itv) { | ||
| 3095 | PRE_READ(&itv->it_interval.tv_sec, sizeof(__sanitizer_time_t)); | ||
| 3096 | PRE_READ(&itv->it_interval.tv_usec, sizeof(__sanitizer_suseconds_t)); | ||
| 3097 | PRE_READ(&itv->it_value.tv_sec, sizeof(__sanitizer_time_t)); | ||
| 3098 | PRE_READ(&itv->it_value.tv_usec, sizeof(__sanitizer_suseconds_t)); | ||
| 3099 | } | ||
| 3100 | } | ||
| 3101 | POST_SYSCALL(__setitimer50) | ||
| 3102 | (long long res, long long which_, void *itv_, void *oitv_) {} | ||
| 3103 | PRE_SYSCALL(__getitimer50)(long long which_, void *itv_) { /* Nothing to do */ } | ||
| 3104 | POST_SYSCALL(__getitimer50)(long long res, long long which_, void *itv_) { | ||
| 3105 | /* Nothing to do */ | ||
| 3106 | } | ||
| 3107 | PRE_SYSCALL(__clock_gettime50)(long long clock_id_, void *tp_) { | ||
| 3108 | /* Nothing to do */ | ||
| 3109 | } | ||
| 3110 | POST_SYSCALL(__clock_gettime50)(long long res, long long clock_id_, void *tp_) { | ||
| 3111 | /* Nothing to do */ | ||
| 3112 | } | ||
| 3113 | PRE_SYSCALL(__clock_settime50)(long long clock_id_, void *tp_) { | ||
| 3114 | if (tp_) { | ||
| 3115 | PRE_READ(tp_, struct_timespec_sz); | ||
| 3116 | } | ||
| 3117 | } | ||
| 3118 | POST_SYSCALL(__clock_settime50) | ||
| 3119 | (long long res, long long clock_id_, void *tp_) {} | ||
| 3120 | PRE_SYSCALL(__clock_getres50)(long long clock_id_, void *tp_) { | ||
| 3121 | /* Nothing to do */ | ||
| 3122 | } | ||
| 3123 | POST_SYSCALL(__clock_getres50)(long long res, long long clock_id_, void *tp_) { | ||
| 3124 | /* Nothing to do */ | ||
| 3125 | } | ||
| 3126 | PRE_SYSCALL(__nanosleep50)(void *rqtp_, void *rmtp_) { | ||
| 3127 | if (rqtp_) { | ||
| 3128 | PRE_READ(rqtp_, struct_timespec_sz); | ||
| 3129 | } | ||
| 3130 | } | ||
| 3131 | POST_SYSCALL(__nanosleep50)(long long res, void *rqtp_, void *rmtp_) {} | ||
| 3132 | PRE_SYSCALL(____sigtimedwait50)(void *set_, void *info_, void *timeout_) { | ||
| 3133 | if (set_) { | ||
| 3134 | PRE_READ(set_, sizeof(__sanitizer_sigset_t)); | ||
| 3135 | } | ||
| 3136 | if (timeout_) { | ||
| 3137 | PRE_READ(timeout_, struct_timespec_sz); | ||
| 3138 | } | ||
| 3139 | } | ||
| 3140 | POST_SYSCALL(____sigtimedwait50) | ||
| 3141 | (long long res, void *set_, void *info_, void *timeout_) {} | ||
| 3142 | PRE_SYSCALL(__mq_timedsend50) | ||
| 3143 | (long long mqdes_, void *msg_ptr_, long long msg_len_, long long msg_prio_, | ||
| 3144 | void *abs_timeout_) { | ||
| 3145 | if (msg_ptr_) { | ||
| 3146 | PRE_READ(msg_ptr_, msg_len_); | ||
| 3147 | } | ||
| 3148 | if (abs_timeout_) { | ||
| 3149 | PRE_READ(abs_timeout_, struct_timespec_sz); | ||
| 3150 | } | ||
| 3151 | } | ||
| 3152 | POST_SYSCALL(__mq_timedsend50) | ||
| 3153 | (long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, | ||
| 3154 | long long msg_prio_, void *abs_timeout_) {} | ||
| 3155 | PRE_SYSCALL(__mq_timedreceive50) | ||
| 3156 | (long long mqdes_, void *msg_ptr_, long long msg_len_, void *msg_prio_, | ||
| 3157 | void *abs_timeout_) { | ||
| 3158 | if (msg_ptr_) { | ||
| 3159 | PRE_READ(msg_ptr_, msg_len_); | ||
| 3160 | } | ||
| 3161 | if (abs_timeout_) { | ||
| 3162 | PRE_READ(abs_timeout_, struct_timespec_sz); | ||
| 3163 | } | ||
| 3164 | } | ||
| 3165 | POST_SYSCALL(__mq_timedreceive50) | ||
| 3166 | (long long res, long long mqdes_, void *msg_ptr_, long long msg_len_, | ||
| 3167 | void *msg_prio_, void *abs_timeout_) {} | ||
| 3168 | PRE_SYSCALL(compat_60__lwp_park) | ||
| 3169 | (void *ts_, long long unpark_, void *hint_, void *unparkhint_) { | ||
| 3170 | /* TODO */ | ||
| 3171 | } | ||
| 3172 | POST_SYSCALL(compat_60__lwp_park) | ||
| 3173 | (long long res, void *ts_, long long unpark_, void *hint_, void *unparkhint_) { | ||
| 3174 | /* TODO */ | ||
| 3175 | } | ||
| 3176 | PRE_SYSCALL(__kevent50) | ||
| 3177 | (long long fd_, void *changelist_, long long nchanges_, void *eventlist_, | ||
| 3178 | long long nevents_, void *timeout_) { | ||
| 3179 | if (changelist_) { | ||
| 3180 | PRE_READ(changelist_, nchanges_ * struct_kevent_sz); | ||
| 3181 | } | ||
| 3182 | if (timeout_) { | ||
| 3183 | PRE_READ(timeout_, struct_timespec_sz); | ||
| 3184 | } | ||
| 3185 | } | ||
| 3186 | POST_SYSCALL(__kevent50) | ||
| 3187 | (long long res, long long fd_, void *changelist_, long long nchanges_, | ||
| 3188 | void *eventlist_, long long nevents_, void *timeout_) {} | ||
| 3189 | PRE_SYSCALL(__pselect50) | ||
| 3190 | (long long nd_, void *in_, void *ou_, void *ex_, void *ts_, void *mask_) { | ||
| 3191 | if (ts_) { | ||
| 3192 | PRE_READ(ts_, struct_timespec_sz); | ||
| 3193 | } | ||
| 3194 | if (mask_) { | ||
| 3195 | PRE_READ(mask_, sizeof(struct __sanitizer_sigset_t)); | ||
| 3196 | } | ||
| 3197 | } | ||
| 3198 | POST_SYSCALL(__pselect50) | ||
| 3199 | (long long res, long long nd_, void *in_, void *ou_, void *ex_, void *ts_, | ||
| 3200 | void *mask_) {} | ||
| 3201 | PRE_SYSCALL(__pollts50)(void *fds_, long long nfds_, void *ts_, void *mask_) { | ||
| 3202 | if (ts_) { | ||
| 3203 | PRE_READ(ts_, struct_timespec_sz); | ||
| 3204 | } | ||
| 3205 | if (mask_) { | ||
| 3206 | PRE_READ(mask_, sizeof(struct __sanitizer_sigset_t)); | ||
| 3207 | } | ||
| 3208 | } | ||
| 3209 | POST_SYSCALL(__pollts50) | ||
| 3210 | (long long res, void *fds_, long long nfds_, void *ts_, void *mask_) {} | ||
| 3211 | PRE_SYSCALL(__aio_suspend50)(void *list_, long long nent_, void *timeout_) { | ||
| 3212 | int i; | ||
| 3213 | const struct aiocb *const *list = (const struct aiocb *const *)list_; | ||
| 3214 | if (list) { | ||
| 3215 | for (i = 0; i < nent_; i++) { | ||
| 3216 | if (list[i]) { | ||
| 3217 | PRE_READ(list[i], sizeof(struct __sanitizer_aiocb)); | ||
| 3218 | } | ||
| 3219 | } | ||
| 3220 | } | ||
| 3221 | if (timeout_) { | ||
| 3222 | PRE_READ(timeout_, struct_timespec_sz); | ||
| 3223 | } | ||
| 3224 | } | ||
| 3225 | POST_SYSCALL(__aio_suspend50) | ||
| 3226 | (long long res, void *list_, long long nent_, void *timeout_) {} | ||
| 3227 | PRE_SYSCALL(__stat50)(void *path_, void *ub_) { | ||
| 3228 | const char *path = (const char *)path_; | ||
| 3229 | if (path) { | ||
| 3230 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3231 | } | ||
| 3232 | } | ||
| 3233 | POST_SYSCALL(__stat50)(long long res, void *path_, void *ub_) { | ||
| 3234 | const char *path = (const char *)path_; | ||
| 3235 | if (res == 0) { | ||
| 3236 | if (path) { | ||
| 3237 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3238 | } | ||
| 3239 | } | ||
| 3240 | } | ||
| 3241 | PRE_SYSCALL(__fstat50)(long long fd_, void *sb_) { /* Nothing to do */ } | ||
| 3242 | POST_SYSCALL(__fstat50)(long long res, long long fd_, void *sb_) { | ||
| 3243 | /* Nothing to do */ | ||
| 3244 | } | ||
| 3245 | PRE_SYSCALL(__lstat50)(void *path_, void *ub_) { | ||
| 3246 | const char *path = (const char *)path_; | ||
| 3247 | if (path) { | ||
| 3248 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3249 | } | ||
| 3250 | } | ||
| 3251 | POST_SYSCALL(__lstat50)(long long res, void *path_, void *ub_) { | ||
| 3252 | const char *path = (const char *)path_; | ||
| 3253 | if (res == 0) { | ||
| 3254 | if (path) { | ||
| 3255 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3256 | } | ||
| 3257 | } | ||
| 3258 | } | ||
| 3259 | PRE_SYSCALL(____semctl50) | ||
| 3260 | (long long semid_, long long semnum_, long long cmd_, void *arg_) { | ||
| 3261 | /* Nothing to do */ | ||
| 3262 | } | ||
| 3263 | POST_SYSCALL(____semctl50) | ||
| 3264 | (long long res, long long semid_, long long semnum_, long long cmd_, | ||
| 3265 | void *arg_) { | ||
| 3266 | /* Nothing to do */ | ||
| 3267 | } | ||
| 3268 | PRE_SYSCALL(__shmctl50)(long long shmid_, long long cmd_, void *buf_) { | ||
| 3269 | /* Nothing to do */ | ||
| 3270 | } | ||
| 3271 | POST_SYSCALL(__shmctl50) | ||
| 3272 | (long long res, long long shmid_, long long cmd_, void *buf_) { | ||
| 3273 | /* Nothing to do */ | ||
| 3274 | } | ||
| 3275 | PRE_SYSCALL(__msgctl50)(long long msqid_, long long cmd_, void *buf_) { | ||
| 3276 | /* Nothing to do */ | ||
| 3277 | } | ||
| 3278 | POST_SYSCALL(__msgctl50) | ||
| 3279 | (long long res, long long msqid_, long long cmd_, void *buf_) { | ||
| 3280 | /* Nothing to do */ | ||
| 3281 | } | ||
| 3282 | PRE_SYSCALL(__getrusage50)(long long who_, void *rusage_) { | ||
| 3283 | /* Nothing to do */ | ||
| 3284 | } | ||
| 3285 | POST_SYSCALL(__getrusage50)(long long res, long long who_, void *rusage_) { | ||
| 3286 | /* Nothing to do */ | ||
| 3287 | } | ||
| 3288 | PRE_SYSCALL(__timer_settime50) | ||
| 3289 | (long long timerid_, long long flags_, void *value_, void *ovalue_) { | ||
| 3290 | struct __sanitizer_itimerval *value = (struct __sanitizer_itimerval *)value_; | ||
| 3291 | if (value) { | ||
| 3292 | PRE_READ(&value->it_interval.tv_sec, sizeof(__sanitizer_time_t)); | ||
| 3293 | PRE_READ(&value->it_interval.tv_usec, sizeof(__sanitizer_suseconds_t)); | ||
| 3294 | PRE_READ(&value->it_value.tv_sec, sizeof(__sanitizer_time_t)); | ||
| 3295 | PRE_READ(&value->it_value.tv_usec, sizeof(__sanitizer_suseconds_t)); | ||
| 3296 | } | ||
| 3297 | } | ||
| 3298 | POST_SYSCALL(__timer_settime50) | ||
| 3299 | (long long res, long long timerid_, long long flags_, void *value_, | ||
| 3300 | void *ovalue_) { | ||
| 3301 | struct __sanitizer_itimerval *value = (struct __sanitizer_itimerval *)value_; | ||
| 3302 | if (res == 0) { | ||
| 3303 | if (value) { | ||
| 3304 | POST_READ(&value->it_interval.tv_sec, sizeof(__sanitizer_time_t)); | ||
| 3305 | POST_READ(&value->it_interval.tv_usec, sizeof(__sanitizer_suseconds_t)); | ||
| 3306 | POST_READ(&value->it_value.tv_sec, sizeof(__sanitizer_time_t)); | ||
| 3307 | POST_READ(&value->it_value.tv_usec, sizeof(__sanitizer_suseconds_t)); | ||
| 3308 | } | ||
| 3309 | } | ||
| 3310 | } | ||
| 3311 | PRE_SYSCALL(__timer_gettime50)(long long timerid_, void *value_) { | ||
| 3312 | /* Nothing to do */ | ||
| 3313 | } | ||
| 3314 | POST_SYSCALL(__timer_gettime50) | ||
| 3315 | (long long res, long long timerid_, void *value_) { | ||
| 3316 | /* Nothing to do */ | ||
| 3317 | } | ||
| 3318 | #if defined(NTP) || !defined(_KERNEL_OPT) | ||
| 3319 | PRE_SYSCALL(__ntp_gettime50)(void *ntvp_) { /* Nothing to do */ } | ||
| 3320 | POST_SYSCALL(__ntp_gettime50)(long long res, void *ntvp_) { | ||
| 3321 | /* Nothing to do */ | ||
| 3322 | } | ||
| 3323 | #else | ||
| 3324 | /* syscall 448 has been skipped */ | ||
| 3325 | #endif | ||
| 3326 | PRE_SYSCALL(__wait450) | ||
| 3327 | (long long pid_, void *status_, long long options_, void *rusage_) { | ||
| 3328 | /* Nothing to do */ | ||
| 3329 | } | ||
| 3330 | POST_SYSCALL(__wait450) | ||
| 3331 | (long long res, long long pid_, void *status_, long long options_, | ||
| 3332 | void *rusage_) { | ||
| 3333 | /* Nothing to do */ | ||
| 3334 | } | ||
| 3335 | PRE_SYSCALL(__mknod50)(void *path_, long long mode_, long long dev_) { | ||
| 3336 | const char *path = (const char *)path_; | ||
| 3337 | if (path) { | ||
| 3338 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3339 | } | ||
| 3340 | } | ||
| 3341 | POST_SYSCALL(__mknod50) | ||
| 3342 | (long long res, void *path_, long long mode_, long long dev_) { | ||
| 3343 | const char *path = (const char *)path_; | ||
| 3344 | if (res == 0) { | ||
| 3345 | if (path) { | ||
| 3346 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3347 | } | ||
| 3348 | } | ||
| 3349 | } | ||
| 3350 | PRE_SYSCALL(__fhstat50)(void *fhp_, long long fh_size_, void *sb_) { | ||
| 3351 | if (fhp_) { | ||
| 3352 | PRE_READ(fhp_, fh_size_); | ||
| 3353 | } | ||
| 3354 | } | ||
| 3355 | POST_SYSCALL(__fhstat50) | ||
| 3356 | (long long res, void *fhp_, long long fh_size_, void *sb_) { | ||
| 3357 | if (res == 0) { | ||
| 3358 | if (fhp_) { | ||
| 3359 | POST_READ(fhp_, fh_size_); | ||
| 3360 | } | ||
| 3361 | } | ||
| 3362 | } | ||
| 3363 | /* syscall 452 has been skipped */ | ||
| 3364 | PRE_SYSCALL(pipe2)(void *fildes_, long long flags_) { /* Nothing to do */ } | ||
| 3365 | POST_SYSCALL(pipe2)(long long res, void *fildes_, long long flags_) { | ||
| 3366 | /* Nothing to do */ | ||
| 3367 | } | ||
| 3368 | PRE_SYSCALL(dup3)(long long from_, long long to_, long long flags_) { | ||
| 3369 | /* Nothing to do */ | ||
| 3370 | } | ||
| 3371 | POST_SYSCALL(dup3) | ||
| 3372 | (long long res, long long from_, long long to_, long long flags_) { | ||
| 3373 | /* Nothing to do */ | ||
| 3374 | } | ||
| 3375 | PRE_SYSCALL(kqueue1)(long long flags_) { /* Nothing to do */ } | ||
| 3376 | POST_SYSCALL(kqueue1)(long long res, long long flags_) { /* Nothing to do */ } | ||
| 3377 | PRE_SYSCALL(paccept) | ||
| 3378 | (long long s_, void *name_, void *anamelen_, void *mask_, long long flags_) { | ||
| 3379 | if (mask_) { | ||
| 3380 | PRE_READ(mask_, sizeof(__sanitizer_sigset_t)); | ||
| 3381 | } | ||
| 3382 | } | ||
| 3383 | POST_SYSCALL(paccept) | ||
| 3384 | (long long res, long long s_, void *name_, void *anamelen_, void *mask_, | ||
| 3385 | long long flags_) { | ||
| 3386 | if (res >= 0) { | ||
| 3387 | if (mask_) { | ||
| 3388 | PRE_READ(mask_, sizeof(__sanitizer_sigset_t)); | ||
| 3389 | } | ||
| 3390 | } | ||
| 3391 | } | ||
| 3392 | PRE_SYSCALL(linkat) | ||
| 3393 | (long long fd1_, void *name1_, long long fd2_, void *name2_, long long flags_) { | ||
| 3394 | const char *name1 = (const char *)name1_; | ||
| 3395 | const char *name2 = (const char *)name2_; | ||
| 3396 | if (name1) { | ||
| 3397 | PRE_READ(name1, __sanitizer::internal_strlen(name1) + 1); | ||
| 3398 | } | ||
| 3399 | if (name2) { | ||
| 3400 | PRE_READ(name2, __sanitizer::internal_strlen(name2) + 1); | ||
| 3401 | } | ||
| 3402 | } | ||
| 3403 | POST_SYSCALL(linkat) | ||
| 3404 | (long long res, long long fd1_, void *name1_, long long fd2_, void *name2_, | ||
| 3405 | long long flags_) { | ||
| 3406 | const char *name1 = (const char *)name1_; | ||
| 3407 | const char *name2 = (const char *)name2_; | ||
| 3408 | if (res == 0) { | ||
| 3409 | if (name1) { | ||
| 3410 | POST_READ(name1, __sanitizer::internal_strlen(name1) + 1); | ||
| 3411 | } | ||
| 3412 | if (name2) { | ||
| 3413 | POST_READ(name2, __sanitizer::internal_strlen(name2) + 1); | ||
| 3414 | } | ||
| 3415 | } | ||
| 3416 | } | ||
| 3417 | PRE_SYSCALL(renameat) | ||
| 3418 | (long long fromfd_, void *from_, long long tofd_, void *to_) { | ||
| 3419 | const char *from = (const char *)from_; | ||
| 3420 | const char *to = (const char *)to_; | ||
| 3421 | if (from) { | ||
| 3422 | PRE_READ(from, __sanitizer::internal_strlen(from) + 1); | ||
| 3423 | } | ||
| 3424 | if (to) { | ||
| 3425 | PRE_READ(to, __sanitizer::internal_strlen(to) + 1); | ||
| 3426 | } | ||
| 3427 | } | ||
| 3428 | POST_SYSCALL(renameat) | ||
| 3429 | (long long res, long long fromfd_, void *from_, long long tofd_, void *to_) { | ||
| 3430 | const char *from = (const char *)from_; | ||
| 3431 | const char *to = (const char *)to_; | ||
| 3432 | if (res == 0) { | ||
| 3433 | if (from) { | ||
| 3434 | POST_READ(from, __sanitizer::internal_strlen(from) + 1); | ||
| 3435 | } | ||
| 3436 | if (to) { | ||
| 3437 | POST_READ(to, __sanitizer::internal_strlen(to) + 1); | ||
| 3438 | } | ||
| 3439 | } | ||
| 3440 | } | ||
| 3441 | PRE_SYSCALL(mkfifoat)(long long fd_, void *path_, long long mode_) { | ||
| 3442 | const char *path = (const char *)path_; | ||
| 3443 | if (path) { | ||
| 3444 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3445 | } | ||
| 3446 | } | ||
| 3447 | POST_SYSCALL(mkfifoat) | ||
| 3448 | (long long res, long long fd_, void *path_, long long mode_) { | ||
| 3449 | const char *path = (const char *)path_; | ||
| 3450 | if (res == 0) { | ||
| 3451 | if (path) { | ||
| 3452 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3453 | } | ||
| 3454 | } | ||
| 3455 | } | ||
| 3456 | PRE_SYSCALL(mknodat) | ||
| 3457 | (long long fd_, void *path_, long long mode_, long long PAD_, long long dev_) { | ||
| 3458 | const char *path = (const char *)path_; | ||
| 3459 | if (path) { | ||
| 3460 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3461 | } | ||
| 3462 | } | ||
| 3463 | POST_SYSCALL(mknodat) | ||
| 3464 | (long long res, long long fd_, void *path_, long long mode_, long long PAD_, | ||
| 3465 | long long dev_) { | ||
| 3466 | const char *path = (const char *)path_; | ||
| 3467 | if (res == 0) { | ||
| 3468 | if (path) { | ||
| 3469 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3470 | } | ||
| 3471 | } | ||
| 3472 | } | ||
| 3473 | PRE_SYSCALL(mkdirat)(long long fd_, void *path_, long long mode_) { | ||
| 3474 | const char *path = (const char *)path_; | ||
| 3475 | if (path) { | ||
| 3476 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3477 | } | ||
| 3478 | } | ||
| 3479 | POST_SYSCALL(mkdirat) | ||
| 3480 | (long long res, long long fd_, void *path_, long long mode_) { | ||
| 3481 | const char *path = (const char *)path_; | ||
| 3482 | if (res == 0) { | ||
| 3483 | if (path) { | ||
| 3484 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3485 | } | ||
| 3486 | } | ||
| 3487 | } | ||
| 3488 | PRE_SYSCALL(faccessat) | ||
| 3489 | (long long fd_, void *path_, long long amode_, long long flag_) { | ||
| 3490 | const char *path = (const char *)path_; | ||
| 3491 | if (path) { | ||
| 3492 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3493 | } | ||
| 3494 | } | ||
| 3495 | POST_SYSCALL(faccessat) | ||
| 3496 | (long long res, long long fd_, void *path_, long long amode_, long long flag_) { | ||
| 3497 | const char *path = (const char *)path_; | ||
| 3498 | if (res == 0) { | ||
| 3499 | if (path) { | ||
| 3500 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3501 | } | ||
| 3502 | } | ||
| 3503 | } | ||
| 3504 | PRE_SYSCALL(fchmodat) | ||
| 3505 | (long long fd_, void *path_, long long mode_, long long flag_) { | ||
| 3506 | const char *path = (const char *)path_; | ||
| 3507 | if (path) { | ||
| 3508 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3509 | } | ||
| 3510 | } | ||
| 3511 | POST_SYSCALL(fchmodat) | ||
| 3512 | (long long res, long long fd_, void *path_, long long mode_, long long flag_) { | ||
| 3513 | const char *path = (const char *)path_; | ||
| 3514 | if (res == 0) { | ||
| 3515 | if (path) { | ||
| 3516 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3517 | } | ||
| 3518 | } | ||
| 3519 | } | ||
| 3520 | PRE_SYSCALL(fchownat) | ||
| 3521 | (long long fd_, void *path_, long long owner_, long long group_, | ||
| 3522 | long long flag_) { | ||
| 3523 | const char *path = (const char *)path_; | ||
| 3524 | if (path) { | ||
| 3525 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3526 | } | ||
| 3527 | } | ||
| 3528 | POST_SYSCALL(fchownat) | ||
| 3529 | (long long res, long long fd_, void *path_, long long owner_, long long group_, | ||
| 3530 | long long flag_) { | ||
| 3531 | const char *path = (const char *)path_; | ||
| 3532 | if (res == 0) { | ||
| 3533 | if (path) { | ||
| 3534 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3535 | } | ||
| 3536 | } | ||
| 3537 | } | ||
| 3538 | PRE_SYSCALL(fexecve)(long long fd_, void *argp_, void *envp_) { /* TODO */ } | ||
| 3539 | POST_SYSCALL(fexecve)(long long res, long long fd_, void *argp_, void *envp_) { | ||
| 3540 | /* TODO */ | ||
| 3541 | } | ||
| 3542 | PRE_SYSCALL(fstatat)(long long fd_, void *path_, void *buf_, long long flag_) { | ||
| 3543 | const char *path = (const char *)path_; | ||
| 3544 | if (path) { | ||
| 3545 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3546 | } | ||
| 3547 | } | ||
| 3548 | POST_SYSCALL(fstatat) | ||
| 3549 | (long long res, long long fd_, void *path_, void *buf_, long long flag_) { | ||
| 3550 | const char *path = (const char *)path_; | ||
| 3551 | if (path) { | ||
| 3552 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3553 | } | ||
| 3554 | } | ||
| 3555 | PRE_SYSCALL(utimensat) | ||
| 3556 | (long long fd_, void *path_, void *tptr_, long long flag_) { | ||
| 3557 | const char *path = (const char *)path_; | ||
| 3558 | if (path) { | ||
| 3559 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3560 | } | ||
| 3561 | if (tptr_) { | ||
| 3562 | PRE_READ(tptr_, struct_timespec_sz); | ||
| 3563 | } | ||
| 3564 | } | ||
| 3565 | POST_SYSCALL(utimensat) | ||
| 3566 | (long long res, long long fd_, void *path_, void *tptr_, long long flag_) { | ||
| 3567 | const char *path = (const char *)path_; | ||
| 3568 | if (res > 0) { | ||
| 3569 | if (path) { | ||
| 3570 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3571 | } | ||
| 3572 | if (tptr_) { | ||
| 3573 | POST_READ(tptr_, struct_timespec_sz); | ||
| 3574 | } | ||
| 3575 | } | ||
| 3576 | } | ||
| 3577 | PRE_SYSCALL(openat) | ||
| 3578 | (long long fd_, void *path_, long long oflags_, long long mode_) { | ||
| 3579 | const char *path = (const char *)path_; | ||
| 3580 | if (path) { | ||
| 3581 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3582 | } | ||
| 3583 | } | ||
| 3584 | POST_SYSCALL(openat) | ||
| 3585 | (long long res, long long fd_, void *path_, long long oflags_, | ||
| 3586 | long long mode_) { | ||
| 3587 | const char *path = (const char *)path_; | ||
| 3588 | if (res > 0) { | ||
| 3589 | if (path) { | ||
| 3590 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3591 | } | ||
| 3592 | } | ||
| 3593 | } | ||
| 3594 | PRE_SYSCALL(readlinkat) | ||
| 3595 | (long long fd_, void *path_, void *buf_, long long bufsize_) { | ||
| 3596 | const char *path = (const char *)path_; | ||
| 3597 | if (path) { | ||
| 3598 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3599 | } | ||
| 3600 | } | ||
| 3601 | POST_SYSCALL(readlinkat) | ||
| 3602 | (long long res, long long fd_, void *path_, void *buf_, long long bufsize_) { | ||
| 3603 | const char *path = (const char *)path_; | ||
| 3604 | if (res > 0) { | ||
| 3605 | if (path) { | ||
| 3606 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3607 | } | ||
| 3608 | } | ||
| 3609 | } | ||
| 3610 | PRE_SYSCALL(symlinkat)(void *path1_, long long fd_, void *path2_) { | ||
| 3611 | const char *path1 = (const char *)path1_; | ||
| 3612 | const char *path2 = (const char *)path2_; | ||
| 3613 | if (path1) { | ||
| 3614 | PRE_READ(path1, __sanitizer::internal_strlen(path1) + 1); | ||
| 3615 | } | ||
| 3616 | if (path2) { | ||
| 3617 | PRE_READ(path2, __sanitizer::internal_strlen(path2) + 1); | ||
| 3618 | } | ||
| 3619 | } | ||
| 3620 | POST_SYSCALL(symlinkat) | ||
| 3621 | (long long res, void *path1_, long long fd_, void *path2_) { | ||
| 3622 | const char *path1 = (const char *)path1_; | ||
| 3623 | const char *path2 = (const char *)path2_; | ||
| 3624 | if (res == 0) { | ||
| 3625 | if (path1) { | ||
| 3626 | POST_READ(path1, __sanitizer::internal_strlen(path1) + 1); | ||
| 3627 | } | ||
| 3628 | if (path2) { | ||
| 3629 | POST_READ(path2, __sanitizer::internal_strlen(path2) + 1); | ||
| 3630 | } | ||
| 3631 | } | ||
| 3632 | } | ||
| 3633 | PRE_SYSCALL(unlinkat)(long long fd_, void *path_, long long flag_) { | ||
| 3634 | const char *path = (const char *)path_; | ||
| 3635 | if (path) { | ||
| 3636 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3637 | } | ||
| 3638 | } | ||
| 3639 | POST_SYSCALL(unlinkat) | ||
| 3640 | (long long res, long long fd_, void *path_, long long flag_) { | ||
| 3641 | const char *path = (const char *)path_; | ||
| 3642 | if (res == 0) { | ||
| 3643 | if (path) { | ||
| 3644 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3645 | } | ||
| 3646 | } | ||
| 3647 | } | ||
| 3648 | PRE_SYSCALL(futimens)(long long fd_, void *tptr_) { | ||
| 3649 | struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; | ||
| 3650 | if (tptr) { | ||
| 3651 | PRE_READ(tptr[0], struct_timespec_sz); | ||
| 3652 | PRE_READ(tptr[1], struct_timespec_sz); | ||
| 3653 | } | ||
| 3654 | } | ||
| 3655 | POST_SYSCALL(futimens)(long long res, long long fd_, void *tptr_) { | ||
| 3656 | struct __sanitizer_timespec **tptr = (struct __sanitizer_timespec **)tptr_; | ||
| 3657 | if (res == 0) { | ||
| 3658 | if (tptr) { | ||
| 3659 | POST_READ(tptr[0], struct_timespec_sz); | ||
| 3660 | POST_READ(tptr[1], struct_timespec_sz); | ||
| 3661 | } | ||
| 3662 | } | ||
| 3663 | } | ||
| 3664 | PRE_SYSCALL(__quotactl)(void *path_, void *args_) { | ||
| 3665 | const char *path = (const char *)path_; | ||
| 3666 | if (path) { | ||
| 3667 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3668 | } | ||
| 3669 | } | ||
| 3670 | POST_SYSCALL(__quotactl)(long long res, void *path_, void *args_) { | ||
| 3671 | const char *path = (const char *)path_; | ||
| 3672 | if (res == 0) { | ||
| 3673 | if (path) { | ||
| 3674 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3675 | } | ||
| 3676 | } | ||
| 3677 | } | ||
| 3678 | PRE_SYSCALL(posix_spawn) | ||
| 3679 | (void *pid_, void *path_, void *file_actions_, void *attrp_, void *argv_, | ||
| 3680 | void *envp_) { | ||
| 3681 | const char *path = (const char *)path_; | ||
| 3682 | if (path) { | ||
| 3683 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3684 | } | ||
| 3685 | } | ||
| 3686 | POST_SYSCALL(posix_spawn) | ||
| 3687 | (long long res, void *pid_, void *path_, void *file_actions_, void *attrp_, | ||
| 3688 | void *argv_, void *envp_) { | ||
| 3689 | const char *path = (const char *)path_; | ||
| 3690 | if (pid_) { | ||
| 3691 | if (path) { | ||
| 3692 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3693 | } | ||
| 3694 | } | ||
| 3695 | } | ||
| 3696 | PRE_SYSCALL(recvmmsg) | ||
| 3697 | (long long s_, void *mmsg_, long long vlen_, long long flags_, void *timeout_) { | ||
| 3698 | if (timeout_) { | ||
| 3699 | PRE_READ(timeout_, struct_timespec_sz); | ||
| 3700 | } | ||
| 3701 | } | ||
| 3702 | POST_SYSCALL(recvmmsg) | ||
| 3703 | (long long res, long long s_, void *mmsg_, long long vlen_, long long flags_, | ||
| 3704 | void *timeout_) { | ||
| 3705 | if (res >= 0) { | ||
| 3706 | if (timeout_) { | ||
| 3707 | POST_READ(timeout_, struct_timespec_sz); | ||
| 3708 | } | ||
| 3709 | } | ||
| 3710 | } | ||
| 3711 | PRE_SYSCALL(sendmmsg) | ||
| 3712 | (long long s_, void *mmsg_, long long vlen_, long long flags_) { | ||
| 3713 | struct __sanitizer_mmsghdr *mmsg = (struct __sanitizer_mmsghdr *)mmsg_; | ||
| 3714 | if (mmsg) { | ||
| 3715 | PRE_READ(mmsg, sizeof(struct __sanitizer_mmsghdr) * | ||
| 3716 | (vlen_ > 1024 ? 1024 : vlen_)); | ||
| 3717 | } | ||
| 3718 | } | ||
| 3719 | POST_SYSCALL(sendmmsg) | ||
| 3720 | (long long res, long long s_, void *mmsg_, long long vlen_, long long flags_) { | ||
| 3721 | struct __sanitizer_mmsghdr *mmsg = (struct __sanitizer_mmsghdr *)mmsg_; | ||
| 3722 | if (res >= 0) { | ||
| 3723 | if (mmsg) { | ||
| 3724 | POST_READ(mmsg, sizeof(struct __sanitizer_mmsghdr) * | ||
| 3725 | (vlen_ > 1024 ? 1024 : vlen_)); | ||
| 3726 | } | ||
| 3727 | } | ||
| 3728 | } | ||
| 3729 | PRE_SYSCALL(clock_nanosleep) | ||
| 3730 | (long long clock_id_, long long flags_, void *rqtp_, void *rmtp_) { | ||
| 3731 | if (rqtp_) { | ||
| 3732 | PRE_READ(rqtp_, struct_timespec_sz); | ||
| 3733 | } | ||
| 3734 | } | ||
| 3735 | POST_SYSCALL(clock_nanosleep) | ||
| 3736 | (long long res, long long clock_id_, long long flags_, void *rqtp_, | ||
| 3737 | void *rmtp_) { | ||
| 3738 | if (rqtp_) { | ||
| 3739 | POST_READ(rqtp_, struct_timespec_sz); | ||
| 3740 | } | ||
| 3741 | } | ||
| 3742 | PRE_SYSCALL(___lwp_park60) | ||
| 3743 | (long long clock_id_, long long flags_, void *ts_, long long unpark_, | ||
| 3744 | void *hint_, void *unparkhint_) { | ||
| 3745 | if (ts_) { | ||
| 3746 | PRE_READ(ts_, struct_timespec_sz); | ||
| 3747 | } | ||
| 3748 | } | ||
| 3749 | POST_SYSCALL(___lwp_park60) | ||
| 3750 | (long long res, long long clock_id_, long long flags_, void *ts_, | ||
| 3751 | long long unpark_, void *hint_, void *unparkhint_) { | ||
| 3752 | if (res == 0) { | ||
| 3753 | if (ts_) { | ||
| 3754 | POST_READ(ts_, struct_timespec_sz); | ||
| 3755 | } | ||
| 3756 | } | ||
| 3757 | } | ||
| 3758 | PRE_SYSCALL(posix_fallocate) | ||
| 3759 | (long long fd_, long long PAD_, long long pos_, long long len_) { | ||
| 3760 | /* Nothing to do */ | ||
| 3761 | } | ||
| 3762 | POST_SYSCALL(posix_fallocate) | ||
| 3763 | (long long res, long long fd_, long long PAD_, long long pos_, long long len_) { | ||
| 3764 | /* Nothing to do */ | ||
| 3765 | } | ||
| 3766 | PRE_SYSCALL(fdiscard) | ||
| 3767 | (long long fd_, long long PAD_, long long pos_, long long len_) { | ||
| 3768 | /* Nothing to do */ | ||
| 3769 | } | ||
| 3770 | POST_SYSCALL(fdiscard) | ||
| 3771 | (long long res, long long fd_, long long PAD_, long long pos_, long long len_) { | ||
| 3772 | /* Nothing to do */ | ||
| 3773 | } | ||
| 3774 | PRE_SYSCALL(wait6) | ||
| 3775 | (long long idtype_, long long id_, void *status_, long long options_, | ||
| 3776 | void *wru_, void *info_) { | ||
| 3777 | /* Nothing to do */ | ||
| 3778 | } | ||
| 3779 | POST_SYSCALL(wait6) | ||
| 3780 | (long long res, long long idtype_, long long id_, void *status_, | ||
| 3781 | long long options_, void *wru_, void *info_) { | ||
| 3782 | /* Nothing to do */ | ||
| 3783 | } | ||
| 3784 | PRE_SYSCALL(clock_getcpuclockid2) | ||
| 3785 | (long long idtype_, long long id_, void *clock_id_) { | ||
| 3786 | /* Nothing to do */ | ||
| 3787 | } | ||
| 3788 | POST_SYSCALL(clock_getcpuclockid2) | ||
| 3789 | (long long res, long long idtype_, long long id_, void *clock_id_) { | ||
| 3790 | /* Nothing to do */ | ||
| 3791 | } | ||
| 3792 | PRE_SYSCALL(__getvfsstat90)(void *buf_, long long bufsize_, long long flags_) { | ||
| 3793 | /* Nothing to do */ | ||
| 3794 | } | ||
| 3795 | POST_SYSCALL(__getvfsstat90) | ||
| 3796 | (long long res, void *buf_, long long bufsize_, long long flags_) { | ||
| 3797 | /* Nothing to do */ | ||
| 3798 | } | ||
| 3799 | PRE_SYSCALL(__statvfs190)(void *path_, void *buf_, long long flags_) { | ||
| 3800 | const char *path = (const char *)path_; | ||
| 3801 | if (path) { | ||
| 3802 | PRE_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3803 | } | ||
| 3804 | } | ||
| 3805 | POST_SYSCALL(__statvfs190) | ||
| 3806 | (long long res, void *path_, void *buf_, long long flags_) { | ||
| 3807 | const char *path = (const char *)path_; | ||
| 3808 | if (path) { | ||
| 3809 | POST_READ(path, __sanitizer::internal_strlen(path) + 1); | ||
| 3810 | } | ||
| 3811 | } | ||
| 3812 | PRE_SYSCALL(__fstatvfs190)(long long fd_, void *buf_, long long flags_) { | ||
| 3813 | /* Nothing to do */ | ||
| 3814 | } | ||
| 3815 | POST_SYSCALL(__fstatvfs190) | ||
| 3816 | (long long res, long long fd_, void *buf_, long long flags_) { | ||
| 3817 | /* Nothing to do */ | ||
| 3818 | } | ||
| 3819 | PRE_SYSCALL(__fhstatvfs190) | ||
| 3820 | (void *fhp_, long long fh_size_, void *buf_, long long flags_) { | ||
| 3821 | if (fhp_) { | ||
| 3822 | PRE_READ(fhp_, fh_size_); | ||
| 3823 | } | ||
| 3824 | } | ||
| 3825 | POST_SYSCALL(__fhstatvfs190) | ||
| 3826 | (long long res, void *fhp_, long long fh_size_, void *buf_, long long flags_) {} | ||
| 3827 | #undef SYS_MAXSYSARGS | ||
| 3828 | } // extern "C" | ||
| 3829 | |||
| 3830 | #undef PRE_SYSCALL | ||
| 3831 | #undef PRE_READ | ||
| 3832 | #undef PRE_WRITE | ||
| 3833 | #undef POST_SYSCALL | ||
| 3834 | #undef POST_READ | ||
| 3835 | #undef POST_WRITE | ||
| 3836 | |||
| 3837 | #endif // SANITIZER_NETBSD | ||
lib/tsan/sanitizer_common/sanitizer_termination.cpp created+94| ... | @@ -0,0 +1,94 @@ | ||
| 1 | //===-- sanitizer_termination.cpp -------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | /// | ||
| 9 | /// This file contains the Sanitizer termination functions CheckFailed and Die, | ||
| 10 | /// and the callback functionalities associated with them. | ||
| 11 | /// | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_common.h" | ||
| 15 | #include "sanitizer_libc.h" | ||
| 16 | |||
| 17 | namespace __sanitizer { | ||
| 18 | |||
| 19 | static const int kMaxNumOfInternalDieCallbacks = 5; | ||
| 20 | static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks]; | ||
| 21 | |||
| 22 | bool AddDieCallback(DieCallbackType callback) { | ||
| 23 | for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) { | ||
| 24 | if (InternalDieCallbacks[i] == nullptr) { | ||
| 25 | InternalDieCallbacks[i] = callback; | ||
| 26 | return true; | ||
| 27 | } | ||
| 28 | } | ||
| 29 | return false; | ||
| 30 | } | ||
| 31 | |||
| 32 | bool RemoveDieCallback(DieCallbackType callback) { | ||
| 33 | for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) { | ||
| 34 | if (InternalDieCallbacks[i] == callback) { | ||
| 35 | internal_memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1], | ||
| 36 | sizeof(InternalDieCallbacks[0]) * | ||
| 37 | (kMaxNumOfInternalDieCallbacks - i - 1)); | ||
| 38 | InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr; | ||
| 39 | return true; | ||
| 40 | } | ||
| 41 | } | ||
| 42 | return false; | ||
| 43 | } | ||
| 44 | |||
| 45 | static DieCallbackType UserDieCallback; | ||
| 46 | void SetUserDieCallback(DieCallbackType callback) { | ||
| 47 | UserDieCallback = callback; | ||
| 48 | } | ||
| 49 | |||
| 50 | void NORETURN Die() { | ||
| 51 | if (UserDieCallback) | ||
| 52 | UserDieCallback(); | ||
| 53 | for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) { | ||
| 54 | if (InternalDieCallbacks[i]) | ||
| 55 | InternalDieCallbacks[i](); | ||
| 56 | } | ||
| 57 | if (common_flags()->abort_on_error) | ||
| 58 | Abort(); | ||
| 59 | internal__exit(common_flags()->exitcode); | ||
| 60 | } | ||
| 61 | |||
| 62 | static CheckFailedCallbackType CheckFailedCallback; | ||
| 63 | void SetCheckFailedCallback(CheckFailedCallbackType callback) { | ||
| 64 | CheckFailedCallback = callback; | ||
| 65 | } | ||
| 66 | |||
| 67 | const int kSecondsToSleepWhenRecursiveCheckFailed = 2; | ||
| 68 | |||
| 69 | void NORETURN CheckFailed(const char *file, int line, const char *cond, | ||
| 70 | u64 v1, u64 v2) { | ||
| 71 | static atomic_uint32_t num_calls; | ||
| 72 | if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) > 10) { | ||
| 73 | SleepForSeconds(kSecondsToSleepWhenRecursiveCheckFailed); | ||
| 74 | Trap(); | ||
| 75 | } | ||
| 76 | |||
| 77 | if (CheckFailedCallback) { | ||
| 78 | CheckFailedCallback(file, line, cond, v1, v2); | ||
| 79 | } | ||
| 80 | Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond, | ||
| 81 | v1, v2); | ||
| 82 | Die(); | ||
| 83 | } | ||
| 84 | |||
| 85 | } // namespace __sanitizer | ||
| 86 | |||
| 87 | using namespace __sanitizer; | ||
| 88 | |||
| 89 | extern "C" { | ||
| 90 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 91 | void __sanitizer_set_death_callback(void (*callback)(void)) { | ||
| 92 | SetUserDieCallback(callback); | ||
| 93 | } | ||
| 94 | } // extern "C" | ||
lib/tsan/sanitizer_common/sanitizer_thread_registry.cpp created+351| ... | @@ -0,0 +1,351 @@ | ||
| 1 | //===-- sanitizer_thread_registry.cpp -------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between sanitizer tools. | ||
| 10 | // | ||
| 11 | // General thread bookkeeping functionality. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_thread_registry.h" | ||
| 15 | |||
| 16 | namespace __sanitizer { | ||
| 17 | |||
| 18 | ThreadContextBase::ThreadContextBase(u32 tid) | ||
| 19 | : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0), | ||
| 20 | status(ThreadStatusInvalid), detached(false), | ||
| 21 | thread_type(ThreadType::Regular), parent_tid(0), next(0) { | ||
| 22 | name[0] = '\0'; | ||
| 23 | atomic_store(&thread_destroyed, 0, memory_order_release); | ||
| 24 | } | ||
| 25 | |||
| 26 | ThreadContextBase::~ThreadContextBase() { | ||
| 27 | // ThreadContextBase should never be deleted. | ||
| 28 | CHECK(0); | ||
| 29 | } | ||
| 30 | |||
| 31 | void ThreadContextBase::SetName(const char *new_name) { | ||
| 32 | name[0] = '\0'; | ||
| 33 | if (new_name) { | ||
| 34 | internal_strncpy(name, new_name, sizeof(name)); | ||
| 35 | name[sizeof(name) - 1] = '\0'; | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | void ThreadContextBase::SetDead() { | ||
| 40 | CHECK(status == ThreadStatusRunning || | ||
| 41 | status == ThreadStatusFinished); | ||
| 42 | status = ThreadStatusDead; | ||
| 43 | user_id = 0; | ||
| 44 | OnDead(); | ||
| 45 | } | ||
| 46 | |||
| 47 | void ThreadContextBase::SetDestroyed() { | ||
| 48 | atomic_store(&thread_destroyed, 1, memory_order_release); | ||
| 49 | } | ||
| 50 | |||
| 51 | bool ThreadContextBase::GetDestroyed() { | ||
| 52 | return !!atomic_load(&thread_destroyed, memory_order_acquire); | ||
| 53 | } | ||
| 54 | |||
| 55 | void ThreadContextBase::SetJoined(void *arg) { | ||
| 56 | // FIXME(dvyukov): print message and continue (it's user error). | ||
| 57 | CHECK_EQ(false, detached); | ||
| 58 | CHECK_EQ(ThreadStatusFinished, status); | ||
| 59 | status = ThreadStatusDead; | ||
| 60 | user_id = 0; | ||
| 61 | OnJoined(arg); | ||
| 62 | } | ||
| 63 | |||
| 64 | void ThreadContextBase::SetFinished() { | ||
| 65 | // ThreadRegistry::FinishThread calls here in ThreadStatusCreated state | ||
| 66 | // for a thread that never actually started. In that case the thread | ||
| 67 | // should go to ThreadStatusFinished regardless of whether it was created | ||
| 68 | // as detached. | ||
| 69 | if (!detached || status == ThreadStatusCreated) status = ThreadStatusFinished; | ||
| 70 | OnFinished(); | ||
| 71 | } | ||
| 72 | |||
| 73 | void ThreadContextBase::SetStarted(tid_t _os_id, ThreadType _thread_type, | ||
| 74 | void *arg) { | ||
| 75 | status = ThreadStatusRunning; | ||
| 76 | os_id = _os_id; | ||
| 77 | thread_type = _thread_type; | ||
| 78 | OnStarted(arg); | ||
| 79 | } | ||
| 80 | |||
| 81 | void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id, | ||
| 82 | bool _detached, u32 _parent_tid, void *arg) { | ||
| 83 | status = ThreadStatusCreated; | ||
| 84 | user_id = _user_id; | ||
| 85 | unique_id = _unique_id; | ||
| 86 | detached = _detached; | ||
| 87 | // Parent tid makes no sense for the main thread. | ||
| 88 | if (tid != 0) | ||
| 89 | parent_tid = _parent_tid; | ||
| 90 | OnCreated(arg); | ||
| 91 | } | ||
| 92 | |||
| 93 | void ThreadContextBase::Reset() { | ||
| 94 | status = ThreadStatusInvalid; | ||
| 95 | SetName(0); | ||
| 96 | atomic_store(&thread_destroyed, 0, memory_order_release); | ||
| 97 | OnReset(); | ||
| 98 | } | ||
| 99 | |||
| 100 | // ThreadRegistry implementation. | ||
| 101 | |||
| 102 | const u32 ThreadRegistry::kUnknownTid = ~0U; | ||
| 103 | |||
| 104 | ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads, | ||
| 105 | u32 thread_quarantine_size, u32 max_reuse) | ||
| 106 | : context_factory_(factory), | ||
| 107 | max_threads_(max_threads), | ||
| 108 | thread_quarantine_size_(thread_quarantine_size), | ||
| 109 | max_reuse_(max_reuse), | ||
| 110 | mtx_(), | ||
| 111 | n_contexts_(0), | ||
| 112 | total_threads_(0), | ||
| 113 | alive_threads_(0), | ||
| 114 | max_alive_threads_(0), | ||
| 115 | running_threads_(0) { | ||
| 116 | threads_ = (ThreadContextBase **)MmapOrDie(max_threads_ * sizeof(threads_[0]), | ||
| 117 | "ThreadRegistry"); | ||
| 118 | dead_threads_.clear(); | ||
| 119 | invalid_threads_.clear(); | ||
| 120 | } | ||
| 121 | |||
| 122 | void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running, | ||
| 123 | uptr *alive) { | ||
| 124 | BlockingMutexLock l(&mtx_); | ||
| 125 | if (total) *total = n_contexts_; | ||
| 126 | if (running) *running = running_threads_; | ||
| 127 | if (alive) *alive = alive_threads_; | ||
| 128 | } | ||
| 129 | |||
| 130 | uptr ThreadRegistry::GetMaxAliveThreads() { | ||
| 131 | BlockingMutexLock l(&mtx_); | ||
| 132 | return max_alive_threads_; | ||
| 133 | } | ||
| 134 | |||
| 135 | u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid, | ||
| 136 | void *arg) { | ||
| 137 | BlockingMutexLock l(&mtx_); | ||
| 138 | u32 tid = kUnknownTid; | ||
| 139 | ThreadContextBase *tctx = QuarantinePop(); | ||
| 140 | if (tctx) { | ||
| 141 | tid = tctx->tid; | ||
| 142 | } else if (n_contexts_ < max_threads_) { | ||
| 143 | // Allocate new thread context and tid. | ||
| 144 | tid = n_contexts_++; | ||
| 145 | tctx = context_factory_(tid); | ||
| 146 | threads_[tid] = tctx; | ||
| 147 | } else { | ||
| 148 | #if !SANITIZER_GO | ||
| 149 | Report("%s: Thread limit (%u threads) exceeded. Dying.\n", | ||
| 150 | SanitizerToolName, max_threads_); | ||
| 151 | #else | ||
| 152 | Printf("race: limit on %u simultaneously alive goroutines is exceeded," | ||
| 153 | " dying\n", max_threads_); | ||
| 154 | #endif | ||
| 155 | Die(); | ||
| 156 | } | ||
| 157 | CHECK_NE(tctx, 0); | ||
| 158 | CHECK_NE(tid, kUnknownTid); | ||
| 159 | CHECK_LT(tid, max_threads_); | ||
| 160 | CHECK_EQ(tctx->status, ThreadStatusInvalid); | ||
| 161 | alive_threads_++; | ||
| 162 | if (max_alive_threads_ < alive_threads_) { | ||
| 163 | max_alive_threads_++; | ||
| 164 | CHECK_EQ(alive_threads_, max_alive_threads_); | ||
| 165 | } | ||
| 166 | tctx->SetCreated(user_id, total_threads_++, detached, | ||
| 167 | parent_tid, arg); | ||
| 168 | return tid; | ||
| 169 | } | ||
| 170 | |||
| 171 | void ThreadRegistry::RunCallbackForEachThreadLocked(ThreadCallback cb, | ||
| 172 | void *arg) { | ||
| 173 | CheckLocked(); | ||
| 174 | for (u32 tid = 0; tid < n_contexts_; tid++) { | ||
| 175 | ThreadContextBase *tctx = threads_[tid]; | ||
| 176 | if (tctx == 0) | ||
| 177 | continue; | ||
| 178 | cb(tctx, arg); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 182 | u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) { | ||
| 183 | BlockingMutexLock l(&mtx_); | ||
| 184 | for (u32 tid = 0; tid < n_contexts_; tid++) { | ||
| 185 | ThreadContextBase *tctx = threads_[tid]; | ||
| 186 | if (tctx != 0 && cb(tctx, arg)) | ||
| 187 | return tctx->tid; | ||
| 188 | } | ||
| 189 | return kUnknownTid; | ||
| 190 | } | ||
| 191 | |||
| 192 | ThreadContextBase * | ||
| 193 | ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) { | ||
| 194 | CheckLocked(); | ||
| 195 | for (u32 tid = 0; tid < n_contexts_; tid++) { | ||
| 196 | ThreadContextBase *tctx = threads_[tid]; | ||
| 197 | if (tctx != 0 && cb(tctx, arg)) | ||
| 198 | return tctx; | ||
| 199 | } | ||
| 200 | return 0; | ||
| 201 | } | ||
| 202 | |||
| 203 | static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx, | ||
| 204 | void *arg) { | ||
| 205 | return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid && | ||
| 206 | tctx->status != ThreadStatusDead); | ||
| 207 | } | ||
| 208 | |||
| 209 | ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id) { | ||
| 210 | return FindThreadContextLocked(FindThreadContextByOsIdCallback, | ||
| 211 | (void *)os_id); | ||
| 212 | } | ||
| 213 | |||
| 214 | void ThreadRegistry::SetThreadName(u32 tid, const char *name) { | ||
| 215 | BlockingMutexLock l(&mtx_); | ||
| 216 | CHECK_LT(tid, n_contexts_); | ||
| 217 | ThreadContextBase *tctx = threads_[tid]; | ||
| 218 | CHECK_NE(tctx, 0); | ||
| 219 | CHECK_EQ(SANITIZER_FUCHSIA ? ThreadStatusCreated : ThreadStatusRunning, | ||
| 220 | tctx->status); | ||
| 221 | tctx->SetName(name); | ||
| 222 | } | ||
| 223 | |||
| 224 | void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) { | ||
| 225 | BlockingMutexLock l(&mtx_); | ||
| 226 | for (u32 tid = 0; tid < n_contexts_; tid++) { | ||
| 227 | ThreadContextBase *tctx = threads_[tid]; | ||
| 228 | if (tctx != 0 && tctx->user_id == user_id && | ||
| 229 | tctx->status != ThreadStatusInvalid) { | ||
| 230 | tctx->SetName(name); | ||
| 231 | return; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | void ThreadRegistry::DetachThread(u32 tid, void *arg) { | ||
| 237 | BlockingMutexLock l(&mtx_); | ||
| 238 | CHECK_LT(tid, n_contexts_); | ||
| 239 | ThreadContextBase *tctx = threads_[tid]; | ||
| 240 | CHECK_NE(tctx, 0); | ||
| 241 | if (tctx->status == ThreadStatusInvalid) { | ||
| 242 | Report("%s: Detach of non-existent thread\n", SanitizerToolName); | ||
| 243 | return; | ||
| 244 | } | ||
| 245 | tctx->OnDetached(arg); | ||
| 246 | if (tctx->status == ThreadStatusFinished) { | ||
| 247 | tctx->SetDead(); | ||
| 248 | QuarantinePush(tctx); | ||
| 249 | } else { | ||
| 250 | tctx->detached = true; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | void ThreadRegistry::JoinThread(u32 tid, void *arg) { | ||
| 255 | bool destroyed = false; | ||
| 256 | do { | ||
| 257 | { | ||
| 258 | BlockingMutexLock l(&mtx_); | ||
| 259 | CHECK_LT(tid, n_contexts_); | ||
| 260 | ThreadContextBase *tctx = threads_[tid]; | ||
| 261 | CHECK_NE(tctx, 0); | ||
| 262 | if (tctx->status == ThreadStatusInvalid) { | ||
| 263 | Report("%s: Join of non-existent thread\n", SanitizerToolName); | ||
| 264 | return; | ||
| 265 | } | ||
| 266 | if ((destroyed = tctx->GetDestroyed())) { | ||
| 267 | tctx->SetJoined(arg); | ||
| 268 | QuarantinePush(tctx); | ||
| 269 | } | ||
| 270 | } | ||
| 271 | if (!destroyed) | ||
| 272 | internal_sched_yield(); | ||
| 273 | } while (!destroyed); | ||
| 274 | } | ||
| 275 | |||
| 276 | // Normally this is called when the thread is about to exit. If | ||
| 277 | // called in ThreadStatusCreated state, then this thread was never | ||
| 278 | // really started. We just did CreateThread for a prospective new | ||
| 279 | // thread before trying to create it, and then failed to actually | ||
| 280 | // create it, and so never called StartThread. | ||
| 281 | void ThreadRegistry::FinishThread(u32 tid) { | ||
| 282 | BlockingMutexLock l(&mtx_); | ||
| 283 | CHECK_GT(alive_threads_, 0); | ||
| 284 | alive_threads_--; | ||
| 285 | CHECK_LT(tid, n_contexts_); | ||
| 286 | ThreadContextBase *tctx = threads_[tid]; | ||
| 287 | CHECK_NE(tctx, 0); | ||
| 288 | bool dead = tctx->detached; | ||
| 289 | if (tctx->status == ThreadStatusRunning) { | ||
| 290 | CHECK_GT(running_threads_, 0); | ||
| 291 | running_threads_--; | ||
| 292 | } else { | ||
| 293 | // The thread never really existed. | ||
| 294 | CHECK_EQ(tctx->status, ThreadStatusCreated); | ||
| 295 | dead = true; | ||
| 296 | } | ||
| 297 | tctx->SetFinished(); | ||
| 298 | if (dead) { | ||
| 299 | tctx->SetDead(); | ||
| 300 | QuarantinePush(tctx); | ||
| 301 | } | ||
| 302 | tctx->SetDestroyed(); | ||
| 303 | } | ||
| 304 | |||
| 305 | void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type, | ||
| 306 | void *arg) { | ||
| 307 | BlockingMutexLock l(&mtx_); | ||
| 308 | running_threads_++; | ||
| 309 | CHECK_LT(tid, n_contexts_); | ||
| 310 | ThreadContextBase *tctx = threads_[tid]; | ||
| 311 | CHECK_NE(tctx, 0); | ||
| 312 | CHECK_EQ(ThreadStatusCreated, tctx->status); | ||
| 313 | tctx->SetStarted(os_id, thread_type, arg); | ||
| 314 | } | ||
| 315 | |||
| 316 | void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) { | ||
| 317 | if (tctx->tid == 0) | ||
| 318 | return; // Don't reuse the main thread. It's a special snowflake. | ||
| 319 | dead_threads_.push_back(tctx); | ||
| 320 | if (dead_threads_.size() <= thread_quarantine_size_) | ||
| 321 | return; | ||
| 322 | tctx = dead_threads_.front(); | ||
| 323 | dead_threads_.pop_front(); | ||
| 324 | CHECK_EQ(tctx->status, ThreadStatusDead); | ||
| 325 | tctx->Reset(); | ||
| 326 | tctx->reuse_count++; | ||
| 327 | if (max_reuse_ > 0 && tctx->reuse_count >= max_reuse_) | ||
| 328 | return; | ||
| 329 | invalid_threads_.push_back(tctx); | ||
| 330 | } | ||
| 331 | |||
| 332 | ThreadContextBase *ThreadRegistry::QuarantinePop() { | ||
| 333 | if (invalid_threads_.size() == 0) | ||
| 334 | return 0; | ||
| 335 | ThreadContextBase *tctx = invalid_threads_.front(); | ||
| 336 | invalid_threads_.pop_front(); | ||
| 337 | return tctx; | ||
| 338 | } | ||
| 339 | |||
| 340 | void ThreadRegistry::SetThreadUserId(u32 tid, uptr user_id) { | ||
| 341 | BlockingMutexLock l(&mtx_); | ||
| 342 | CHECK_LT(tid, n_contexts_); | ||
| 343 | ThreadContextBase *tctx = threads_[tid]; | ||
| 344 | CHECK_NE(tctx, 0); | ||
| 345 | CHECK_NE(tctx->status, ThreadStatusInvalid); | ||
| 346 | CHECK_NE(tctx->status, ThreadStatusDead); | ||
| 347 | CHECK_EQ(tctx->user_id, 0); | ||
| 348 | tctx->user_id = user_id; | ||
| 349 | } | ||
| 350 | |||
| 351 | } // namespace __sanitizer | ||
lib/tsan/sanitizer_common/sanitizer_thread_registry.h created+160| ... | @@ -0,0 +1,160 @@ | ||
| 1 | //===-- sanitizer_thread_registry.h -----------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between sanitizer tools. | ||
| 10 | // | ||
| 11 | // General thread bookkeeping functionality. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef SANITIZER_THREAD_REGISTRY_H | ||
| 15 | #define SANITIZER_THREAD_REGISTRY_H | ||
| 16 | |||
| 17 | #include "sanitizer_common.h" | ||
| 18 | #include "sanitizer_list.h" | ||
| 19 | #include "sanitizer_mutex.h" | ||
| 20 | |||
| 21 | namespace __sanitizer { | ||
| 22 | |||
| 23 | enum ThreadStatus { | ||
| 24 | ThreadStatusInvalid, // Non-existent thread, data is invalid. | ||
| 25 | ThreadStatusCreated, // Created but not yet running. | ||
| 26 | ThreadStatusRunning, // The thread is currently running. | ||
| 27 | ThreadStatusFinished, // Joinable thread is finished but not yet joined. | ||
| 28 | ThreadStatusDead // Joined, but some info is still available. | ||
| 29 | }; | ||
| 30 | |||
| 31 | enum class ThreadType { | ||
| 32 | Regular, // Normal thread | ||
| 33 | Worker, // macOS Grand Central Dispatch (GCD) worker thread | ||
| 34 | Fiber, // Fiber | ||
| 35 | }; | ||
| 36 | |||
| 37 | // Generic thread context. Specific sanitizer tools may inherit from it. | ||
| 38 | // If thread is dead, context may optionally be reused for a new thread. | ||
| 39 | class ThreadContextBase { | ||
| 40 | public: | ||
| 41 | explicit ThreadContextBase(u32 tid); | ||
| 42 | ~ThreadContextBase(); // Should never be called. | ||
| 43 | |||
| 44 | const u32 tid; // Thread ID. Main thread should have tid = 0. | ||
| 45 | u64 unique_id; // Unique thread ID. | ||
| 46 | u32 reuse_count; // Number of times this tid was reused. | ||
| 47 | tid_t os_id; // PID (used for reporting). | ||
| 48 | uptr user_id; // Some opaque user thread id (e.g. pthread_t). | ||
| 49 | char name[64]; // As annotated by user. | ||
| 50 | |||
| 51 | ThreadStatus status; | ||
| 52 | bool detached; | ||
| 53 | ThreadType thread_type; | ||
| 54 | |||
| 55 | u32 parent_tid; | ||
| 56 | ThreadContextBase *next; // For storing thread contexts in a list. | ||
| 57 | |||
| 58 | atomic_uint32_t thread_destroyed; // To address race of Joined vs Finished | ||
| 59 | |||
| 60 | void SetName(const char *new_name); | ||
| 61 | |||
| 62 | void SetDead(); | ||
| 63 | void SetJoined(void *arg); | ||
| 64 | void SetFinished(); | ||
| 65 | void SetStarted(tid_t _os_id, ThreadType _thread_type, void *arg); | ||
| 66 | void SetCreated(uptr _user_id, u64 _unique_id, bool _detached, | ||
| 67 | u32 _parent_tid, void *arg); | ||
| 68 | void Reset(); | ||
| 69 | |||
| 70 | void SetDestroyed(); | ||
| 71 | bool GetDestroyed(); | ||
| 72 | |||
| 73 | // The following methods may be overriden by subclasses. | ||
| 74 | // Some of them take opaque arg that may be optionally be used | ||
| 75 | // by subclasses. | ||
| 76 | virtual void OnDead() {} | ||
| 77 | virtual void OnJoined(void *arg) {} | ||
| 78 | virtual void OnFinished() {} | ||
| 79 | virtual void OnStarted(void *arg) {} | ||
| 80 | virtual void OnCreated(void *arg) {} | ||
| 81 | virtual void OnReset() {} | ||
| 82 | virtual void OnDetached(void *arg) {} | ||
| 83 | }; | ||
| 84 | |||
| 85 | typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid); | ||
| 86 | |||
| 87 | class ThreadRegistry { | ||
| 88 | public: | ||
| 89 | static const u32 kUnknownTid; | ||
| 90 | |||
| 91 | ThreadRegistry(ThreadContextFactory factory, u32 max_threads, | ||
| 92 | u32 thread_quarantine_size, u32 max_reuse = 0); | ||
| 93 | void GetNumberOfThreads(uptr *total = nullptr, uptr *running = nullptr, | ||
| 94 | uptr *alive = nullptr); | ||
| 95 | uptr GetMaxAliveThreads(); | ||
| 96 | |||
| 97 | void Lock() { mtx_.Lock(); } | ||
| 98 | void CheckLocked() { mtx_.CheckLocked(); } | ||
| 99 | void Unlock() { mtx_.Unlock(); } | ||
| 100 | |||
| 101 | // Should be guarded by ThreadRegistryLock. | ||
| 102 | ThreadContextBase *GetThreadLocked(u32 tid) { | ||
| 103 | DCHECK_LT(tid, n_contexts_); | ||
| 104 | return threads_[tid]; | ||
| 105 | } | ||
| 106 | |||
| 107 | u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg); | ||
| 108 | |||
| 109 | typedef void (*ThreadCallback)(ThreadContextBase *tctx, void *arg); | ||
| 110 | // Invokes callback with a specified arg for each thread context. | ||
| 111 | // Should be guarded by ThreadRegistryLock. | ||
| 112 | void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg); | ||
| 113 | |||
| 114 | typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg); | ||
| 115 | // Finds a thread using the provided callback. Returns kUnknownTid if no | ||
| 116 | // thread is found. | ||
| 117 | u32 FindThread(FindThreadCallback cb, void *arg); | ||
| 118 | // Should be guarded by ThreadRegistryLock. Return 0 if no thread | ||
| 119 | // is found. | ||
| 120 | ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb, | ||
| 121 | void *arg); | ||
| 122 | ThreadContextBase *FindThreadContextByOsIDLocked(tid_t os_id); | ||
| 123 | |||
| 124 | void SetThreadName(u32 tid, const char *name); | ||
| 125 | void SetThreadNameByUserId(uptr user_id, const char *name); | ||
| 126 | void DetachThread(u32 tid, void *arg); | ||
| 127 | void JoinThread(u32 tid, void *arg); | ||
| 128 | void FinishThread(u32 tid); | ||
| 129 | void StartThread(u32 tid, tid_t os_id, ThreadType thread_type, void *arg); | ||
| 130 | void SetThreadUserId(u32 tid, uptr user_id); | ||
| 131 | |||
| 132 | private: | ||
| 133 | const ThreadContextFactory context_factory_; | ||
| 134 | const u32 max_threads_; | ||
| 135 | const u32 thread_quarantine_size_; | ||
| 136 | const u32 max_reuse_; | ||
| 137 | |||
| 138 | BlockingMutex mtx_; | ||
| 139 | |||
| 140 | u32 n_contexts_; // Number of created thread contexts, | ||
| 141 | // at most max_threads_. | ||
| 142 | u64 total_threads_; // Total number of created threads. May be greater than | ||
| 143 | // max_threads_ if contexts were reused. | ||
| 144 | uptr alive_threads_; // Created or running. | ||
| 145 | uptr max_alive_threads_; | ||
| 146 | uptr running_threads_; | ||
| 147 | |||
| 148 | ThreadContextBase **threads_; // Array of thread contexts is leaked. | ||
| 149 | IntrusiveList<ThreadContextBase> dead_threads_; | ||
| 150 | IntrusiveList<ThreadContextBase> invalid_threads_; | ||
| 151 | |||
| 152 | void QuarantinePush(ThreadContextBase *tctx); | ||
| 153 | ThreadContextBase *QuarantinePop(); | ||
| 154 | }; | ||
| 155 | |||
| 156 | typedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock; | ||
| 157 | |||
| 158 | } // namespace __sanitizer | ||
| 159 | |||
| 160 | #endif // SANITIZER_THREAD_REGISTRY_H | ||
lib/tsan/sanitizer_common/sanitizer_tls_get_addr.cpp created+154| ... | @@ -0,0 +1,154 @@ | ||
| 1 | //===-- sanitizer_tls_get_addr.cpp ----------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Handle the __tls_get_addr call. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_tls_get_addr.h" | ||
| 14 | |||
| 15 | #include "sanitizer_flags.h" | ||
| 16 | #include "sanitizer_platform_interceptors.h" | ||
| 17 | |||
| 18 | namespace __sanitizer { | ||
| 19 | #if SANITIZER_INTERCEPT_TLS_GET_ADDR | ||
| 20 | |||
| 21 | // The actual parameter that comes to __tls_get_addr | ||
| 22 | // is a pointer to a struct with two words in it: | ||
| 23 | struct TlsGetAddrParam { | ||
| 24 | uptr dso_id; | ||
| 25 | uptr offset; | ||
| 26 | }; | ||
| 27 | |||
| 28 | // Glibc starting from 2.19 allocates tls using __signal_safe_memalign, | ||
| 29 | // which has such header. | ||
| 30 | struct Glibc_2_19_tls_header { | ||
| 31 | uptr size; | ||
| 32 | uptr start; | ||
| 33 | }; | ||
| 34 | |||
| 35 | // This must be static TLS | ||
| 36 | __attribute__((tls_model("initial-exec"))) | ||
| 37 | static __thread DTLS dtls; | ||
| 38 | |||
| 39 | // Make sure we properly destroy the DTLS objects: | ||
| 40 | // this counter should never get too large. | ||
| 41 | static atomic_uintptr_t number_of_live_dtls; | ||
| 42 | |||
| 43 | static const uptr kDestroyedThread = -1; | ||
| 44 | |||
| 45 | static inline void DTLS_Deallocate(DTLS::DTV *dtv, uptr size) { | ||
| 46 | if (!size) return; | ||
| 47 | VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size); | ||
| 48 | UnmapOrDie(dtv, size * sizeof(DTLS::DTV)); | ||
| 49 | atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed); | ||
| 50 | } | ||
| 51 | |||
| 52 | static inline void DTLS_Resize(uptr new_size) { | ||
| 53 | if (dtls.dtv_size >= new_size) return; | ||
| 54 | new_size = RoundUpToPowerOfTwo(new_size); | ||
| 55 | new_size = Max(new_size, 4096UL / sizeof(DTLS::DTV)); | ||
| 56 | DTLS::DTV *new_dtv = | ||
| 57 | (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize"); | ||
| 58 | uptr num_live_dtls = | ||
| 59 | atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed); | ||
| 60 | VReport(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls); | ||
| 61 | CHECK_LT(num_live_dtls, 1 << 20); | ||
| 62 | uptr old_dtv_size = dtls.dtv_size; | ||
| 63 | DTLS::DTV *old_dtv = dtls.dtv; | ||
| 64 | if (old_dtv_size) | ||
| 65 | internal_memcpy(new_dtv, dtls.dtv, dtls.dtv_size * sizeof(DTLS::DTV)); | ||
| 66 | dtls.dtv = new_dtv; | ||
| 67 | dtls.dtv_size = new_size; | ||
| 68 | if (old_dtv_size) | ||
| 69 | DTLS_Deallocate(old_dtv, old_dtv_size); | ||
| 70 | } | ||
| 71 | |||
| 72 | void DTLS_Destroy() { | ||
| 73 | if (!common_flags()->intercept_tls_get_addr) return; | ||
| 74 | VReport(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size); | ||
| 75 | uptr s = dtls.dtv_size; | ||
| 76 | dtls.dtv_size = kDestroyedThread; // Do this before unmap for AS-safety. | ||
| 77 | DTLS_Deallocate(dtls.dtv, s); | ||
| 78 | } | ||
| 79 | |||
| 80 | #if defined(__powerpc64__) || defined(__mips__) | ||
| 81 | // This is glibc's TLS_DTV_OFFSET: | ||
| 82 | // "Dynamic thread vector pointers point 0x8000 past the start of each | ||
| 83 | // TLS block." | ||
| 84 | static const uptr kDtvOffset = 0x8000; | ||
| 85 | #else | ||
| 86 | static const uptr kDtvOffset = 0; | ||
| 87 | #endif | ||
| 88 | |||
| 89 | DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res, | ||
| 90 | uptr static_tls_begin, uptr static_tls_end) { | ||
| 91 | if (!common_flags()->intercept_tls_get_addr) return 0; | ||
| 92 | TlsGetAddrParam *arg = reinterpret_cast<TlsGetAddrParam *>(arg_void); | ||
| 93 | uptr dso_id = arg->dso_id; | ||
| 94 | if (dtls.dtv_size == kDestroyedThread) return 0; | ||
| 95 | DTLS_Resize(dso_id + 1); | ||
| 96 | if (dtls.dtv[dso_id].beg) return 0; | ||
| 97 | uptr tls_size = 0; | ||
| 98 | uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset - kDtvOffset; | ||
| 99 | VReport(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p " | ||
| 100 | "num_live_dtls %zd\n", | ||
| 101 | arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg, | ||
| 102 | atomic_load(&number_of_live_dtls, memory_order_relaxed)); | ||
| 103 | if (dtls.last_memalign_ptr == tls_beg) { | ||
| 104 | tls_size = dtls.last_memalign_size; | ||
| 105 | VReport(2, "__tls_get_addr: glibc <=2.18 suspected; tls={%p,%p}\n", | ||
| 106 | tls_beg, tls_size); | ||
| 107 | } else if (tls_beg >= static_tls_begin && tls_beg < static_tls_end) { | ||
| 108 | // This is the static TLS block which was initialized / unpoisoned at thread | ||
| 109 | // creation. | ||
| 110 | VReport(2, "__tls_get_addr: static tls: %p\n", tls_beg); | ||
| 111 | tls_size = 0; | ||
| 112 | } else if ((tls_beg % 4096) == sizeof(Glibc_2_19_tls_header)) { | ||
| 113 | // We may want to check gnu_get_libc_version(). | ||
| 114 | Glibc_2_19_tls_header *header = (Glibc_2_19_tls_header *)tls_beg - 1; | ||
| 115 | tls_size = header->size; | ||
| 116 | tls_beg = header->start; | ||
| 117 | VReport(2, "__tls_get_addr: glibc >=2.19 suspected; tls={%p %p}\n", | ||
| 118 | tls_beg, tls_size); | ||
| 119 | } else { | ||
| 120 | VReport(2, "__tls_get_addr: Can't guess glibc version\n"); | ||
| 121 | // This may happen inside the DTOR of main thread, so just ignore it. | ||
| 122 | tls_size = 0; | ||
| 123 | } | ||
| 124 | dtls.dtv[dso_id].beg = tls_beg; | ||
| 125 | dtls.dtv[dso_id].size = tls_size; | ||
| 126 | return dtls.dtv + dso_id; | ||
| 127 | } | ||
| 128 | |||
| 129 | void DTLS_on_libc_memalign(void *ptr, uptr size) { | ||
| 130 | if (!common_flags()->intercept_tls_get_addr) return; | ||
| 131 | VReport(2, "DTLS_on_libc_memalign: %p %p\n", ptr, size); | ||
| 132 | dtls.last_memalign_ptr = reinterpret_cast<uptr>(ptr); | ||
| 133 | dtls.last_memalign_size = size; | ||
| 134 | } | ||
| 135 | |||
| 136 | DTLS *DTLS_Get() { return &dtls; } | ||
| 137 | |||
| 138 | bool DTLSInDestruction(DTLS *dtls) { | ||
| 139 | return dtls->dtv_size == kDestroyedThread; | ||
| 140 | } | ||
| 141 | |||
| 142 | #else | ||
| 143 | void DTLS_on_libc_memalign(void *ptr, uptr size) {} | ||
| 144 | DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, | ||
| 145 | unsigned long, unsigned long) { return 0; } | ||
| 146 | DTLS *DTLS_Get() { return 0; } | ||
| 147 | void DTLS_Destroy() {} | ||
| 148 | bool DTLSInDestruction(DTLS *dtls) { | ||
| 149 | UNREACHABLE("dtls is unsupported on this platform!"); | ||
| 150 | } | ||
| 151 | |||
| 152 | #endif // SANITIZER_INTERCEPT_TLS_GET_ADDR | ||
| 153 | |||
| 154 | } // namespace __sanitizer | ||
lib/tsan/sanitizer_common/sanitizer_tls_get_addr.h created+62| ... | @@ -0,0 +1,62 @@ | ||
| 1 | //===-- sanitizer_tls_get_addr.h --------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Handle the __tls_get_addr call. | ||
| 10 | // | ||
| 11 | // All this magic is specific to glibc and is required to workaround | ||
| 12 | // the lack of interface that would tell us about the Dynamic TLS (DTLS). | ||
| 13 | // https://sourceware.org/bugzilla/show_bug.cgi?id=16291 | ||
| 14 | // | ||
| 15 | // The matters get worse because the glibc implementation changed between | ||
| 16 | // 2.18 and 2.19: | ||
| 17 | // https://groups.google.com/forum/#!topic/address-sanitizer/BfwYD8HMxTM | ||
| 18 | // | ||
| 19 | // Before 2.19, every DTLS chunk is allocated with __libc_memalign, | ||
| 20 | // which we intercept and thus know where is the DTLS. | ||
| 21 | // Since 2.19, DTLS chunks are allocated with __signal_safe_memalign, | ||
| 22 | // which is an internal function that wraps a mmap call, neither of which | ||
| 23 | // we can intercept. Luckily, __signal_safe_memalign has a simple parseable | ||
| 24 | // header which we can use. | ||
| 25 | // | ||
| 26 | //===----------------------------------------------------------------------===// | ||
| 27 | |||
| 28 | #ifndef SANITIZER_TLS_GET_ADDR_H | ||
| 29 | #define SANITIZER_TLS_GET_ADDR_H | ||
| 30 | |||
| 31 | #include "sanitizer_common.h" | ||
| 32 | |||
| 33 | namespace __sanitizer { | ||
| 34 | |||
| 35 | struct DTLS { | ||
| 36 | // Array of DTLS chunks for the current Thread. | ||
| 37 | // If beg == 0, the chunk is unused. | ||
| 38 | struct DTV { | ||
| 39 | uptr beg, size; | ||
| 40 | }; | ||
| 41 | |||
| 42 | uptr dtv_size; | ||
| 43 | DTV *dtv; // dtv_size elements, allocated by MmapOrDie. | ||
| 44 | |||
| 45 | // Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cpp | ||
| 46 | uptr last_memalign_size; | ||
| 47 | uptr last_memalign_ptr; | ||
| 48 | }; | ||
| 49 | |||
| 50 | // Returns pointer and size of a linker-allocated TLS block. | ||
| 51 | // Each block is returned exactly once. | ||
| 52 | DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, uptr static_tls_begin, | ||
| 53 | uptr static_tls_end); | ||
| 54 | void DTLS_on_libc_memalign(void *ptr, uptr size); | ||
| 55 | DTLS *DTLS_Get(); | ||
| 56 | void DTLS_Destroy(); // Make sure to call this before the thread is destroyed. | ||
| 57 | // Returns true if DTLS of suspended thread is in destruction process. | ||
| 58 | bool DTLSInDestruction(DTLS *dtls); | ||
| 59 | |||
| 60 | } // namespace __sanitizer | ||
| 61 | |||
| 62 | #endif // SANITIZER_TLS_GET_ADDR_H | ||
lib/tsan/sanitizer_common/sanitizer_type_traits.cpp created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | //===-- sanitizer_type_traits.cpp -------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Implements a subset of C++ type traits. This is so we can avoid depending | ||
| 10 | // on system C++ headers. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | #include "sanitizer_type_traits.h" | ||
| 14 | |||
| 15 | namespace __sanitizer { | ||
| 16 | |||
| 17 | const bool true_type::value; | ||
| 18 | const bool false_type::value; | ||
| 19 | |||
| 20 | } // namespace __sanitizer | ||
lib/tsan/sanitizer_common/sanitizer_type_traits.h created+62| ... | @@ -0,0 +1,62 @@ | ||
| 1 | //===-- sanitizer_type_traits.h ---------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Implements a subset of C++ type traits. This is so we can avoid depending | ||
| 10 | // on system C++ headers. | ||
| 11 | // | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | #ifndef SANITIZER_TYPE_TRAITS_H | ||
| 14 | #define SANITIZER_TYPE_TRAITS_H | ||
| 15 | |||
| 16 | namespace __sanitizer { | ||
| 17 | |||
| 18 | struct true_type { | ||
| 19 | static const bool value = true; | ||
| 20 | }; | ||
| 21 | |||
| 22 | struct false_type { | ||
| 23 | static const bool value = false; | ||
| 24 | }; | ||
| 25 | |||
| 26 | // is_same<T, U> | ||
| 27 | // | ||
| 28 | // Type trait to compare if types are the same. | ||
| 29 | // E.g. | ||
| 30 | // | ||
| 31 | // ``` | ||
| 32 | // is_same<int,int>::value - True | ||
| 33 | // is_same<int,char>::value - False | ||
| 34 | // ``` | ||
| 35 | template <typename T, typename U> | ||
| 36 | struct is_same : public false_type {}; | ||
| 37 | |||
| 38 | template <typename T> | ||
| 39 | struct is_same<T, T> : public true_type {}; | ||
| 40 | |||
| 41 | // conditional<B, T, F> | ||
| 42 | // | ||
| 43 | // Defines type as T if B is true or as F otherwise. | ||
| 44 | // E.g. the following is true | ||
| 45 | // | ||
| 46 | // ``` | ||
| 47 | // is_same<int, conditional<true, int, double>::type>::value | ||
| 48 | // is_same<double, conditional<false, int, double>::type>::value | ||
| 49 | // ``` | ||
| 50 | template <bool B, class T, class F> | ||
| 51 | struct conditional { | ||
| 52 | using type = T; | ||
| 53 | }; | ||
| 54 | |||
| 55 | template <class T, class F> | ||
| 56 | struct conditional<false, T, F> { | ||
| 57 | using type = F; | ||
| 58 | }; | ||
| 59 | |||
| 60 | } // namespace __sanitizer | ||
| 61 | |||
| 62 | #endif | ||
lib/tsan/sanitizer_common/sanitizer_vector.h created+124| ... | @@ -0,0 +1,124 @@ | ||
| 1 | //===-- sanitizer_vector.h -------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between sanitizers run-time libraries. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | // Low-fat STL-like vector container. | ||
| 14 | |||
| 15 | #ifndef SANITIZER_VECTOR_H | ||
| 16 | #define SANITIZER_VECTOR_H | ||
| 17 | |||
| 18 | #include "sanitizer_common/sanitizer_allocator_internal.h" | ||
| 19 | #include "sanitizer_common/sanitizer_libc.h" | ||
| 20 | |||
| 21 | namespace __sanitizer { | ||
| 22 | |||
| 23 | template<typename T> | ||
| 24 | class Vector { | ||
| 25 | public: | ||
| 26 | Vector() : begin_(), end_(), last_() {} | ||
| 27 | |||
| 28 | ~Vector() { | ||
| 29 | if (begin_) | ||
| 30 | InternalFree(begin_); | ||
| 31 | } | ||
| 32 | |||
| 33 | void Reset() { | ||
| 34 | if (begin_) | ||
| 35 | InternalFree(begin_); | ||
| 36 | begin_ = 0; | ||
| 37 | end_ = 0; | ||
| 38 | last_ = 0; | ||
| 39 | } | ||
| 40 | |||
| 41 | uptr Size() const { | ||
| 42 | return end_ - begin_; | ||
| 43 | } | ||
| 44 | |||
| 45 | T &operator[](uptr i) { | ||
| 46 | DCHECK_LT(i, end_ - begin_); | ||
| 47 | return begin_[i]; | ||
| 48 | } | ||
| 49 | |||
| 50 | const T &operator[](uptr i) const { | ||
| 51 | DCHECK_LT(i, end_ - begin_); | ||
| 52 | return begin_[i]; | ||
| 53 | } | ||
| 54 | |||
| 55 | T *PushBack() { | ||
| 56 | EnsureSize(Size() + 1); | ||
| 57 | T *p = &end_[-1]; | ||
| 58 | internal_memset(p, 0, sizeof(*p)); | ||
| 59 | return p; | ||
| 60 | } | ||
| 61 | |||
| 62 | T *PushBack(const T& v) { | ||
| 63 | EnsureSize(Size() + 1); | ||
| 64 | T *p = &end_[-1]; | ||
| 65 | internal_memcpy(p, &v, sizeof(*p)); | ||
| 66 | return p; | ||
| 67 | } | ||
| 68 | |||
| 69 | void PopBack() { | ||
| 70 | DCHECK_GT(end_, begin_); | ||
| 71 | end_--; | ||
| 72 | } | ||
| 73 | |||
| 74 | void Resize(uptr size) { | ||
| 75 | if (size == 0) { | ||
| 76 | end_ = begin_; | ||
| 77 | return; | ||
| 78 | } | ||
| 79 | uptr old_size = Size(); | ||
| 80 | if (size <= old_size) { | ||
| 81 | end_ = begin_ + size; | ||
| 82 | return; | ||
| 83 | } | ||
| 84 | EnsureSize(size); | ||
| 85 | if (old_size < size) { | ||
| 86 | for (uptr i = old_size; i < size; i++) | ||
| 87 | internal_memset(&begin_[i], 0, sizeof(begin_[i])); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | private: | ||
| 92 | T *begin_; | ||
| 93 | T *end_; | ||
| 94 | T *last_; | ||
| 95 | |||
| 96 | void EnsureSize(uptr size) { | ||
| 97 | if (size <= Size()) | ||
| 98 | return; | ||
| 99 | if (size <= (uptr)(last_ - begin_)) { | ||
| 100 | end_ = begin_ + size; | ||
| 101 | return; | ||
| 102 | } | ||
| 103 | uptr cap0 = last_ - begin_; | ||
| 104 | uptr cap = cap0 * 5 / 4; // 25% growth | ||
| 105 | if (cap == 0) | ||
| 106 | cap = 16; | ||
| 107 | if (cap < size) | ||
| 108 | cap = size; | ||
| 109 | T *p = (T*)InternalAlloc(cap * sizeof(T)); | ||
| 110 | if (cap0) { | ||
| 111 | internal_memcpy(p, begin_, cap0 * sizeof(T)); | ||
| 112 | InternalFree(begin_); | ||
| 113 | } | ||
| 114 | begin_ = p; | ||
| 115 | end_ = begin_ + size; | ||
| 116 | last_ = begin_ + cap; | ||
| 117 | } | ||
| 118 | |||
| 119 | Vector(const Vector&); | ||
| 120 | void operator=(const Vector&); | ||
| 121 | }; | ||
| 122 | } // namespace __sanitizer | ||
| 123 | |||
| 124 | #endif // #ifndef SANITIZER_VECTOR_H | ||
lib/tsan/sanitizer_common/sanitizer_win.cpp created+1129| ... | @@ -0,0 +1,1129 @@ | ||
| 1 | //===-- sanitizer_win.cpp -------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is shared between AddressSanitizer and ThreadSanitizer | ||
| 10 | // run-time libraries and implements windows-specific functions from | ||
| 11 | // sanitizer_libc.h. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_platform.h" | ||
| 15 | #if SANITIZER_WINDOWS | ||
| 16 | |||
| 17 | #define WIN32_LEAN_AND_MEAN | ||
| 18 | #define NOGDI | ||
| 19 | #include <windows.h> | ||
| 20 | #include <io.h> | ||
| 21 | #include <psapi.h> | ||
| 22 | #include <stdlib.h> | ||
| 23 | |||
| 24 | #include "sanitizer_common.h" | ||
| 25 | #include "sanitizer_file.h" | ||
| 26 | #include "sanitizer_libc.h" | ||
| 27 | #include "sanitizer_mutex.h" | ||
| 28 | #include "sanitizer_placement_new.h" | ||
| 29 | #include "sanitizer_win_defs.h" | ||
| 30 | |||
| 31 | #if defined(PSAPI_VERSION) && PSAPI_VERSION == 1 | ||
| 32 | #pragma comment(lib, "psapi") | ||
| 33 | #endif | ||
| 34 | #if SANITIZER_WIN_TRACE | ||
| 35 | #include <traceloggingprovider.h> | ||
| 36 | // Windows trace logging provider init | ||
| 37 | #pragma comment(lib, "advapi32.lib") | ||
| 38 | TRACELOGGING_DECLARE_PROVIDER(g_asan_provider); | ||
| 39 | // GUID must be the same in utils/AddressSanitizerLoggingProvider.wprp | ||
| 40 | TRACELOGGING_DEFINE_PROVIDER(g_asan_provider, "AddressSanitizerLoggingProvider", | ||
| 41 | (0x6c6c766d, 0x3846, 0x4e6a, 0xa4, 0xfb, 0x5b, | ||
| 42 | 0x53, 0x0b, 0xd0, 0xf3, 0xfa)); | ||
| 43 | #else | ||
| 44 | #define TraceLoggingUnregister(x) | ||
| 45 | #endif | ||
| 46 | |||
| 47 | // A macro to tell the compiler that this part of the code cannot be reached, | ||
| 48 | // if the compiler supports this feature. Since we're using this in | ||
| 49 | // code that is called when terminating the process, the expansion of the | ||
| 50 | // macro should not terminate the process to avoid infinite recursion. | ||
| 51 | #if defined(__clang__) | ||
| 52 | # define BUILTIN_UNREACHABLE() __builtin_unreachable() | ||
| 53 | #elif defined(__GNUC__) && \ | ||
| 54 | (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) | ||
| 55 | # define BUILTIN_UNREACHABLE() __builtin_unreachable() | ||
| 56 | #elif defined(_MSC_VER) | ||
| 57 | # define BUILTIN_UNREACHABLE() __assume(0) | ||
| 58 | #else | ||
| 59 | # define BUILTIN_UNREACHABLE() | ||
| 60 | #endif | ||
| 61 | |||
| 62 | namespace __sanitizer { | ||
| 63 | |||
| 64 | #include "sanitizer_syscall_generic.inc" | ||
| 65 | |||
| 66 | // --------------------- sanitizer_common.h | ||
| 67 | uptr GetPageSize() { | ||
| 68 | SYSTEM_INFO si; | ||
| 69 | GetSystemInfo(&si); | ||
| 70 | return si.dwPageSize; | ||
| 71 | } | ||
| 72 | |||
| 73 | uptr GetMmapGranularity() { | ||
| 74 | SYSTEM_INFO si; | ||
| 75 | GetSystemInfo(&si); | ||
| 76 | return si.dwAllocationGranularity; | ||
| 77 | } | ||
| 78 | |||
| 79 | uptr GetMaxUserVirtualAddress() { | ||
| 80 | SYSTEM_INFO si; | ||
| 81 | GetSystemInfo(&si); | ||
| 82 | return (uptr)si.lpMaximumApplicationAddress; | ||
| 83 | } | ||
| 84 | |||
| 85 | uptr GetMaxVirtualAddress() { | ||
| 86 | return GetMaxUserVirtualAddress(); | ||
| 87 | } | ||
| 88 | |||
| 89 | bool FileExists(const char *filename) { | ||
| 90 | return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES; | ||
| 91 | } | ||
| 92 | |||
| 93 | uptr internal_getpid() { | ||
| 94 | return GetProcessId(GetCurrentProcess()); | ||
| 95 | } | ||
| 96 | |||
| 97 | int internal_dlinfo(void *handle, int request, void *p) { | ||
| 98 | UNIMPLEMENTED(); | ||
| 99 | } | ||
| 100 | |||
| 101 | // In contrast to POSIX, on Windows GetCurrentThreadId() | ||
| 102 | // returns a system-unique identifier. | ||
| 103 | tid_t GetTid() { | ||
| 104 | return GetCurrentThreadId(); | ||
| 105 | } | ||
| 106 | |||
| 107 | uptr GetThreadSelf() { | ||
| 108 | return GetTid(); | ||
| 109 | } | ||
| 110 | |||
| 111 | #if !SANITIZER_GO | ||
| 112 | void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, | ||
| 113 | uptr *stack_bottom) { | ||
| 114 | CHECK(stack_top); | ||
| 115 | CHECK(stack_bottom); | ||
| 116 | MEMORY_BASIC_INFORMATION mbi; | ||
| 117 | CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0); | ||
| 118 | // FIXME: is it possible for the stack to not be a single allocation? | ||
| 119 | // Are these values what ASan expects to get (reserved, not committed; | ||
| 120 | // including stack guard page) ? | ||
| 121 | *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize; | ||
| 122 | *stack_bottom = (uptr)mbi.AllocationBase; | ||
| 123 | } | ||
| 124 | #endif // #if !SANITIZER_GO | ||
| 125 | |||
| 126 | void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { | ||
| 127 | void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); | ||
| 128 | if (rv == 0) | ||
| 129 | ReportMmapFailureAndDie(size, mem_type, "allocate", | ||
| 130 | GetLastError(), raw_report); | ||
| 131 | return rv; | ||
| 132 | } | ||
| 133 | |||
| 134 | void UnmapOrDie(void *addr, uptr size) { | ||
| 135 | if (!size || !addr) | ||
| 136 | return; | ||
| 137 | |||
| 138 | MEMORY_BASIC_INFORMATION mbi; | ||
| 139 | CHECK(VirtualQuery(addr, &mbi, sizeof(mbi))); | ||
| 140 | |||
| 141 | // MEM_RELEASE can only be used to unmap whole regions previously mapped with | ||
| 142 | // VirtualAlloc. So we first try MEM_RELEASE since it is better, and if that | ||
| 143 | // fails try MEM_DECOMMIT. | ||
| 144 | if (VirtualFree(addr, 0, MEM_RELEASE) == 0) { | ||
| 145 | if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) { | ||
| 146 | Report("ERROR: %s failed to " | ||
| 147 | "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n", | ||
| 148 | SanitizerToolName, size, size, addr, GetLastError()); | ||
| 149 | CHECK("unable to unmap" && 0); | ||
| 150 | } | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | static void *ReturnNullptrOnOOMOrDie(uptr size, const char *mem_type, | ||
| 155 | const char *mmap_type) { | ||
| 156 | error_t last_error = GetLastError(); | ||
| 157 | if (last_error == ERROR_NOT_ENOUGH_MEMORY) | ||
| 158 | return nullptr; | ||
| 159 | ReportMmapFailureAndDie(size, mem_type, mmap_type, last_error); | ||
| 160 | } | ||
| 161 | |||
| 162 | void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { | ||
| 163 | void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); | ||
| 164 | if (rv == 0) | ||
| 165 | return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); | ||
| 166 | return rv; | ||
| 167 | } | ||
| 168 | |||
| 169 | // We want to map a chunk of address space aligned to 'alignment'. | ||
| 170 | void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, | ||
| 171 | const char *mem_type) { | ||
| 172 | CHECK(IsPowerOfTwo(size)); | ||
| 173 | CHECK(IsPowerOfTwo(alignment)); | ||
| 174 | |||
| 175 | // Windows will align our allocations to at least 64K. | ||
| 176 | alignment = Max(alignment, GetMmapGranularity()); | ||
| 177 | |||
| 178 | uptr mapped_addr = | ||
| 179 | (uptr)VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); | ||
| 180 | if (!mapped_addr) | ||
| 181 | return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); | ||
| 182 | |||
| 183 | // If we got it right on the first try, return. Otherwise, unmap it and go to | ||
| 184 | // the slow path. | ||
| 185 | if (IsAligned(mapped_addr, alignment)) | ||
| 186 | return (void*)mapped_addr; | ||
| 187 | if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0) | ||
| 188 | ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError()); | ||
| 189 | |||
| 190 | // If we didn't get an aligned address, overallocate, find an aligned address, | ||
| 191 | // unmap, and try to allocate at that aligned address. | ||
| 192 | int retries = 0; | ||
| 193 | const int kMaxRetries = 10; | ||
| 194 | for (; retries < kMaxRetries && | ||
| 195 | (mapped_addr == 0 || !IsAligned(mapped_addr, alignment)); | ||
| 196 | retries++) { | ||
| 197 | // Overallocate size + alignment bytes. | ||
| 198 | mapped_addr = | ||
| 199 | (uptr)VirtualAlloc(0, size + alignment, MEM_RESERVE, PAGE_NOACCESS); | ||
| 200 | if (!mapped_addr) | ||
| 201 | return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); | ||
| 202 | |||
| 203 | // Find the aligned address. | ||
| 204 | uptr aligned_addr = RoundUpTo(mapped_addr, alignment); | ||
| 205 | |||
| 206 | // Free the overallocation. | ||
| 207 | if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0) | ||
| 208 | ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError()); | ||
| 209 | |||
| 210 | // Attempt to allocate exactly the number of bytes we need at the aligned | ||
| 211 | // address. This may fail for a number of reasons, in which case we continue | ||
| 212 | // the loop. | ||
| 213 | mapped_addr = (uptr)VirtualAlloc((void *)aligned_addr, size, | ||
| 214 | MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); | ||
| 215 | } | ||
| 216 | |||
| 217 | // Fail if we can't make this work quickly. | ||
| 218 | if (retries == kMaxRetries && mapped_addr == 0) | ||
| 219 | return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); | ||
| 220 | |||
| 221 | return (void *)mapped_addr; | ||
| 222 | } | ||
| 223 | |||
| 224 | bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { | ||
| 225 | // FIXME: is this really "NoReserve"? On Win32 this does not matter much, | ||
| 226 | // but on Win64 it does. | ||
| 227 | (void)name; // unsupported | ||
| 228 | #if !SANITIZER_GO && SANITIZER_WINDOWS64 | ||
| 229 | // On asan/Windows64, use MEM_COMMIT would result in error | ||
| 230 | // 1455:ERROR_COMMITMENT_LIMIT. | ||
| 231 | // Asan uses exception handler to commit page on demand. | ||
| 232 | void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE, PAGE_READWRITE); | ||
| 233 | #else | ||
| 234 | void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE | MEM_COMMIT, | ||
| 235 | PAGE_READWRITE); | ||
| 236 | #endif | ||
| 237 | if (p == 0) { | ||
| 238 | Report("ERROR: %s failed to " | ||
| 239 | "allocate %p (%zd) bytes at %p (error code: %d)\n", | ||
| 240 | SanitizerToolName, size, size, fixed_addr, GetLastError()); | ||
| 241 | return false; | ||
| 242 | } | ||
| 243 | return true; | ||
| 244 | } | ||
| 245 | |||
| 246 | bool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, const char *name) { | ||
| 247 | // FIXME: Windows support large pages too. Might be worth checking | ||
| 248 | return MmapFixedNoReserve(fixed_addr, size, name); | ||
| 249 | } | ||
| 250 | |||
| 251 | // Memory space mapped by 'MmapFixedOrDie' must have been reserved by | ||
| 252 | // 'MmapFixedNoAccess'. | ||
| 253 | void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) { | ||
| 254 | void *p = VirtualAlloc((LPVOID)fixed_addr, size, | ||
| 255 | MEM_COMMIT, PAGE_READWRITE); | ||
| 256 | if (p == 0) { | ||
| 257 | char mem_type[30]; | ||
| 258 | internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", | ||
| 259 | fixed_addr); | ||
| 260 | ReportMmapFailureAndDie(size, mem_type, "allocate", GetLastError()); | ||
| 261 | } | ||
| 262 | return p; | ||
| 263 | } | ||
| 264 | |||
| 265 | // Uses fixed_addr for now. | ||
| 266 | // Will use offset instead once we've implemented this function for real. | ||
| 267 | uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, const char *name) { | ||
| 268 | return reinterpret_cast<uptr>(MmapFixedOrDieOnFatalError(fixed_addr, size)); | ||
| 269 | } | ||
| 270 | |||
| 271 | uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size, | ||
| 272 | const char *name) { | ||
| 273 | return reinterpret_cast<uptr>(MmapFixedOrDie(fixed_addr, size)); | ||
| 274 | } | ||
| 275 | |||
| 276 | void ReservedAddressRange::Unmap(uptr addr, uptr size) { | ||
| 277 | // Only unmap if it covers the entire range. | ||
| 278 | CHECK((addr == reinterpret_cast<uptr>(base_)) && (size == size_)); | ||
| 279 | // We unmap the whole range, just null out the base. | ||
| 280 | base_ = nullptr; | ||
| 281 | size_ = 0; | ||
| 282 | UnmapOrDie(reinterpret_cast<void*>(addr), size); | ||
| 283 | } | ||
| 284 | |||
| 285 | void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) { | ||
| 286 | void *p = VirtualAlloc((LPVOID)fixed_addr, size, | ||
| 287 | MEM_COMMIT, PAGE_READWRITE); | ||
| 288 | if (p == 0) { | ||
| 289 | char mem_type[30]; | ||
| 290 | internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", | ||
| 291 | fixed_addr); | ||
| 292 | return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); | ||
| 293 | } | ||
| 294 | return p; | ||
| 295 | } | ||
| 296 | |||
| 297 | void *MmapNoReserveOrDie(uptr size, const char *mem_type) { | ||
| 298 | // FIXME: make this really NoReserve? | ||
| 299 | return MmapOrDie(size, mem_type); | ||
| 300 | } | ||
| 301 | |||
| 302 | uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { | ||
| 303 | base_ = fixed_addr ? MmapFixedNoAccess(fixed_addr, size) : MmapNoAccess(size); | ||
| 304 | size_ = size; | ||
| 305 | name_ = name; | ||
| 306 | (void)os_handle_; // unsupported | ||
| 307 | return reinterpret_cast<uptr>(base_); | ||
| 308 | } | ||
| 309 | |||
| 310 | |||
| 311 | void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { | ||
| 312 | (void)name; // unsupported | ||
| 313 | void *res = VirtualAlloc((LPVOID)fixed_addr, size, | ||
| 314 | MEM_RESERVE, PAGE_NOACCESS); | ||
| 315 | if (res == 0) | ||
| 316 | Report("WARNING: %s failed to " | ||
| 317 | "mprotect %p (%zd) bytes at %p (error code: %d)\n", | ||
| 318 | SanitizerToolName, size, size, fixed_addr, GetLastError()); | ||
| 319 | return res; | ||
| 320 | } | ||
| 321 | |||
| 322 | void *MmapNoAccess(uptr size) { | ||
| 323 | void *res = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_NOACCESS); | ||
| 324 | if (res == 0) | ||
| 325 | Report("WARNING: %s failed to " | ||
| 326 | "mprotect %p (%zd) bytes (error code: %d)\n", | ||
| 327 | SanitizerToolName, size, size, GetLastError()); | ||
| 328 | return res; | ||
| 329 | } | ||
| 330 | |||
| 331 | bool MprotectNoAccess(uptr addr, uptr size) { | ||
| 332 | DWORD old_protection; | ||
| 333 | return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection); | ||
| 334 | } | ||
| 335 | |||
| 336 | void ReleaseMemoryPagesToOS(uptr beg, uptr end) { | ||
| 337 | // This is almost useless on 32-bits. | ||
| 338 | // FIXME: add madvise-analog when we move to 64-bits. | ||
| 339 | } | ||
| 340 | |||
| 341 | void SetShadowRegionHugePageMode(uptr addr, uptr size) { | ||
| 342 | // FIXME: probably similar to ReleaseMemoryToOS. | ||
| 343 | } | ||
| 344 | |||
| 345 | bool DontDumpShadowMemory(uptr addr, uptr length) { | ||
| 346 | // This is almost useless on 32-bits. | ||
| 347 | // FIXME: add madvise-analog when we move to 64-bits. | ||
| 348 | return true; | ||
| 349 | } | ||
| 350 | |||
| 351 | uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, | ||
| 352 | uptr *largest_gap_found, | ||
| 353 | uptr *max_occupied_addr) { | ||
| 354 | uptr address = 0; | ||
| 355 | while (true) { | ||
| 356 | MEMORY_BASIC_INFORMATION info; | ||
| 357 | if (!::VirtualQuery((void*)address, &info, sizeof(info))) | ||
| 358 | return 0; | ||
| 359 | |||
| 360 | if (info.State == MEM_FREE) { | ||
| 361 | uptr shadow_address = RoundUpTo((uptr)info.BaseAddress + left_padding, | ||
| 362 | alignment); | ||
| 363 | if (shadow_address + size < (uptr)info.BaseAddress + info.RegionSize) | ||
| 364 | return shadow_address; | ||
| 365 | } | ||
| 366 | |||
| 367 | // Move to the next region. | ||
| 368 | address = (uptr)info.BaseAddress + info.RegionSize; | ||
| 369 | } | ||
| 370 | return 0; | ||
| 371 | } | ||
| 372 | |||
| 373 | bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { | ||
| 374 | MEMORY_BASIC_INFORMATION mbi; | ||
| 375 | CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi))); | ||
| 376 | return mbi.Protect == PAGE_NOACCESS && | ||
| 377 | (uptr)mbi.BaseAddress + mbi.RegionSize >= range_end; | ||
| 378 | } | ||
| 379 | |||
| 380 | void *MapFileToMemory(const char *file_name, uptr *buff_size) { | ||
| 381 | UNIMPLEMENTED(); | ||
| 382 | } | ||
| 383 | |||
| 384 | void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { | ||
| 385 | UNIMPLEMENTED(); | ||
| 386 | } | ||
| 387 | |||
| 388 | static const int kMaxEnvNameLength = 128; | ||
| 389 | static const DWORD kMaxEnvValueLength = 32767; | ||
| 390 | |||
| 391 | namespace { | ||
| 392 | |||
| 393 | struct EnvVariable { | ||
| 394 | char name[kMaxEnvNameLength]; | ||
| 395 | char value[kMaxEnvValueLength]; | ||
| 396 | }; | ||
| 397 | |||
| 398 | } // namespace | ||
| 399 | |||
| 400 | static const int kEnvVariables = 5; | ||
| 401 | static EnvVariable env_vars[kEnvVariables]; | ||
| 402 | static int num_env_vars; | ||
| 403 | |||
| 404 | const char *GetEnv(const char *name) { | ||
| 405 | // Note: this implementation caches the values of the environment variables | ||
| 406 | // and limits their quantity. | ||
| 407 | for (int i = 0; i < num_env_vars; i++) { | ||
| 408 | if (0 == internal_strcmp(name, env_vars[i].name)) | ||
| 409 | return env_vars[i].value; | ||
| 410 | } | ||
| 411 | CHECK_LT(num_env_vars, kEnvVariables); | ||
| 412 | DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value, | ||
| 413 | kMaxEnvValueLength); | ||
| 414 | if (rv > 0 && rv < kMaxEnvValueLength) { | ||
| 415 | CHECK_LT(internal_strlen(name), kMaxEnvNameLength); | ||
| 416 | internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength); | ||
| 417 | num_env_vars++; | ||
| 418 | return env_vars[num_env_vars - 1].value; | ||
| 419 | } | ||
| 420 | return 0; | ||
| 421 | } | ||
| 422 | |||
| 423 | const char *GetPwd() { | ||
| 424 | UNIMPLEMENTED(); | ||
| 425 | } | ||
| 426 | |||
| 427 | u32 GetUid() { | ||
| 428 | UNIMPLEMENTED(); | ||
| 429 | } | ||
| 430 | |||
| 431 | namespace { | ||
| 432 | struct ModuleInfo { | ||
| 433 | const char *filepath; | ||
| 434 | uptr base_address; | ||
| 435 | uptr end_address; | ||
| 436 | }; | ||
| 437 | |||
| 438 | #if !SANITIZER_GO | ||
| 439 | int CompareModulesBase(const void *pl, const void *pr) { | ||
| 440 | const ModuleInfo *l = (const ModuleInfo *)pl, *r = (const ModuleInfo *)pr; | ||
| 441 | if (l->base_address < r->base_address) | ||
| 442 | return -1; | ||
| 443 | return l->base_address > r->base_address; | ||
| 444 | } | ||
| 445 | #endif | ||
| 446 | } // namespace | ||
| 447 | |||
| 448 | #if !SANITIZER_GO | ||
| 449 | void DumpProcessMap() { | ||
| 450 | Report("Dumping process modules:\n"); | ||
| 451 | ListOfModules modules; | ||
| 452 | modules.init(); | ||
| 453 | uptr num_modules = modules.size(); | ||
| 454 | |||
| 455 | InternalMmapVector<ModuleInfo> module_infos(num_modules); | ||
| 456 | for (size_t i = 0; i < num_modules; ++i) { | ||
| 457 | module_infos[i].filepath = modules[i].full_name(); | ||
| 458 | module_infos[i].base_address = modules[i].ranges().front()->beg; | ||
| 459 | module_infos[i].end_address = modules[i].ranges().back()->end; | ||
| 460 | } | ||
| 461 | qsort(module_infos.data(), num_modules, sizeof(ModuleInfo), | ||
| 462 | CompareModulesBase); | ||
| 463 | |||
| 464 | for (size_t i = 0; i < num_modules; ++i) { | ||
| 465 | const ModuleInfo &mi = module_infos[i]; | ||
| 466 | if (mi.end_address != 0) { | ||
| 467 | Printf("\t%p-%p %s\n", mi.base_address, mi.end_address, | ||
| 468 | mi.filepath[0] ? mi.filepath : "[no name]"); | ||
| 469 | } else if (mi.filepath[0]) { | ||
| 470 | Printf("\t??\?-??? %s\n", mi.filepath); | ||
| 471 | } else { | ||
| 472 | Printf("\t???\n"); | ||
| 473 | } | ||
| 474 | } | ||
| 475 | } | ||
| 476 | #endif | ||
| 477 | |||
| 478 | void PrintModuleMap() { } | ||
| 479 | |||
| 480 | void DisableCoreDumperIfNecessary() { | ||
| 481 | // Do nothing. | ||
| 482 | } | ||
| 483 | |||
| 484 | void ReExec() { | ||
| 485 | UNIMPLEMENTED(); | ||
| 486 | } | ||
| 487 | |||
| 488 | void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} | ||
| 489 | |||
| 490 | bool StackSizeIsUnlimited() { | ||
| 491 | UNIMPLEMENTED(); | ||
| 492 | } | ||
| 493 | |||
| 494 | void SetStackSizeLimitInBytes(uptr limit) { | ||
| 495 | UNIMPLEMENTED(); | ||
| 496 | } | ||
| 497 | |||
| 498 | bool AddressSpaceIsUnlimited() { | ||
| 499 | UNIMPLEMENTED(); | ||
| 500 | } | ||
| 501 | |||
| 502 | void SetAddressSpaceUnlimited() { | ||
| 503 | UNIMPLEMENTED(); | ||
| 504 | } | ||
| 505 | |||
| 506 | bool IsPathSeparator(const char c) { | ||
| 507 | return c == '\\' || c == '/'; | ||
| 508 | } | ||
| 509 | |||
| 510 | static bool IsAlpha(char c) { | ||
| 511 | c = ToLower(c); | ||
| 512 | return c >= 'a' && c <= 'z'; | ||
| 513 | } | ||
| 514 | |||
| 515 | bool IsAbsolutePath(const char *path) { | ||
| 516 | return path != nullptr && IsAlpha(path[0]) && path[1] == ':' && | ||
| 517 | IsPathSeparator(path[2]); | ||
| 518 | } | ||
| 519 | |||
| 520 | void SleepForSeconds(int seconds) { | ||
| 521 | Sleep(seconds * 1000); | ||
| 522 | } | ||
| 523 | |||
| 524 | void SleepForMillis(int millis) { | ||
| 525 | Sleep(millis); | ||
| 526 | } | ||
| 527 | |||
| 528 | u64 NanoTime() { | ||
| 529 | static LARGE_INTEGER frequency = {}; | ||
| 530 | LARGE_INTEGER counter; | ||
| 531 | if (UNLIKELY(frequency.QuadPart == 0)) { | ||
| 532 | QueryPerformanceFrequency(&frequency); | ||
| 533 | CHECK_NE(frequency.QuadPart, 0); | ||
| 534 | } | ||
| 535 | QueryPerformanceCounter(&counter); | ||
| 536 | counter.QuadPart *= 1000ULL * 1000000ULL; | ||
| 537 | counter.QuadPart /= frequency.QuadPart; | ||
| 538 | return counter.QuadPart; | ||
| 539 | } | ||
| 540 | |||
| 541 | u64 MonotonicNanoTime() { return NanoTime(); } | ||
| 542 | |||
| 543 | void Abort() { | ||
| 544 | internal__exit(3); | ||
| 545 | } | ||
| 546 | |||
| 547 | #if !SANITIZER_GO | ||
| 548 | // Read the file to extract the ImageBase field from the PE header. If ASLR is | ||
| 549 | // disabled and this virtual address is available, the loader will typically | ||
| 550 | // load the image at this address. Therefore, we call it the preferred base. Any | ||
| 551 | // addresses in the DWARF typically assume that the object has been loaded at | ||
| 552 | // this address. | ||
| 553 | static uptr GetPreferredBase(const char *modname) { | ||
| 554 | fd_t fd = OpenFile(modname, RdOnly, nullptr); | ||
| 555 | if (fd == kInvalidFd) | ||
| 556 | return 0; | ||
| 557 | FileCloser closer(fd); | ||
| 558 | |||
| 559 | // Read just the DOS header. | ||
| 560 | IMAGE_DOS_HEADER dos_header; | ||
| 561 | uptr bytes_read; | ||
| 562 | if (!ReadFromFile(fd, &dos_header, sizeof(dos_header), &bytes_read) || | ||
| 563 | bytes_read != sizeof(dos_header)) | ||
| 564 | return 0; | ||
| 565 | |||
| 566 | // The file should start with the right signature. | ||
| 567 | if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) | ||
| 568 | return 0; | ||
| 569 | |||
| 570 | // The layout at e_lfanew is: | ||
| 571 | // "PE\0\0" | ||
| 572 | // IMAGE_FILE_HEADER | ||
| 573 | // IMAGE_OPTIONAL_HEADER | ||
| 574 | // Seek to e_lfanew and read all that data. | ||
| 575 | char buf[4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER)]; | ||
| 576 | if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) == | ||
| 577 | INVALID_SET_FILE_POINTER) | ||
| 578 | return 0; | ||
| 579 | if (!ReadFromFile(fd, &buf[0], sizeof(buf), &bytes_read) || | ||
| 580 | bytes_read != sizeof(buf)) | ||
| 581 | return 0; | ||
| 582 | |||
| 583 | // Check for "PE\0\0" before the PE header. | ||
| 584 | char *pe_sig = &buf[0]; | ||
| 585 | if (internal_memcmp(pe_sig, "PE\0\0", 4) != 0) | ||
| 586 | return 0; | ||
| 587 | |||
| 588 | // Skip over IMAGE_FILE_HEADER. We could do more validation here if we wanted. | ||
| 589 | IMAGE_OPTIONAL_HEADER *pe_header = | ||
| 590 | (IMAGE_OPTIONAL_HEADER *)(pe_sig + 4 + sizeof(IMAGE_FILE_HEADER)); | ||
| 591 | |||
| 592 | // Check for more magic in the PE header. | ||
| 593 | if (pe_header->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) | ||
| 594 | return 0; | ||
| 595 | |||
| 596 | // Finally, return the ImageBase. | ||
| 597 | return (uptr)pe_header->ImageBase; | ||
| 598 | } | ||
| 599 | |||
| 600 | void ListOfModules::init() { | ||
| 601 | clearOrInit(); | ||
| 602 | HANDLE cur_process = GetCurrentProcess(); | ||
| 603 | |||
| 604 | // Query the list of modules. Start by assuming there are no more than 256 | ||
| 605 | // modules and retry if that's not sufficient. | ||
| 606 | HMODULE *hmodules = 0; | ||
| 607 | uptr modules_buffer_size = sizeof(HMODULE) * 256; | ||
| 608 | DWORD bytes_required; | ||
| 609 | while (!hmodules) { | ||
| 610 | hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__); | ||
| 611 | CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size, | ||
| 612 | &bytes_required)); | ||
| 613 | if (bytes_required > modules_buffer_size) { | ||
| 614 | // Either there turned out to be more than 256 hmodules, or new hmodules | ||
| 615 | // could have loaded since the last try. Retry. | ||
| 616 | UnmapOrDie(hmodules, modules_buffer_size); | ||
| 617 | hmodules = 0; | ||
| 618 | modules_buffer_size = bytes_required; | ||
| 619 | } | ||
| 620 | } | ||
| 621 | |||
| 622 | // |num_modules| is the number of modules actually present, | ||
| 623 | size_t num_modules = bytes_required / sizeof(HMODULE); | ||
| 624 | for (size_t i = 0; i < num_modules; ++i) { | ||
| 625 | HMODULE handle = hmodules[i]; | ||
| 626 | MODULEINFO mi; | ||
| 627 | if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi))) | ||
| 628 | continue; | ||
| 629 | |||
| 630 | // Get the UTF-16 path and convert to UTF-8. | ||
| 631 | wchar_t modname_utf16[kMaxPathLength]; | ||
| 632 | int modname_utf16_len = | ||
| 633 | GetModuleFileNameW(handle, modname_utf16, kMaxPathLength); | ||
| 634 | if (modname_utf16_len == 0) | ||
| 635 | modname_utf16[0] = '\0'; | ||
| 636 | char module_name[kMaxPathLength]; | ||
| 637 | int module_name_len = | ||
| 638 | ::WideCharToMultiByte(CP_UTF8, 0, modname_utf16, modname_utf16_len + 1, | ||
| 639 | &module_name[0], kMaxPathLength, NULL, NULL); | ||
| 640 | module_name[module_name_len] = '\0'; | ||
| 641 | |||
| 642 | uptr base_address = (uptr)mi.lpBaseOfDll; | ||
| 643 | uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage; | ||
| 644 | |||
| 645 | // Adjust the base address of the module so that we get a VA instead of an | ||
| 646 | // RVA when computing the module offset. This helps llvm-symbolizer find the | ||
| 647 | // right DWARF CU. In the common case that the image is loaded at it's | ||
| 648 | // preferred address, we will now print normal virtual addresses. | ||
| 649 | uptr preferred_base = GetPreferredBase(&module_name[0]); | ||
| 650 | uptr adjusted_base = base_address - preferred_base; | ||
| 651 | |||
| 652 | LoadedModule cur_module; | ||
| 653 | cur_module.set(module_name, adjusted_base); | ||
| 654 | // We add the whole module as one single address range. | ||
| 655 | cur_module.addAddressRange(base_address, end_address, /*executable*/ true, | ||
| 656 | /*writable*/ true); | ||
| 657 | modules_.push_back(cur_module); | ||
| 658 | } | ||
| 659 | UnmapOrDie(hmodules, modules_buffer_size); | ||
| 660 | } | ||
| 661 | |||
| 662 | void ListOfModules::fallbackInit() { clear(); } | ||
| 663 | |||
| 664 | // We can't use atexit() directly at __asan_init time as the CRT is not fully | ||
| 665 | // initialized at this point. Place the functions into a vector and use | ||
| 666 | // atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers). | ||
| 667 | InternalMmapVectorNoCtor<void (*)(void)> atexit_functions; | ||
| 668 | |||
| 669 | int Atexit(void (*function)(void)) { | ||
| 670 | atexit_functions.push_back(function); | ||
| 671 | return 0; | ||
| 672 | } | ||
| 673 | |||
| 674 | static int RunAtexit() { | ||
| 675 | TraceLoggingUnregister(g_asan_provider); | ||
| 676 | int ret = 0; | ||
| 677 | for (uptr i = 0; i < atexit_functions.size(); ++i) { | ||
| 678 | ret |= atexit(atexit_functions[i]); | ||
| 679 | } | ||
| 680 | return ret; | ||
| 681 | } | ||
| 682 | |||
| 683 | #pragma section(".CRT$XID", long, read) | ||
| 684 | __declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit; | ||
| 685 | #endif | ||
| 686 | |||
| 687 | // ------------------ sanitizer_libc.h | ||
| 688 | fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) { | ||
| 689 | // FIXME: Use the wide variants to handle Unicode filenames. | ||
| 690 | fd_t res; | ||
| 691 | if (mode == RdOnly) { | ||
| 692 | res = CreateFileA(filename, GENERIC_READ, | ||
| 693 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | ||
| 694 | nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); | ||
| 695 | } else if (mode == WrOnly) { | ||
| 696 | res = CreateFileA(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, | ||
| 697 | FILE_ATTRIBUTE_NORMAL, nullptr); | ||
| 698 | } else { | ||
| 699 | UNIMPLEMENTED(); | ||
| 700 | } | ||
| 701 | CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd); | ||
| 702 | CHECK(res != kStderrFd || kStderrFd == kInvalidFd); | ||
| 703 | if (res == kInvalidFd && last_error) | ||
| 704 | *last_error = GetLastError(); | ||
| 705 | return res; | ||
| 706 | } | ||
| 707 | |||
| 708 | void CloseFile(fd_t fd) { | ||
| 709 | CloseHandle(fd); | ||
| 710 | } | ||
| 711 | |||
| 712 | bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, | ||
| 713 | error_t *error_p) { | ||
| 714 | CHECK(fd != kInvalidFd); | ||
| 715 | |||
| 716 | // bytes_read can't be passed directly to ReadFile: | ||
| 717 | // uptr is unsigned long long on 64-bit Windows. | ||
| 718 | unsigned long num_read_long; | ||
| 719 | |||
| 720 | bool success = ::ReadFile(fd, buff, buff_size, &num_read_long, nullptr); | ||
| 721 | if (!success && error_p) | ||
| 722 | *error_p = GetLastError(); | ||
| 723 | if (bytes_read) | ||
| 724 | *bytes_read = num_read_long; | ||
| 725 | return success; | ||
| 726 | } | ||
| 727 | |||
| 728 | bool SupportsColoredOutput(fd_t fd) { | ||
| 729 | // FIXME: support colored output. | ||
| 730 | return false; | ||
| 731 | } | ||
| 732 | |||
| 733 | bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, | ||
| 734 | error_t *error_p) { | ||
| 735 | CHECK(fd != kInvalidFd); | ||
| 736 | |||
| 737 | // Handle null optional parameters. | ||
| 738 | error_t dummy_error; | ||
| 739 | error_p = error_p ? error_p : &dummy_error; | ||
| 740 | uptr dummy_bytes_written; | ||
| 741 | bytes_written = bytes_written ? bytes_written : &dummy_bytes_written; | ||
| 742 | |||
| 743 | // Initialize output parameters in case we fail. | ||
| 744 | *error_p = 0; | ||
| 745 | *bytes_written = 0; | ||
| 746 | |||
| 747 | // Map the conventional Unix fds 1 and 2 to Windows handles. They might be | ||
| 748 | // closed, in which case this will fail. | ||
| 749 | if (fd == kStdoutFd || fd == kStderrFd) { | ||
| 750 | fd = GetStdHandle(fd == kStdoutFd ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); | ||
| 751 | if (fd == 0) { | ||
| 752 | *error_p = ERROR_INVALID_HANDLE; | ||
| 753 | return false; | ||
| 754 | } | ||
| 755 | } | ||
| 756 | |||
| 757 | DWORD bytes_written_32; | ||
| 758 | if (!WriteFile(fd, buff, buff_size, &bytes_written_32, 0)) { | ||
| 759 | *error_p = GetLastError(); | ||
| 760 | return false; | ||
| 761 | } else { | ||
| 762 | *bytes_written = bytes_written_32; | ||
| 763 | return true; | ||
| 764 | } | ||
| 765 | } | ||
| 766 | |||
| 767 | uptr internal_sched_yield() { | ||
| 768 | Sleep(0); | ||
| 769 | return 0; | ||
| 770 | } | ||
| 771 | |||
| 772 | void internal__exit(int exitcode) { | ||
| 773 | TraceLoggingUnregister(g_asan_provider); | ||
| 774 | // ExitProcess runs some finalizers, so use TerminateProcess to avoid that. | ||
| 775 | // The debugger doesn't stop on TerminateProcess like it does on ExitProcess, | ||
| 776 | // so add our own breakpoint here. | ||
| 777 | if (::IsDebuggerPresent()) | ||
| 778 | __debugbreak(); | ||
| 779 | TerminateProcess(GetCurrentProcess(), exitcode); | ||
| 780 | BUILTIN_UNREACHABLE(); | ||
| 781 | } | ||
| 782 | |||
| 783 | uptr internal_ftruncate(fd_t fd, uptr size) { | ||
| 784 | UNIMPLEMENTED(); | ||
| 785 | } | ||
| 786 | |||
| 787 | uptr GetRSS() { | ||
| 788 | PROCESS_MEMORY_COUNTERS counters; | ||
| 789 | if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) | ||
| 790 | return 0; | ||
| 791 | return counters.WorkingSetSize; | ||
| 792 | } | ||
| 793 | |||
| 794 | void *internal_start_thread(void *(*func)(void *arg), void *arg) { return 0; } | ||
| 795 | void internal_join_thread(void *th) { } | ||
| 796 | |||
| 797 | // ---------------------- BlockingMutex ---------------- {{{1 | ||
| 798 | |||
| 799 | BlockingMutex::BlockingMutex() { | ||
| 800 | CHECK(sizeof(SRWLOCK) <= sizeof(opaque_storage_)); | ||
| 801 | internal_memset(this, 0, sizeof(*this)); | ||
| 802 | } | ||
| 803 | |||
| 804 | void BlockingMutex::Lock() { | ||
| 805 | AcquireSRWLockExclusive((PSRWLOCK)opaque_storage_); | ||
| 806 | CHECK_EQ(owner_, 0); | ||
| 807 | owner_ = GetThreadSelf(); | ||
| 808 | } | ||
| 809 | |||
| 810 | void BlockingMutex::Unlock() { | ||
| 811 | CheckLocked(); | ||
| 812 | owner_ = 0; | ||
| 813 | ReleaseSRWLockExclusive((PSRWLOCK)opaque_storage_); | ||
| 814 | } | ||
| 815 | |||
| 816 | void BlockingMutex::CheckLocked() { | ||
| 817 | CHECK_EQ(owner_, GetThreadSelf()); | ||
| 818 | } | ||
| 819 | |||
| 820 | uptr GetTlsSize() { | ||
| 821 | return 0; | ||
| 822 | } | ||
| 823 | |||
| 824 | void InitTlsSize() { | ||
| 825 | } | ||
| 826 | |||
| 827 | void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, | ||
| 828 | uptr *tls_addr, uptr *tls_size) { | ||
| 829 | #if SANITIZER_GO | ||
| 830 | *stk_addr = 0; | ||
| 831 | *stk_size = 0; | ||
| 832 | *tls_addr = 0; | ||
| 833 | *tls_size = 0; | ||
| 834 | #else | ||
| 835 | uptr stack_top, stack_bottom; | ||
| 836 | GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); | ||
| 837 | *stk_addr = stack_bottom; | ||
| 838 | *stk_size = stack_top - stack_bottom; | ||
| 839 | *tls_addr = 0; | ||
| 840 | *tls_size = 0; | ||
| 841 | #endif | ||
| 842 | } | ||
| 843 | |||
| 844 | void ReportFile::Write(const char *buffer, uptr length) { | ||
| 845 | SpinMutexLock l(mu); | ||
| 846 | ReopenIfNecessary(); | ||
| 847 | if (!WriteToFile(fd, buffer, length)) { | ||
| 848 | // stderr may be closed, but we may be able to print to the debugger | ||
| 849 | // instead. This is the case when launching a program from Visual Studio, | ||
| 850 | // and the following routine should write to its console. | ||
| 851 | OutputDebugStringA(buffer); | ||
| 852 | } | ||
| 853 | } | ||
| 854 | |||
| 855 | void SetAlternateSignalStack() { | ||
| 856 | // FIXME: Decide what to do on Windows. | ||
| 857 | } | ||
| 858 | |||
| 859 | void UnsetAlternateSignalStack() { | ||
| 860 | // FIXME: Decide what to do on Windows. | ||
| 861 | } | ||
| 862 | |||
| 863 | void InstallDeadlySignalHandlers(SignalHandlerType handler) { | ||
| 864 | (void)handler; | ||
| 865 | // FIXME: Decide what to do on Windows. | ||
| 866 | } | ||
| 867 | |||
| 868 | HandleSignalMode GetHandleSignalMode(int signum) { | ||
| 869 | // FIXME: Decide what to do on Windows. | ||
| 870 | return kHandleSignalNo; | ||
| 871 | } | ||
| 872 | |||
| 873 | // Check based on flags if we should handle this exception. | ||
| 874 | bool IsHandledDeadlyException(DWORD exceptionCode) { | ||
| 875 | switch (exceptionCode) { | ||
| 876 | case EXCEPTION_ACCESS_VIOLATION: | ||
| 877 | case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: | ||
| 878 | case EXCEPTION_STACK_OVERFLOW: | ||
| 879 | case EXCEPTION_DATATYPE_MISALIGNMENT: | ||
| 880 | case EXCEPTION_IN_PAGE_ERROR: | ||
| 881 | return common_flags()->handle_segv; | ||
| 882 | case EXCEPTION_ILLEGAL_INSTRUCTION: | ||
| 883 | case EXCEPTION_PRIV_INSTRUCTION: | ||
| 884 | case EXCEPTION_BREAKPOINT: | ||
| 885 | return common_flags()->handle_sigill; | ||
| 886 | case EXCEPTION_FLT_DENORMAL_OPERAND: | ||
| 887 | case EXCEPTION_FLT_DIVIDE_BY_ZERO: | ||
| 888 | case EXCEPTION_FLT_INEXACT_RESULT: | ||
| 889 | case EXCEPTION_FLT_INVALID_OPERATION: | ||
| 890 | case EXCEPTION_FLT_OVERFLOW: | ||
| 891 | case EXCEPTION_FLT_STACK_CHECK: | ||
| 892 | case EXCEPTION_FLT_UNDERFLOW: | ||
| 893 | case EXCEPTION_INT_DIVIDE_BY_ZERO: | ||
| 894 | case EXCEPTION_INT_OVERFLOW: | ||
| 895 | return common_flags()->handle_sigfpe; | ||
| 896 | } | ||
| 897 | return false; | ||
| 898 | } | ||
| 899 | |||
| 900 | bool IsAccessibleMemoryRange(uptr beg, uptr size) { | ||
| 901 | SYSTEM_INFO si; | ||
| 902 | GetNativeSystemInfo(&si); | ||
| 903 | uptr page_size = si.dwPageSize; | ||
| 904 | uptr page_mask = ~(page_size - 1); | ||
| 905 | |||
| 906 | for (uptr page = beg & page_mask, end = (beg + size - 1) & page_mask; | ||
| 907 | page <= end;) { | ||
| 908 | MEMORY_BASIC_INFORMATION info; | ||
| 909 | if (VirtualQuery((LPCVOID)page, &info, sizeof(info)) != sizeof(info)) | ||
| 910 | return false; | ||
| 911 | |||
| 912 | if (info.Protect == 0 || info.Protect == PAGE_NOACCESS || | ||
| 913 | info.Protect == PAGE_EXECUTE) | ||
| 914 | return false; | ||
| 915 | |||
| 916 | if (info.RegionSize == 0) | ||
| 917 | return false; | ||
| 918 | |||
| 919 | page += info.RegionSize; | ||
| 920 | } | ||
| 921 | |||
| 922 | return true; | ||
| 923 | } | ||
| 924 | |||
| 925 | bool SignalContext::IsStackOverflow() const { | ||
| 926 | return (DWORD)GetType() == EXCEPTION_STACK_OVERFLOW; | ||
| 927 | } | ||
| 928 | |||
| 929 | void SignalContext::InitPcSpBp() { | ||
| 930 | EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; | ||
| 931 | CONTEXT *context_record = (CONTEXT *)context; | ||
| 932 | |||
| 933 | pc = (uptr)exception_record->ExceptionAddress; | ||
| 934 | #ifdef _WIN64 | ||
| 935 | bp = (uptr)context_record->Rbp; | ||
| 936 | sp = (uptr)context_record->Rsp; | ||
| 937 | #else | ||
| 938 | bp = (uptr)context_record->Ebp; | ||
| 939 | sp = (uptr)context_record->Esp; | ||
| 940 | #endif | ||
| 941 | } | ||
| 942 | |||
| 943 | uptr SignalContext::GetAddress() const { | ||
| 944 | EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; | ||
| 945 | return exception_record->ExceptionInformation[1]; | ||
| 946 | } | ||
| 947 | |||
| 948 | bool SignalContext::IsMemoryAccess() const { | ||
| 949 | return GetWriteFlag() != SignalContext::UNKNOWN; | ||
| 950 | } | ||
| 951 | |||
| 952 | bool SignalContext::IsTrueFaultingAddress() const { | ||
| 953 | // FIXME: Provide real implementation for this. See Linux and Mac variants. | ||
| 954 | return IsMemoryAccess(); | ||
| 955 | } | ||
| 956 | |||
| 957 | SignalContext::WriteFlag SignalContext::GetWriteFlag() const { | ||
| 958 | EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; | ||
| 959 | // The contents of this array are documented at | ||
| 960 | // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx | ||
| 961 | // The first element indicates read as 0, write as 1, or execute as 8. The | ||
| 962 | // second element is the faulting address. | ||
| 963 | switch (exception_record->ExceptionInformation[0]) { | ||
| 964 | case 0: | ||
| 965 | return SignalContext::READ; | ||
| 966 | case 1: | ||
| 967 | return SignalContext::WRITE; | ||
| 968 | case 8: | ||
| 969 | return SignalContext::UNKNOWN; | ||
| 970 | } | ||
| 971 | return SignalContext::UNKNOWN; | ||
| 972 | } | ||
| 973 | |||
| 974 | void SignalContext::DumpAllRegisters(void *context) { | ||
| 975 | // FIXME: Implement this. | ||
| 976 | } | ||
| 977 | |||
| 978 | int SignalContext::GetType() const { | ||
| 979 | return static_cast<const EXCEPTION_RECORD *>(siginfo)->ExceptionCode; | ||
| 980 | } | ||
| 981 | |||
| 982 | const char *SignalContext::Describe() const { | ||
| 983 | unsigned code = GetType(); | ||
| 984 | // Get the string description of the exception if this is a known deadly | ||
| 985 | // exception. | ||
| 986 | switch (code) { | ||
| 987 | case EXCEPTION_ACCESS_VIOLATION: | ||
| 988 | return "access-violation"; | ||
| 989 | case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: | ||
| 990 | return "array-bounds-exceeded"; | ||
| 991 | case EXCEPTION_STACK_OVERFLOW: | ||
| 992 | return "stack-overflow"; | ||
| 993 | case EXCEPTION_DATATYPE_MISALIGNMENT: | ||
| 994 | return "datatype-misalignment"; | ||
| 995 | case EXCEPTION_IN_PAGE_ERROR: | ||
| 996 | return "in-page-error"; | ||
| 997 | case EXCEPTION_ILLEGAL_INSTRUCTION: | ||
| 998 | return "illegal-instruction"; | ||
| 999 | case EXCEPTION_PRIV_INSTRUCTION: | ||
| 1000 | return "priv-instruction"; | ||
| 1001 | case EXCEPTION_BREAKPOINT: | ||
| 1002 | return "breakpoint"; | ||
| 1003 | case EXCEPTION_FLT_DENORMAL_OPERAND: | ||
| 1004 | return "flt-denormal-operand"; | ||
| 1005 | case EXCEPTION_FLT_DIVIDE_BY_ZERO: | ||
| 1006 | return "flt-divide-by-zero"; | ||
| 1007 | case EXCEPTION_FLT_INEXACT_RESULT: | ||
| 1008 | return "flt-inexact-result"; | ||
| 1009 | case EXCEPTION_FLT_INVALID_OPERATION: | ||
| 1010 | return "flt-invalid-operation"; | ||
| 1011 | case EXCEPTION_FLT_OVERFLOW: | ||
| 1012 | return "flt-overflow"; | ||
| 1013 | case EXCEPTION_FLT_STACK_CHECK: | ||
| 1014 | return "flt-stack-check"; | ||
| 1015 | case EXCEPTION_FLT_UNDERFLOW: | ||
| 1016 | return "flt-underflow"; | ||
| 1017 | case EXCEPTION_INT_DIVIDE_BY_ZERO: | ||
| 1018 | return "int-divide-by-zero"; | ||
| 1019 | case EXCEPTION_INT_OVERFLOW: | ||
| 1020 | return "int-overflow"; | ||
| 1021 | } | ||
| 1022 | return "unknown exception"; | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { | ||
| 1026 | // FIXME: Actually implement this function. | ||
| 1027 | CHECK_GT(buf_len, 0); | ||
| 1028 | buf[0] = 0; | ||
| 1029 | return 0; | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { | ||
| 1033 | return ReadBinaryName(buf, buf_len); | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | void CheckVMASize() { | ||
| 1037 | // Do nothing. | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | void InitializePlatformEarly() { | ||
| 1041 | // Do nothing. | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | void MaybeReexec() { | ||
| 1045 | // No need to re-exec on Windows. | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | void CheckASLR() { | ||
| 1049 | // Do nothing | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | void CheckMPROTECT() { | ||
| 1053 | // Do nothing | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | char **GetArgv() { | ||
| 1057 | // FIXME: Actually implement this function. | ||
| 1058 | return 0; | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | char **GetEnviron() { | ||
| 1062 | // FIXME: Actually implement this function. | ||
| 1063 | return 0; | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | pid_t StartSubprocess(const char *program, const char *const argv[], | ||
| 1067 | const char *const envp[], fd_t stdin_fd, fd_t stdout_fd, | ||
| 1068 | fd_t stderr_fd) { | ||
| 1069 | // FIXME: implement on this platform | ||
| 1070 | // Should be implemented based on | ||
| 1071 | // SymbolizerProcess::StarAtSymbolizerSubprocess | ||
| 1072 | // from lib/sanitizer_common/sanitizer_symbolizer_win.cpp. | ||
| 1073 | return -1; | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | bool IsProcessRunning(pid_t pid) { | ||
| 1077 | // FIXME: implement on this platform. | ||
| 1078 | return false; | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | int WaitForProcess(pid_t pid) { return -1; } | ||
| 1082 | |||
| 1083 | // FIXME implement on this platform. | ||
| 1084 | void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { } | ||
| 1085 | |||
| 1086 | void CheckNoDeepBind(const char *filename, int flag) { | ||
| 1087 | // Do nothing. | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | // FIXME: implement on this platform. | ||
| 1091 | bool GetRandom(void *buffer, uptr length, bool blocking) { | ||
| 1092 | UNIMPLEMENTED(); | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | u32 GetNumberOfCPUs() { | ||
| 1096 | SYSTEM_INFO sysinfo = {}; | ||
| 1097 | GetNativeSystemInfo(&sysinfo); | ||
| 1098 | return sysinfo.dwNumberOfProcessors; | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | #if SANITIZER_WIN_TRACE | ||
| 1102 | // TODO(mcgov): Rename this project-wide to PlatformLogInit | ||
| 1103 | void AndroidLogInit(void) { | ||
| 1104 | HRESULT hr = TraceLoggingRegister(g_asan_provider); | ||
| 1105 | if (!SUCCEEDED(hr)) | ||
| 1106 | return; | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | void SetAbortMessage(const char *) {} | ||
| 1110 | |||
| 1111 | void LogFullErrorReport(const char *buffer) { | ||
| 1112 | if (common_flags()->log_to_syslog) { | ||
| 1113 | InternalMmapVector<wchar_t> filename; | ||
| 1114 | DWORD filename_length = 0; | ||
| 1115 | do { | ||
| 1116 | filename.resize(filename.size() + 0x100); | ||
| 1117 | filename_length = | ||
| 1118 | GetModuleFileNameW(NULL, filename.begin(), filename.size()); | ||
| 1119 | } while (filename_length >= filename.size()); | ||
| 1120 | TraceLoggingWrite(g_asan_provider, "AsanReportEvent", | ||
| 1121 | TraceLoggingValue(filename.begin(), "ExecutableName"), | ||
| 1122 | TraceLoggingValue(buffer, "AsanReportContents")); | ||
| 1123 | } | ||
| 1124 | } | ||
| 1125 | #endif // SANITIZER_WIN_TRACE | ||
| 1126 | |||
| 1127 | } // namespace __sanitizer | ||
| 1128 | |||
| 1129 | #endif // _WIN32 | ||
lib/tsan/sanitizer_common/sanitizer_win.h created+25| ... | @@ -0,0 +1,25 @@ | ||
| 1 | //===-- sanitizer_win.h -----------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Windows-specific declarations. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_WIN_H | ||
| 13 | #define SANITIZER_WIN_H | ||
| 14 | |||
| 15 | #include "sanitizer_platform.h" | ||
| 16 | #if SANITIZER_WINDOWS | ||
| 17 | #include "sanitizer_internal_defs.h" | ||
| 18 | |||
| 19 | namespace __sanitizer { | ||
| 20 | // Check based on flags if we should handle the exception. | ||
| 21 | bool IsHandledDeadlyException(DWORD exceptionCode); | ||
| 22 | } // namespace __sanitizer | ||
| 23 | |||
| 24 | #endif // SANITIZER_WINDOWS | ||
| 25 | #endif // SANITIZER_WIN_H | ||
lib/tsan/sanitizer_common/sanitizer_win_defs.h created+174| ... | @@ -0,0 +1,174 @@ | ||
| 1 | //===-- sanitizer_win_defs.h ------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Common definitions for Windows-specific code. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef SANITIZER_WIN_DEFS_H | ||
| 13 | #define SANITIZER_WIN_DEFS_H | ||
| 14 | |||
| 15 | #include "sanitizer_platform.h" | ||
| 16 | #if SANITIZER_WINDOWS | ||
| 17 | |||
| 18 | #ifndef WINAPI | ||
| 19 | #if defined(_M_IX86) || defined(__i386__) | ||
| 20 | #define WINAPI __stdcall | ||
| 21 | #else | ||
| 22 | #define WINAPI | ||
| 23 | #endif | ||
| 24 | #endif | ||
| 25 | |||
| 26 | #if defined(_M_IX86) || defined(__i386__) | ||
| 27 | #define WIN_SYM_PREFIX "_" | ||
| 28 | #else | ||
| 29 | #define WIN_SYM_PREFIX | ||
| 30 | #endif | ||
| 31 | |||
| 32 | // For MinGW, the /export: directives contain undecorated symbols, contrary to | ||
| 33 | // link/lld-link. The GNU linker doesn't support /alternatename and /include | ||
| 34 | // though, thus lld-link in MinGW mode interprets them in the same way as | ||
| 35 | // in the default mode. | ||
| 36 | #ifdef __MINGW32__ | ||
| 37 | #define WIN_EXPORT_PREFIX | ||
| 38 | #else | ||
| 39 | #define WIN_EXPORT_PREFIX WIN_SYM_PREFIX | ||
| 40 | #endif | ||
| 41 | |||
| 42 | // Intermediate macro to ensure the parameter is expanded before stringified. | ||
| 43 | #define STRINGIFY_(A) #A | ||
| 44 | #define STRINGIFY(A) STRINGIFY_(A) | ||
| 45 | |||
| 46 | #if !SANITIZER_GO | ||
| 47 | |||
| 48 | // ----------------- A workaround for the absence of weak symbols -------------- | ||
| 49 | // We don't have a direct equivalent of weak symbols when using MSVC, but we can | ||
| 50 | // use the /alternatename directive to tell the linker to default a specific | ||
| 51 | // symbol to a specific value. | ||
| 52 | // Take into account that this is a pragma directive for the linker, so it will | ||
| 53 | // be ignored by the compiler and the function will be marked as UNDEF in the | ||
| 54 | // symbol table of the resulting object file. The linker won't find the default | ||
| 55 | // implementation until it links with that object file. | ||
| 56 | // So, suppose we provide a default implementation "fundef" for "fun", and this | ||
| 57 | // is compiled into the object file "test.obj" including the pragma directive. | ||
| 58 | // If we have some code with references to "fun" and we link that code with | ||
| 59 | // "test.obj", it will work because the linker always link object files. | ||
| 60 | // But, if "test.obj" is included in a static library, like "test.lib", then the | ||
| 61 | // liker will only link to "test.obj" if necessary. If we only included the | ||
| 62 | // definition of "fun", it won't link to "test.obj" (from test.lib) because | ||
| 63 | // "fun" appears as UNDEF, so it doesn't resolve the symbol "fun", and will | ||
| 64 | // result in a link error (the linker doesn't find the pragma directive). | ||
| 65 | // So, a workaround is to force linkage with the modules that include weak | ||
| 66 | // definitions, with the following macro: WIN_FORCE_LINK() | ||
| 67 | |||
| 68 | #define WIN_WEAK_ALIAS(Name, Default) \ | ||
| 69 | __pragma(comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY(Name) "="\ | ||
| 70 | WIN_SYM_PREFIX STRINGIFY(Default))) | ||
| 71 | |||
| 72 | #define WIN_FORCE_LINK(Name) \ | ||
| 73 | __pragma(comment(linker, "/include:" WIN_SYM_PREFIX STRINGIFY(Name))) | ||
| 74 | |||
| 75 | #define WIN_EXPORT(ExportedName, Name) \ | ||
| 76 | __pragma(comment(linker, "/export:" WIN_EXPORT_PREFIX STRINGIFY(ExportedName)\ | ||
| 77 | "=" WIN_EXPORT_PREFIX STRINGIFY(Name))) | ||
| 78 | |||
| 79 | // We cannot define weak functions on Windows, but we can use WIN_WEAK_ALIAS() | ||
| 80 | // which defines an alias to a default implementation, and only works when | ||
| 81 | // linking statically. | ||
| 82 | // So, to define a weak function "fun", we define a default implementation with | ||
| 83 | // a different name "fun__def" and we create a "weak alias" fun = fun__def. | ||
| 84 | // Then, users can override it just defining "fun". | ||
| 85 | // We impose "extern "C"" because otherwise WIN_WEAK_ALIAS() will fail because | ||
| 86 | // of name mangling. | ||
| 87 | |||
| 88 | // Dummy name for default implementation of weak function. | ||
| 89 | # define WEAK_DEFAULT_NAME(Name) Name##__def | ||
| 90 | // Name for exported implementation of weak function. | ||
| 91 | # define WEAK_EXPORT_NAME(Name) Name##__dll | ||
| 92 | |||
| 93 | // Use this macro when you need to define and export a weak function from a | ||
| 94 | // library. For example: | ||
| 95 | // WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; } | ||
| 96 | # define WIN_WEAK_EXPORT_DEF(ReturnType, Name, ...) \ | ||
| 97 | WIN_WEAK_ALIAS(Name, WEAK_DEFAULT_NAME(Name)) \ | ||
| 98 | WIN_EXPORT(WEAK_EXPORT_NAME(Name), Name) \ | ||
| 99 | extern "C" ReturnType Name(__VA_ARGS__); \ | ||
| 100 | extern "C" ReturnType WEAK_DEFAULT_NAME(Name)(__VA_ARGS__) | ||
| 101 | |||
| 102 | // Use this macro when you need to import a weak function from a library. It | ||
| 103 | // defines a weak alias to the imported function from the dll. For example: | ||
| 104 | // WIN_WEAK_IMPORT_DEF(compare) | ||
| 105 | # define WIN_WEAK_IMPORT_DEF(Name) \ | ||
| 106 | WIN_WEAK_ALIAS(Name, WEAK_EXPORT_NAME(Name)) | ||
| 107 | |||
| 108 | // So, for Windows we provide something similar to weak symbols in Linux, with | ||
| 109 | // some differences: | ||
| 110 | // + A default implementation must always be provided. | ||
| 111 | // | ||
| 112 | // + When linking statically it works quite similarly. For example: | ||
| 113 | // | ||
| 114 | // // libExample.cc | ||
| 115 | // WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; } | ||
| 116 | // | ||
| 117 | // // client.cc | ||
| 118 | // // We can use the default implementation from the library: | ||
| 119 | // compare(1, 2); | ||
| 120 | // // Or we can override it: | ||
| 121 | // extern "C" bool compare (int a, int b) { return a >= b; } | ||
| 122 | // | ||
| 123 | // And it will work fine. If we don't override the function, we need to ensure | ||
| 124 | // that the linker includes the object file with the default implementation. | ||
| 125 | // We can do so with the linker option "-wholearchive:". | ||
| 126 | // | ||
| 127 | // + When linking dynamically with a library (dll), weak functions are exported | ||
| 128 | // with "__dll" suffix. Clients can use the macro WIN_WEAK_IMPORT_DEF(fun) | ||
| 129 | // which defines a "weak alias" fun = fun__dll. | ||
| 130 | // | ||
| 131 | // // libExample.cc | ||
| 132 | // WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; } | ||
| 133 | // | ||
| 134 | // // client.cc | ||
| 135 | // WIN_WEAK_IMPORT_DEF(compare) | ||
| 136 | // // We can use the default implementation from the library: | ||
| 137 | // compare(1, 2); | ||
| 138 | // // Or we can override it: | ||
| 139 | // extern "C" bool compare (int a, int b) { return a >= b; } | ||
| 140 | // | ||
| 141 | // But if we override the function, the dlls don't have access to it (which | ||
| 142 | // is different in linux). If that is desired, the strong definition must be | ||
| 143 | // exported and interception can be used from the rest of the dlls. | ||
| 144 | // | ||
| 145 | // // libExample.cc | ||
| 146 | // WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; } | ||
| 147 | // // When initialized, check if the main executable defined "compare". | ||
| 148 | // int libExample_init() { | ||
| 149 | // uptr fnptr = __interception::InternalGetProcAddress( | ||
| 150 | // (void *)GetModuleHandleA(0), "compare"); | ||
| 151 | // if (fnptr && !__interception::OverrideFunction((uptr)compare, fnptr, 0)) | ||
| 152 | // abort(); | ||
| 153 | // return 0; | ||
| 154 | // } | ||
| 155 | // | ||
| 156 | // // client.cc | ||
| 157 | // WIN_WEAK_IMPORT_DEF(compare) | ||
| 158 | // // We override and export compare: | ||
| 159 | // extern "C" __declspec(dllexport) bool compare (int a, int b) { | ||
| 160 | // return a >= b; | ||
| 161 | // } | ||
| 162 | // | ||
| 163 | |||
| 164 | #else // SANITIZER_GO | ||
| 165 | |||
| 166 | // Go neither needs nor wants weak references. | ||
| 167 | // The shenanigans above don't work for gcc. | ||
| 168 | # define WIN_WEAK_EXPORT_DEF(ReturnType, Name, ...) \ | ||
| 169 | extern "C" ReturnType Name(__VA_ARGS__) | ||
| 170 | |||
| 171 | #endif // SANITIZER_GO | ||
| 172 | |||
| 173 | #endif // SANITIZER_WINDOWS | ||
| 174 | #endif // SANITIZER_WIN_DEFS_H | ||
lib/tsan/sanitizer_common/sanitizer_win_dll_thunk.h created+181| ... | @@ -0,0 +1,181 @@ | ||
| 1 | //===-- sanitizer_win_dll_thunk.h -----------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // This header provide helper macros to delegate calls to the shared runtime | ||
| 9 | // that lives in the main executable. It should be included to dll_thunks that | ||
| 10 | // will be linked to the dlls, when the sanitizer is a static library included | ||
| 11 | // in the main executable. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | #ifndef SANITIZER_WIN_DLL_THUNK_H | ||
| 14 | #define SANITIZER_WIN_DLL_THUNK_H | ||
| 15 | #include "sanitizer_internal_defs.h" | ||
| 16 | |||
| 17 | namespace __sanitizer { | ||
| 18 | uptr dllThunkGetRealAddrOrDie(const char *name); | ||
| 19 | |||
| 20 | int dllThunkIntercept(const char* main_function, uptr dll_function); | ||
| 21 | |||
| 22 | int dllThunkInterceptWhenPossible(const char* main_function, | ||
| 23 | const char* default_function, uptr dll_function); | ||
| 24 | } | ||
| 25 | |||
| 26 | extern "C" int __dll_thunk_init(); | ||
| 27 | |||
| 28 | // ----------------- Function interception helper macros -------------------- // | ||
| 29 | // Override dll_function with main_function from main executable. | ||
| 30 | #define INTERCEPT_OR_DIE(main_function, dll_function) \ | ||
| 31 | static int intercept_##dll_function() { \ | ||
| 32 | return __sanitizer::dllThunkIntercept(main_function, (__sanitizer::uptr) \ | ||
| 33 | dll_function); \ | ||
| 34 | } \ | ||
| 35 | __pragma(section(".DLLTH$M", long, read)) \ | ||
| 36 | __declspec(allocate(".DLLTH$M")) int (*__dll_thunk_##dll_function)() = \ | ||
| 37 | intercept_##dll_function; | ||
| 38 | |||
| 39 | // Try to override dll_function with main_function from main executable. | ||
| 40 | // If main_function is not present, override dll_function with default_function. | ||
| 41 | #define INTERCEPT_WHEN_POSSIBLE(main_function, default_function, dll_function) \ | ||
| 42 | static int intercept_##dll_function() { \ | ||
| 43 | return __sanitizer::dllThunkInterceptWhenPossible(main_function, \ | ||
| 44 | default_function, (__sanitizer::uptr)dll_function); \ | ||
| 45 | } \ | ||
| 46 | __pragma(section(".DLLTH$M", long, read)) \ | ||
| 47 | __declspec(allocate(".DLLTH$M")) int (*__dll_thunk_##dll_function)() = \ | ||
| 48 | intercept_##dll_function; | ||
| 49 | |||
| 50 | // -------------------- Function interception macros ------------------------ // | ||
| 51 | // Special case of hooks -- ASan own interface functions. Those are only called | ||
| 52 | // after __asan_init, thus an empty implementation is sufficient. | ||
| 53 | #define INTERCEPT_SANITIZER_FUNCTION(name) \ | ||
| 54 | extern "C" __declspec(noinline) void name() { \ | ||
| 55 | volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__; \ | ||
| 56 | static const char function_name[] = #name; \ | ||
| 57 | for (const char* ptr = &function_name[0]; *ptr; ++ptr) \ | ||
| 58 | prevent_icf ^= *ptr; \ | ||
| 59 | (void)prevent_icf; \ | ||
| 60 | __debugbreak(); \ | ||
| 61 | } \ | ||
| 62 | INTERCEPT_OR_DIE(#name, name) | ||
| 63 | |||
| 64 | // Special case of hooks -- Weak functions, could be redefined in the main | ||
| 65 | // executable, but that is not necessary, so we shouldn't die if we can not find | ||
| 66 | // a reference. Instead, when the function is not present in the main executable | ||
| 67 | // we consider the default impl provided by asan library. | ||
| 68 | #define INTERCEPT_SANITIZER_WEAK_FUNCTION(name) \ | ||
| 69 | extern "C" __declspec(noinline) void name() { \ | ||
| 70 | volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__; \ | ||
| 71 | static const char function_name[] = #name; \ | ||
| 72 | for (const char* ptr = &function_name[0]; *ptr; ++ptr) \ | ||
| 73 | prevent_icf ^= *ptr; \ | ||
| 74 | (void)prevent_icf; \ | ||
| 75 | __debugbreak(); \ | ||
| 76 | } \ | ||
| 77 | INTERCEPT_WHEN_POSSIBLE(#name, STRINGIFY(WEAK_EXPORT_NAME(name)), name) | ||
| 78 | |||
| 79 | // We can't define our own version of strlen etc. because that would lead to | ||
| 80 | // link-time or even type mismatch errors. Instead, we can declare a function | ||
| 81 | // just to be able to get its address. Me may miss the first few calls to the | ||
| 82 | // functions since it can be called before __dll_thunk_init, but that would lead | ||
| 83 | // to false negatives in the startup code before user's global initializers, | ||
| 84 | // which isn't a big deal. | ||
| 85 | #define INTERCEPT_LIBRARY_FUNCTION(name) \ | ||
| 86 | extern "C" void name(); \ | ||
| 87 | INTERCEPT_OR_DIE(WRAPPER_NAME(name), name) | ||
| 88 | |||
| 89 | // Use these macros for functions that could be called before __dll_thunk_init() | ||
| 90 | // is executed and don't lead to errors if defined (free, malloc, etc). | ||
| 91 | #define INTERCEPT_WRAP_V_V(name) \ | ||
| 92 | extern "C" void name() { \ | ||
| 93 | typedef decltype(name) *fntype; \ | ||
| 94 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | ||
| 95 | fn(); \ | ||
| 96 | } \ | ||
| 97 | INTERCEPT_OR_DIE(#name, name); | ||
| 98 | |||
| 99 | #define INTERCEPT_WRAP_V_W(name) \ | ||
| 100 | extern "C" void name(void *arg) { \ | ||
| 101 | typedef decltype(name) *fntype; \ | ||
| 102 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | ||
| 103 | fn(arg); \ | ||
| 104 | } \ | ||
| 105 | INTERCEPT_OR_DIE(#name, name); | ||
| 106 | |||
| 107 | #define INTERCEPT_WRAP_V_WW(name) \ | ||
| 108 | extern "C" void name(void *arg1, void *arg2) { \ | ||
| 109 | typedef decltype(name) *fntype; \ | ||
| 110 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | ||
| 111 | fn(arg1, arg2); \ | ||
| 112 | } \ | ||
| 113 | INTERCEPT_OR_DIE(#name, name); | ||
| 114 | |||
| 115 | #define INTERCEPT_WRAP_V_WWW(name) \ | ||
| 116 | extern "C" void name(void *arg1, void *arg2, void *arg3) { \ | ||
| 117 | typedef decltype(name) *fntype; \ | ||
| 118 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | ||
| 119 | fn(arg1, arg2, arg3); \ | ||
| 120 | } \ | ||
| 121 | INTERCEPT_OR_DIE(#name, name); | ||
| 122 | |||
| 123 | #define INTERCEPT_WRAP_W_V(name) \ | ||
| 124 | extern "C" void *name() { \ | ||
| 125 | typedef decltype(name) *fntype; \ | ||
| 126 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | ||
| 127 | return fn(); \ | ||
| 128 | } \ | ||
| 129 | INTERCEPT_OR_DIE(#name, name); | ||
| 130 | |||
| 131 | #define INTERCEPT_WRAP_W_W(name) \ | ||
| 132 | extern "C" void *name(void *arg) { \ | ||
| 133 | typedef decltype(name) *fntype; \ | ||
| 134 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | ||
| 135 | return fn(arg); \ | ||
| 136 | } \ | ||
| 137 | INTERCEPT_OR_DIE(#name, name); | ||
| 138 | |||
| 139 | #define INTERCEPT_WRAP_W_WW(name) \ | ||
| 140 | extern "C" void *name(void *arg1, void *arg2) { \ | ||
| 141 | typedef decltype(name) *fntype; \ | ||
| 142 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | ||
| 143 | return fn(arg1, arg2); \ | ||
| 144 | } \ | ||
| 145 | INTERCEPT_OR_DIE(#name, name); | ||
| 146 | |||
| 147 | #define INTERCEPT_WRAP_W_WWW(name) \ | ||
| 148 | extern "C" void *name(void *arg1, void *arg2, void *arg3) { \ | ||
| 149 | typedef decltype(name) *fntype; \ | ||
| 150 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | ||
| 151 | return fn(arg1, arg2, arg3); \ | ||
| 152 | } \ | ||
| 153 | INTERCEPT_OR_DIE(#name, name); | ||
| 154 | |||
| 155 | #define INTERCEPT_WRAP_W_WWWW(name) \ | ||
| 156 | extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \ | ||
| 157 | typedef decltype(name) *fntype; \ | ||
| 158 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | ||
| 159 | return fn(arg1, arg2, arg3, arg4); \ | ||
| 160 | } \ | ||
| 161 | INTERCEPT_OR_DIE(#name, name); | ||
| 162 | |||
| 163 | #define INTERCEPT_WRAP_W_WWWWW(name) \ | ||
| 164 | extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ | ||
| 165 | void *arg5) { \ | ||
| 166 | typedef decltype(name) *fntype; \ | ||
| 167 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | ||
| 168 | return fn(arg1, arg2, arg3, arg4, arg5); \ | ||
| 169 | } \ | ||
| 170 | INTERCEPT_OR_DIE(#name, name); | ||
| 171 | |||
| 172 | #define INTERCEPT_WRAP_W_WWWWWW(name) \ | ||
| 173 | extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ | ||
| 174 | void *arg5, void *arg6) { \ | ||
| 175 | typedef decltype(name) *fntype; \ | ||
| 176 | static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ | ||
| 177 | return fn(arg1, arg2, arg3, arg4, arg5, arg6); \ | ||
| 178 | } \ | ||
| 179 | INTERCEPT_OR_DIE(#name, name); | ||
| 180 | |||
| 181 | #endif // SANITIZER_WIN_DLL_THUNK_H | ||
lib/tsan/sanitizer_common/sanitizer_win_weak_interception.h created+32| ... | @@ -0,0 +1,32 @@ | ||
| 1 | //===-- sanitizer_win_weak_interception.h ---------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // This header provide helper macros to delegate calls of weak functions to the | ||
| 9 | // implementation in the main executable when a strong definition is present. | ||
| 10 | //===----------------------------------------------------------------------===// | ||
| 11 | #ifndef SANITIZER_WIN_WEAK_INTERCEPTION_H | ||
| 12 | #define SANITIZER_WIN_WEAK_INTERCEPTION_H | ||
| 13 | #include "sanitizer_internal_defs.h" | ||
| 14 | |||
| 15 | namespace __sanitizer { | ||
| 16 | int interceptWhenPossible(uptr dll_function, const char *real_function); | ||
| 17 | } | ||
| 18 | |||
| 19 | // ----------------- Function interception helper macros -------------------- // | ||
| 20 | // Weak functions, could be redefined in the main executable, but that is not | ||
| 21 | // necessary, so we shouldn't die if we can not find a reference. | ||
| 22 | #define INTERCEPT_WEAK(Name) interceptWhenPossible((uptr) Name, #Name); | ||
| 23 | |||
| 24 | #define INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) \ | ||
| 25 | static int intercept_##Name() { \ | ||
| 26 | return __sanitizer::interceptWhenPossible((__sanitizer::uptr) Name, #Name);\ | ||
| 27 | } \ | ||
| 28 | __pragma(section(".WEAK$M", long, read)) \ | ||
| 29 | __declspec(allocate(".WEAK$M")) int (*__weak_intercept_##Name)() = \ | ||
| 30 | intercept_##Name; | ||
| 31 | |||
| 32 | #endif // SANITIZER_WIN_WEAK_INTERCEPTION_H | ||
lib/tsan/tsan_clock.cpp created+655| ... | @@ -0,0 +1,655 @@ | ||
| 1 | //===-- tsan_clock.cpp ----------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #include "tsan_clock.h" | ||
| 13 | #include "tsan_rtl.h" | ||
| 14 | #include "sanitizer_common/sanitizer_placement_new.h" | ||
| 15 | |||
| 16 | // SyncClock and ThreadClock implement vector clocks for sync variables | ||
| 17 | // (mutexes, atomic variables, file descriptors, etc) and threads, respectively. | ||
| 18 | // ThreadClock contains fixed-size vector clock for maximum number of threads. | ||
| 19 | // SyncClock contains growable vector clock for currently necessary number of | ||
| 20 | // threads. | ||
| 21 | // Together they implement very simple model of operations, namely: | ||
| 22 | // | ||
| 23 | // void ThreadClock::acquire(const SyncClock *src) { | ||
| 24 | // for (int i = 0; i < kMaxThreads; i++) | ||
| 25 | // clock[i] = max(clock[i], src->clock[i]); | ||
| 26 | // } | ||
| 27 | // | ||
| 28 | // void ThreadClock::release(SyncClock *dst) const { | ||
| 29 | // for (int i = 0; i < kMaxThreads; i++) | ||
| 30 | // dst->clock[i] = max(dst->clock[i], clock[i]); | ||
| 31 | // } | ||
| 32 | // | ||
| 33 | // void ThreadClock::releaseStoreAcquire(SyncClock *sc) const { | ||
| 34 | // for (int i = 0; i < kMaxThreads; i++) { | ||
| 35 | // tmp = clock[i]; | ||
| 36 | // clock[i] = max(clock[i], sc->clock[i]); | ||
| 37 | // sc->clock[i] = tmp; | ||
| 38 | // } | ||
| 39 | // } | ||
| 40 | // | ||
| 41 | // void ThreadClock::ReleaseStore(SyncClock *dst) const { | ||
| 42 | // for (int i = 0; i < kMaxThreads; i++) | ||
| 43 | // dst->clock[i] = clock[i]; | ||
| 44 | // } | ||
| 45 | // | ||
| 46 | // void ThreadClock::acq_rel(SyncClock *dst) { | ||
| 47 | // acquire(dst); | ||
| 48 | // release(dst); | ||
| 49 | // } | ||
| 50 | // | ||
| 51 | // Conformance to this model is extensively verified in tsan_clock_test.cpp. | ||
| 52 | // However, the implementation is significantly more complex. The complexity | ||
| 53 | // allows to implement important classes of use cases in O(1) instead of O(N). | ||
| 54 | // | ||
| 55 | // The use cases are: | ||
| 56 | // 1. Singleton/once atomic that has a single release-store operation followed | ||
| 57 | // by zillions of acquire-loads (the acquire-load is O(1)). | ||
| 58 | // 2. Thread-local mutex (both lock and unlock can be O(1)). | ||
| 59 | // 3. Leaf mutex (unlock is O(1)). | ||
| 60 | // 4. A mutex shared by 2 threads (both lock and unlock can be O(1)). | ||
| 61 | // 5. An atomic with a single writer (writes can be O(1)). | ||
| 62 | // The implementation dynamically adopts to workload. So if an atomic is in | ||
| 63 | // read-only phase, these reads will be O(1); if it later switches to read/write | ||
| 64 | // phase, the implementation will correctly handle that by switching to O(N). | ||
| 65 | // | ||
| 66 | // Thread-safety note: all const operations on SyncClock's are conducted under | ||
| 67 | // a shared lock; all non-const operations on SyncClock's are conducted under | ||
| 68 | // an exclusive lock; ThreadClock's are private to respective threads and so | ||
| 69 | // do not need any protection. | ||
| 70 | // | ||
| 71 | // Description of SyncClock state: | ||
| 72 | // clk_ - variable size vector clock, low kClkBits hold timestamp, | ||
| 73 | // the remaining bits hold "acquired" flag (the actual value is thread's | ||
| 74 | // reused counter); | ||
| 75 | // if acquried == thr->reused_, then the respective thread has already | ||
| 76 | // acquired this clock (except possibly for dirty elements). | ||
| 77 | // dirty_ - holds up to two indeces in the vector clock that other threads | ||
| 78 | // need to acquire regardless of "acquired" flag value; | ||
| 79 | // release_store_tid_ - denotes that the clock state is a result of | ||
| 80 | // release-store operation by the thread with release_store_tid_ index. | ||
| 81 | // release_store_reused_ - reuse count of release_store_tid_. | ||
| 82 | |||
| 83 | // We don't have ThreadState in these methods, so this is an ugly hack that | ||
| 84 | // works only in C++. | ||
| 85 | #if !SANITIZER_GO | ||
| 86 | # define CPP_STAT_INC(typ) StatInc(cur_thread(), typ) | ||
| 87 | #else | ||
| 88 | # define CPP_STAT_INC(typ) (void)0 | ||
| 89 | #endif | ||
| 90 | |||
| 91 | namespace __tsan { | ||
| 92 | |||
| 93 | static atomic_uint32_t *ref_ptr(ClockBlock *cb) { | ||
| 94 | return reinterpret_cast<atomic_uint32_t *>(&cb->table[ClockBlock::kRefIdx]); | ||
| 95 | } | ||
| 96 | |||
| 97 | // Drop reference to the first level block idx. | ||
| 98 | static void UnrefClockBlock(ClockCache *c, u32 idx, uptr blocks) { | ||
| 99 | ClockBlock *cb = ctx->clock_alloc.Map(idx); | ||
| 100 | atomic_uint32_t *ref = ref_ptr(cb); | ||
| 101 | u32 v = atomic_load(ref, memory_order_acquire); | ||
| 102 | for (;;) { | ||
| 103 | CHECK_GT(v, 0); | ||
| 104 | if (v == 1) | ||
| 105 | break; | ||
| 106 | if (atomic_compare_exchange_strong(ref, &v, v - 1, memory_order_acq_rel)) | ||
| 107 | return; | ||
| 108 | } | ||
| 109 | // First level block owns second level blocks, so them as well. | ||
| 110 | for (uptr i = 0; i < blocks; i++) | ||
| 111 | ctx->clock_alloc.Free(c, cb->table[ClockBlock::kBlockIdx - i]); | ||
| 112 | ctx->clock_alloc.Free(c, idx); | ||
| 113 | } | ||
| 114 | |||
| 115 | ThreadClock::ThreadClock(unsigned tid, unsigned reused) | ||
| 116 | : tid_(tid) | ||
| 117 | , reused_(reused + 1) // 0 has special meaning | ||
| 118 | , last_acquire_() | ||
| 119 | , global_acquire_() | ||
| 120 | , cached_idx_() | ||
| 121 | , cached_size_() | ||
| 122 | , cached_blocks_() { | ||
| 123 | CHECK_LT(tid, kMaxTidInClock); | ||
| 124 | CHECK_EQ(reused_, ((u64)reused_ << kClkBits) >> kClkBits); | ||
| 125 | nclk_ = tid_ + 1; | ||
| 126 | internal_memset(clk_, 0, sizeof(clk_)); | ||
| 127 | } | ||
| 128 | |||
| 129 | void ThreadClock::ResetCached(ClockCache *c) { | ||
| 130 | if (cached_idx_) { | ||
| 131 | UnrefClockBlock(c, cached_idx_, cached_blocks_); | ||
| 132 | cached_idx_ = 0; | ||
| 133 | cached_size_ = 0; | ||
| 134 | cached_blocks_ = 0; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | void ThreadClock::acquire(ClockCache *c, SyncClock *src) { | ||
| 139 | DCHECK_LE(nclk_, kMaxTid); | ||
| 140 | DCHECK_LE(src->size_, kMaxTid); | ||
| 141 | CPP_STAT_INC(StatClockAcquire); | ||
| 142 | |||
| 143 | // Check if it's empty -> no need to do anything. | ||
| 144 | const uptr nclk = src->size_; | ||
| 145 | if (nclk == 0) { | ||
| 146 | CPP_STAT_INC(StatClockAcquireEmpty); | ||
| 147 | return; | ||
| 148 | } | ||
| 149 | |||
| 150 | bool acquired = false; | ||
| 151 | for (unsigned i = 0; i < kDirtyTids; i++) { | ||
| 152 | SyncClock::Dirty dirty = src->dirty_[i]; | ||
| 153 | unsigned tid = dirty.tid; | ||
| 154 | if (tid != kInvalidTid) { | ||
| 155 | if (clk_[tid] < dirty.epoch) { | ||
| 156 | clk_[tid] = dirty.epoch; | ||
| 157 | acquired = true; | ||
| 158 | } | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | // Check if we've already acquired src after the last release operation on src | ||
| 163 | if (tid_ >= nclk || src->elem(tid_).reused != reused_) { | ||
| 164 | // O(N) acquire. | ||
| 165 | CPP_STAT_INC(StatClockAcquireFull); | ||
| 166 | nclk_ = max(nclk_, nclk); | ||
| 167 | u64 *dst_pos = &clk_[0]; | ||
| 168 | for (ClockElem &src_elem : *src) { | ||
| 169 | u64 epoch = src_elem.epoch; | ||
| 170 | if (*dst_pos < epoch) { | ||
| 171 | *dst_pos = epoch; | ||
| 172 | acquired = true; | ||
| 173 | } | ||
| 174 | dst_pos++; | ||
| 175 | } | ||
| 176 | |||
| 177 | // Remember that this thread has acquired this clock. | ||
| 178 | if (nclk > tid_) | ||
| 179 | src->elem(tid_).reused = reused_; | ||
| 180 | } | ||
| 181 | |||
| 182 | if (acquired) { | ||
| 183 | CPP_STAT_INC(StatClockAcquiredSomething); | ||
| 184 | last_acquire_ = clk_[tid_]; | ||
| 185 | ResetCached(c); | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | void ThreadClock::releaseStoreAcquire(ClockCache *c, SyncClock *sc) { | ||
| 190 | DCHECK_LE(nclk_, kMaxTid); | ||
| 191 | DCHECK_LE(sc->size_, kMaxTid); | ||
| 192 | |||
| 193 | if (sc->size_ == 0) { | ||
| 194 | // ReleaseStore will correctly set release_store_tid_, | ||
| 195 | // which can be important for future operations. | ||
| 196 | ReleaseStore(c, sc); | ||
| 197 | return; | ||
| 198 | } | ||
| 199 | |||
| 200 | nclk_ = max(nclk_, (uptr) sc->size_); | ||
| 201 | |||
| 202 | // Check if we need to resize sc. | ||
| 203 | if (sc->size_ < nclk_) | ||
| 204 | sc->Resize(c, nclk_); | ||
| 205 | |||
| 206 | bool acquired = false; | ||
| 207 | |||
| 208 | sc->Unshare(c); | ||
| 209 | // Update sc->clk_. | ||
| 210 | sc->FlushDirty(); | ||
| 211 | uptr i = 0; | ||
| 212 | for (ClockElem &ce : *sc) { | ||
| 213 | u64 tmp = clk_[i]; | ||
| 214 | if (clk_[i] < ce.epoch) { | ||
| 215 | clk_[i] = ce.epoch; | ||
| 216 | acquired = true; | ||
| 217 | } | ||
| 218 | ce.epoch = tmp; | ||
| 219 | ce.reused = 0; | ||
| 220 | i++; | ||
| 221 | } | ||
| 222 | sc->release_store_tid_ = kInvalidTid; | ||
| 223 | sc->release_store_reused_ = 0; | ||
| 224 | |||
| 225 | if (acquired) { | ||
| 226 | CPP_STAT_INC(StatClockAcquiredSomething); | ||
| 227 | last_acquire_ = clk_[tid_]; | ||
| 228 | ResetCached(c); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | void ThreadClock::release(ClockCache *c, SyncClock *dst) { | ||
| 233 | DCHECK_LE(nclk_, kMaxTid); | ||
| 234 | DCHECK_LE(dst->size_, kMaxTid); | ||
| 235 | |||
| 236 | if (dst->size_ == 0) { | ||
| 237 | // ReleaseStore will correctly set release_store_tid_, | ||
| 238 | // which can be important for future operations. | ||
| 239 | ReleaseStore(c, dst); | ||
| 240 | return; | ||
| 241 | } | ||
| 242 | |||
| 243 | CPP_STAT_INC(StatClockRelease); | ||
| 244 | // Check if we need to resize dst. | ||
| 245 | if (dst->size_ < nclk_) | ||
| 246 | dst->Resize(c, nclk_); | ||
| 247 | |||
| 248 | // Check if we had not acquired anything from other threads | ||
| 249 | // since the last release on dst. If so, we need to update | ||
| 250 | // only dst->elem(tid_). | ||
| 251 | if (!HasAcquiredAfterRelease(dst)) { | ||
| 252 | UpdateCurrentThread(c, dst); | ||
| 253 | if (dst->release_store_tid_ != tid_ || | ||
| 254 | dst->release_store_reused_ != reused_) | ||
| 255 | dst->release_store_tid_ = kInvalidTid; | ||
| 256 | return; | ||
| 257 | } | ||
| 258 | |||
| 259 | // O(N) release. | ||
| 260 | CPP_STAT_INC(StatClockReleaseFull); | ||
| 261 | dst->Unshare(c); | ||
| 262 | // First, remember whether we've acquired dst. | ||
| 263 | bool acquired = IsAlreadyAcquired(dst); | ||
| 264 | if (acquired) | ||
| 265 | CPP_STAT_INC(StatClockReleaseAcquired); | ||
| 266 | // Update dst->clk_. | ||
| 267 | dst->FlushDirty(); | ||
| 268 | uptr i = 0; | ||
| 269 | for (ClockElem &ce : *dst) { | ||
| 270 | ce.epoch = max(ce.epoch, clk_[i]); | ||
| 271 | ce.reused = 0; | ||
| 272 | i++; | ||
| 273 | } | ||
| 274 | // Clear 'acquired' flag in the remaining elements. | ||
| 275 | if (nclk_ < dst->size_) | ||
| 276 | CPP_STAT_INC(StatClockReleaseClearTail); | ||
| 277 | dst->release_store_tid_ = kInvalidTid; | ||
| 278 | dst->release_store_reused_ = 0; | ||
| 279 | // If we've acquired dst, remember this fact, | ||
| 280 | // so that we don't need to acquire it on next acquire. | ||
| 281 | if (acquired) | ||
| 282 | dst->elem(tid_).reused = reused_; | ||
| 283 | } | ||
| 284 | |||
| 285 | void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) { | ||
| 286 | DCHECK_LE(nclk_, kMaxTid); | ||
| 287 | DCHECK_LE(dst->size_, kMaxTid); | ||
| 288 | CPP_STAT_INC(StatClockStore); | ||
| 289 | |||
| 290 | if (dst->size_ == 0 && cached_idx_ != 0) { | ||
| 291 | // Reuse the cached clock. | ||
| 292 | // Note: we could reuse/cache the cached clock in more cases: | ||
| 293 | // we could update the existing clock and cache it, or replace it with the | ||
| 294 | // currently cached clock and release the old one. And for a shared | ||
| 295 | // existing clock, we could replace it with the currently cached; | ||
| 296 | // or unshare, update and cache. But, for simplicity, we currnetly reuse | ||
| 297 | // cached clock only when the target clock is empty. | ||
| 298 | dst->tab_ = ctx->clock_alloc.Map(cached_idx_); | ||
| 299 | dst->tab_idx_ = cached_idx_; | ||
| 300 | dst->size_ = cached_size_; | ||
| 301 | dst->blocks_ = cached_blocks_; | ||
| 302 | CHECK_EQ(dst->dirty_[0].tid, kInvalidTid); | ||
| 303 | // The cached clock is shared (immutable), | ||
| 304 | // so this is where we store the current clock. | ||
| 305 | dst->dirty_[0].tid = tid_; | ||
| 306 | dst->dirty_[0].epoch = clk_[tid_]; | ||
| 307 | dst->release_store_tid_ = tid_; | ||
| 308 | dst->release_store_reused_ = reused_; | ||
| 309 | // Rememeber that we don't need to acquire it in future. | ||
| 310 | dst->elem(tid_).reused = reused_; | ||
| 311 | // Grab a reference. | ||
| 312 | atomic_fetch_add(ref_ptr(dst->tab_), 1, memory_order_relaxed); | ||
| 313 | return; | ||
| 314 | } | ||
| 315 | |||
| 316 | // Check if we need to resize dst. | ||
| 317 | if (dst->size_ < nclk_) | ||
| 318 | dst->Resize(c, nclk_); | ||
| 319 | |||
| 320 | if (dst->release_store_tid_ == tid_ && | ||
| 321 | dst->release_store_reused_ == reused_ && | ||
| 322 | !HasAcquiredAfterRelease(dst)) { | ||
| 323 | CPP_STAT_INC(StatClockStoreFast); | ||
| 324 | UpdateCurrentThread(c, dst); | ||
| 325 | return; | ||
| 326 | } | ||
| 327 | |||
| 328 | // O(N) release-store. | ||
| 329 | CPP_STAT_INC(StatClockStoreFull); | ||
| 330 | dst->Unshare(c); | ||
| 331 | // Note: dst can be larger than this ThreadClock. | ||
| 332 | // This is fine since clk_ beyond size is all zeros. | ||
| 333 | uptr i = 0; | ||
| 334 | for (ClockElem &ce : *dst) { | ||
| 335 | ce.epoch = clk_[i]; | ||
| 336 | ce.reused = 0; | ||
| 337 | i++; | ||
| 338 | } | ||
| 339 | for (uptr i = 0; i < kDirtyTids; i++) | ||
| 340 | dst->dirty_[i].tid = kInvalidTid; | ||
| 341 | dst->release_store_tid_ = tid_; | ||
| 342 | dst->release_store_reused_ = reused_; | ||
| 343 | // Rememeber that we don't need to acquire it in future. | ||
| 344 | dst->elem(tid_).reused = reused_; | ||
| 345 | |||
| 346 | // If the resulting clock is cachable, cache it for future release operations. | ||
| 347 | // The clock is always cachable if we released to an empty sync object. | ||
| 348 | if (cached_idx_ == 0 && dst->Cachable()) { | ||
| 349 | // Grab a reference to the ClockBlock. | ||
| 350 | atomic_uint32_t *ref = ref_ptr(dst->tab_); | ||
| 351 | if (atomic_load(ref, memory_order_acquire) == 1) | ||
| 352 | atomic_store_relaxed(ref, 2); | ||
| 353 | else | ||
| 354 | atomic_fetch_add(ref_ptr(dst->tab_), 1, memory_order_relaxed); | ||
| 355 | cached_idx_ = dst->tab_idx_; | ||
| 356 | cached_size_ = dst->size_; | ||
| 357 | cached_blocks_ = dst->blocks_; | ||
| 358 | } | ||
| 359 | } | ||
| 360 | |||
| 361 | void ThreadClock::acq_rel(ClockCache *c, SyncClock *dst) { | ||
| 362 | CPP_STAT_INC(StatClockAcquireRelease); | ||
| 363 | acquire(c, dst); | ||
| 364 | ReleaseStore(c, dst); | ||
| 365 | } | ||
| 366 | |||
| 367 | // Updates only single element related to the current thread in dst->clk_. | ||
| 368 | void ThreadClock::UpdateCurrentThread(ClockCache *c, SyncClock *dst) const { | ||
| 369 | // Update the threads time, but preserve 'acquired' flag. | ||
| 370 | for (unsigned i = 0; i < kDirtyTids; i++) { | ||
| 371 | SyncClock::Dirty *dirty = &dst->dirty_[i]; | ||
| 372 | const unsigned tid = dirty->tid; | ||
| 373 | if (tid == tid_ || tid == kInvalidTid) { | ||
| 374 | CPP_STAT_INC(StatClockReleaseFast); | ||
| 375 | dirty->tid = tid_; | ||
| 376 | dirty->epoch = clk_[tid_]; | ||
| 377 | return; | ||
| 378 | } | ||
| 379 | } | ||
| 380 | // Reset all 'acquired' flags, O(N). | ||
| 381 | // We are going to touch dst elements, so we need to unshare it. | ||
| 382 | dst->Unshare(c); | ||
| 383 | CPP_STAT_INC(StatClockReleaseSlow); | ||
| 384 | dst->elem(tid_).epoch = clk_[tid_]; | ||
| 385 | for (uptr i = 0; i < dst->size_; i++) | ||
| 386 | dst->elem(i).reused = 0; | ||
| 387 | dst->FlushDirty(); | ||
| 388 | } | ||
| 389 | |||
| 390 | // Checks whether the current thread has already acquired src. | ||
| 391 | bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const { | ||
| 392 | if (src->elem(tid_).reused != reused_) | ||
| 393 | return false; | ||
| 394 | for (unsigned i = 0; i < kDirtyTids; i++) { | ||
| 395 | SyncClock::Dirty dirty = src->dirty_[i]; | ||
| 396 | if (dirty.tid != kInvalidTid) { | ||
| 397 | if (clk_[dirty.tid] < dirty.epoch) | ||
| 398 | return false; | ||
| 399 | } | ||
| 400 | } | ||
| 401 | return true; | ||
| 402 | } | ||
| 403 | |||
| 404 | // Checks whether the current thread has acquired anything | ||
| 405 | // from other clocks after releasing to dst (directly or indirectly). | ||
| 406 | bool ThreadClock::HasAcquiredAfterRelease(const SyncClock *dst) const { | ||
| 407 | const u64 my_epoch = dst->elem(tid_).epoch; | ||
| 408 | return my_epoch <= last_acquire_ || | ||
| 409 | my_epoch <= atomic_load_relaxed(&global_acquire_); | ||
| 410 | } | ||
| 411 | |||
| 412 | // Sets a single element in the vector clock. | ||
| 413 | // This function is called only from weird places like AcquireGlobal. | ||
| 414 | void ThreadClock::set(ClockCache *c, unsigned tid, u64 v) { | ||
| 415 | DCHECK_LT(tid, kMaxTid); | ||
| 416 | DCHECK_GE(v, clk_[tid]); | ||
| 417 | clk_[tid] = v; | ||
| 418 | if (nclk_ <= tid) | ||
| 419 | nclk_ = tid + 1; | ||
| 420 | last_acquire_ = clk_[tid_]; | ||
| 421 | ResetCached(c); | ||
| 422 | } | ||
| 423 | |||
| 424 | void ThreadClock::DebugDump(int(*printf)(const char *s, ...)) { | ||
| 425 | printf("clock=["); | ||
| 426 | for (uptr i = 0; i < nclk_; i++) | ||
| 427 | printf("%s%llu", i == 0 ? "" : ",", clk_[i]); | ||
| 428 | printf("] tid=%u/%u last_acq=%llu", tid_, reused_, last_acquire_); | ||
| 429 | } | ||
| 430 | |||
| 431 | SyncClock::SyncClock() { | ||
| 432 | ResetImpl(); | ||
| 433 | } | ||
| 434 | |||
| 435 | SyncClock::~SyncClock() { | ||
| 436 | // Reset must be called before dtor. | ||
| 437 | CHECK_EQ(size_, 0); | ||
| 438 | CHECK_EQ(blocks_, 0); | ||
| 439 | CHECK_EQ(tab_, 0); | ||
| 440 | CHECK_EQ(tab_idx_, 0); | ||
| 441 | } | ||
| 442 | |||
| 443 | void SyncClock::Reset(ClockCache *c) { | ||
| 444 | if (size_) | ||
| 445 | UnrefClockBlock(c, tab_idx_, blocks_); | ||
| 446 | ResetImpl(); | ||
| 447 | } | ||
| 448 | |||
| 449 | void SyncClock::ResetImpl() { | ||
| 450 | tab_ = 0; | ||
| 451 | tab_idx_ = 0; | ||
| 452 | size_ = 0; | ||
| 453 | blocks_ = 0; | ||
| 454 | release_store_tid_ = kInvalidTid; | ||
| 455 | release_store_reused_ = 0; | ||
| 456 | for (uptr i = 0; i < kDirtyTids; i++) | ||
| 457 | dirty_[i].tid = kInvalidTid; | ||
| 458 | } | ||
| 459 | |||
| 460 | void SyncClock::Resize(ClockCache *c, uptr nclk) { | ||
| 461 | CPP_STAT_INC(StatClockReleaseResize); | ||
| 462 | Unshare(c); | ||
| 463 | if (nclk <= capacity()) { | ||
| 464 | // Memory is already allocated, just increase the size. | ||
| 465 | size_ = nclk; | ||
| 466 | return; | ||
| 467 | } | ||
| 468 | if (size_ == 0) { | ||
| 469 | // Grow from 0 to one-level table. | ||
| 470 | CHECK_EQ(size_, 0); | ||
| 471 | CHECK_EQ(blocks_, 0); | ||
| 472 | CHECK_EQ(tab_, 0); | ||
| 473 | CHECK_EQ(tab_idx_, 0); | ||
| 474 | tab_idx_ = ctx->clock_alloc.Alloc(c); | ||
| 475 | tab_ = ctx->clock_alloc.Map(tab_idx_); | ||
| 476 | internal_memset(tab_, 0, sizeof(*tab_)); | ||
| 477 | atomic_store_relaxed(ref_ptr(tab_), 1); | ||
| 478 | size_ = 1; | ||
| 479 | } else if (size_ > blocks_ * ClockBlock::kClockCount) { | ||
| 480 | u32 idx = ctx->clock_alloc.Alloc(c); | ||
| 481 | ClockBlock *new_cb = ctx->clock_alloc.Map(idx); | ||
| 482 | uptr top = size_ - blocks_ * ClockBlock::kClockCount; | ||
| 483 | CHECK_LT(top, ClockBlock::kClockCount); | ||
| 484 | const uptr move = top * sizeof(tab_->clock[0]); | ||
| 485 | internal_memcpy(&new_cb->clock[0], tab_->clock, move); | ||
| 486 | internal_memset(&new_cb->clock[top], 0, sizeof(*new_cb) - move); | ||
| 487 | internal_memset(tab_->clock, 0, move); | ||
| 488 | append_block(idx); | ||
| 489 | } | ||
| 490 | // At this point we have first level table allocated and all clock elements | ||
| 491 | // are evacuated from it to a second level block. | ||
| 492 | // Add second level tables as necessary. | ||
| 493 | while (nclk > capacity()) { | ||
| 494 | u32 idx = ctx->clock_alloc.Alloc(c); | ||
| 495 | ClockBlock *cb = ctx->clock_alloc.Map(idx); | ||
| 496 | internal_memset(cb, 0, sizeof(*cb)); | ||
| 497 | append_block(idx); | ||
| 498 | } | ||
| 499 | size_ = nclk; | ||
| 500 | } | ||
| 501 | |||
| 502 | // Flushes all dirty elements into the main clock array. | ||
| 503 | void SyncClock::FlushDirty() { | ||
| 504 | for (unsigned i = 0; i < kDirtyTids; i++) { | ||
| 505 | Dirty *dirty = &dirty_[i]; | ||
| 506 | if (dirty->tid != kInvalidTid) { | ||
| 507 | CHECK_LT(dirty->tid, size_); | ||
| 508 | elem(dirty->tid).epoch = dirty->epoch; | ||
| 509 | dirty->tid = kInvalidTid; | ||
| 510 | } | ||
| 511 | } | ||
| 512 | } | ||
| 513 | |||
| 514 | bool SyncClock::IsShared() const { | ||
| 515 | if (size_ == 0) | ||
| 516 | return false; | ||
| 517 | atomic_uint32_t *ref = ref_ptr(tab_); | ||
| 518 | u32 v = atomic_load(ref, memory_order_acquire); | ||
| 519 | CHECK_GT(v, 0); | ||
| 520 | return v > 1; | ||
| 521 | } | ||
| 522 | |||
| 523 | // Unshares the current clock if it's shared. | ||
| 524 | // Shared clocks are immutable, so they need to be unshared before any updates. | ||
| 525 | // Note: this does not apply to dirty entries as they are not shared. | ||
| 526 | void SyncClock::Unshare(ClockCache *c) { | ||
| 527 | if (!IsShared()) | ||
| 528 | return; | ||
| 529 | // First, copy current state into old. | ||
| 530 | SyncClock old; | ||
| 531 | old.tab_ = tab_; | ||
| 532 | old.tab_idx_ = tab_idx_; | ||
| 533 | old.size_ = size_; | ||
| 534 | old.blocks_ = blocks_; | ||
| 535 | old.release_store_tid_ = release_store_tid_; | ||
| 536 | old.release_store_reused_ = release_store_reused_; | ||
| 537 | for (unsigned i = 0; i < kDirtyTids; i++) | ||
| 538 | old.dirty_[i] = dirty_[i]; | ||
| 539 | // Then, clear current object. | ||
| 540 | ResetImpl(); | ||
| 541 | // Allocate brand new clock in the current object. | ||
| 542 | Resize(c, old.size_); | ||
| 543 | // Now copy state back into this object. | ||
| 544 | Iter old_iter(&old); | ||
| 545 | for (ClockElem &ce : *this) { | ||
| 546 | ce = *old_iter; | ||
| 547 | ++old_iter; | ||
| 548 | } | ||
| 549 | release_store_tid_ = old.release_store_tid_; | ||
| 550 | release_store_reused_ = old.release_store_reused_; | ||
| 551 | for (unsigned i = 0; i < kDirtyTids; i++) | ||
| 552 | dirty_[i] = old.dirty_[i]; | ||
| 553 | // Drop reference to old and delete if necessary. | ||
| 554 | old.Reset(c); | ||
| 555 | } | ||
| 556 | |||
| 557 | // Can we cache this clock for future release operations? | ||
| 558 | ALWAYS_INLINE bool SyncClock::Cachable() const { | ||
| 559 | if (size_ == 0) | ||
| 560 | return false; | ||
| 561 | for (unsigned i = 0; i < kDirtyTids; i++) { | ||
| 562 | if (dirty_[i].tid != kInvalidTid) | ||
| 563 | return false; | ||
| 564 | } | ||
| 565 | return atomic_load_relaxed(ref_ptr(tab_)) == 1; | ||
| 566 | } | ||
| 567 | |||
| 568 | // elem linearizes the two-level structure into linear array. | ||
| 569 | // Note: this is used only for one time accesses, vector operations use | ||
| 570 | // the iterator as it is much faster. | ||
| 571 | ALWAYS_INLINE ClockElem &SyncClock::elem(unsigned tid) const { | ||
| 572 | DCHECK_LT(tid, size_); | ||
| 573 | const uptr block = tid / ClockBlock::kClockCount; | ||
| 574 | DCHECK_LE(block, blocks_); | ||
| 575 | tid %= ClockBlock::kClockCount; | ||
| 576 | if (block == blocks_) | ||
| 577 | return tab_->clock[tid]; | ||
| 578 | u32 idx = get_block(block); | ||
| 579 | ClockBlock *cb = ctx->clock_alloc.Map(idx); | ||
| 580 | return cb->clock[tid]; | ||
| 581 | } | ||
| 582 | |||
| 583 | ALWAYS_INLINE uptr SyncClock::capacity() const { | ||
| 584 | if (size_ == 0) | ||
| 585 | return 0; | ||
| 586 | uptr ratio = sizeof(ClockBlock::clock[0]) / sizeof(ClockBlock::table[0]); | ||
| 587 | // How many clock elements we can fit into the first level block. | ||
| 588 | // +1 for ref counter. | ||
| 589 | uptr top = ClockBlock::kClockCount - RoundUpTo(blocks_ + 1, ratio) / ratio; | ||
| 590 | return blocks_ * ClockBlock::kClockCount + top; | ||
| 591 | } | ||
| 592 | |||
| 593 | ALWAYS_INLINE u32 SyncClock::get_block(uptr bi) const { | ||
| 594 | DCHECK(size_); | ||
| 595 | DCHECK_LT(bi, blocks_); | ||
| 596 | return tab_->table[ClockBlock::kBlockIdx - bi]; | ||
| 597 | } | ||
| 598 | |||
| 599 | ALWAYS_INLINE void SyncClock::append_block(u32 idx) { | ||
| 600 | uptr bi = blocks_++; | ||
| 601 | CHECK_EQ(get_block(bi), 0); | ||
| 602 | tab_->table[ClockBlock::kBlockIdx - bi] = idx; | ||
| 603 | } | ||
| 604 | |||
| 605 | // Used only by tests. | ||
| 606 | u64 SyncClock::get(unsigned tid) const { | ||
| 607 | for (unsigned i = 0; i < kDirtyTids; i++) { | ||
| 608 | Dirty dirty = dirty_[i]; | ||
| 609 | if (dirty.tid == tid) | ||
| 610 | return dirty.epoch; | ||
| 611 | } | ||
| 612 | return elem(tid).epoch; | ||
| 613 | } | ||
| 614 | |||
| 615 | // Used only by Iter test. | ||
| 616 | u64 SyncClock::get_clean(unsigned tid) const { | ||
| 617 | return elem(tid).epoch; | ||
| 618 | } | ||
| 619 | |||
| 620 | void SyncClock::DebugDump(int(*printf)(const char *s, ...)) { | ||
| 621 | printf("clock=["); | ||
| 622 | for (uptr i = 0; i < size_; i++) | ||
| 623 | printf("%s%llu", i == 0 ? "" : ",", elem(i).epoch); | ||
| 624 | printf("] reused=["); | ||
| 625 | for (uptr i = 0; i < size_; i++) | ||
| 626 | printf("%s%llu", i == 0 ? "" : ",", elem(i).reused); | ||
| 627 | printf("] release_store_tid=%d/%d dirty_tids=%d[%llu]/%d[%llu]", | ||
| 628 | release_store_tid_, release_store_reused_, | ||
| 629 | dirty_[0].tid, dirty_[0].epoch, | ||
| 630 | dirty_[1].tid, dirty_[1].epoch); | ||
| 631 | } | ||
| 632 | |||
| 633 | void SyncClock::Iter::Next() { | ||
| 634 | // Finished with the current block, move on to the next one. | ||
| 635 | block_++; | ||
| 636 | if (block_ < parent_->blocks_) { | ||
| 637 | // Iterate over the next second level block. | ||
| 638 | u32 idx = parent_->get_block(block_); | ||
| 639 | ClockBlock *cb = ctx->clock_alloc.Map(idx); | ||
| 640 | pos_ = &cb->clock[0]; | ||
| 641 | end_ = pos_ + min(parent_->size_ - block_ * ClockBlock::kClockCount, | ||
| 642 | ClockBlock::kClockCount); | ||
| 643 | return; | ||
| 644 | } | ||
| 645 | if (block_ == parent_->blocks_ && | ||
| 646 | parent_->size_ > parent_->blocks_ * ClockBlock::kClockCount) { | ||
| 647 | // Iterate over elements in the first level block. | ||
| 648 | pos_ = &parent_->tab_->clock[0]; | ||
| 649 | end_ = pos_ + min(parent_->size_ - block_ * ClockBlock::kClockCount, | ||
| 650 | ClockBlock::kClockCount); | ||
| 651 | return; | ||
| 652 | } | ||
| 653 | parent_ = nullptr; // denotes end | ||
| 654 | } | ||
| 655 | } // namespace __tsan | ||
lib/tsan/tsan_clock.h created+283| ... | @@ -0,0 +1,283 @@ | ||
| 1 | //===-- tsan_clock.h --------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef TSAN_CLOCK_H | ||
| 13 | #define TSAN_CLOCK_H | ||
| 14 | |||
| 15 | #include "tsan_defs.h" | ||
| 16 | #include "tsan_dense_alloc.h" | ||
| 17 | |||
| 18 | namespace __tsan { | ||
| 19 | |||
| 20 | typedef DenseSlabAlloc<ClockBlock, 1<<16, 1<<10> ClockAlloc; | ||
| 21 | typedef DenseSlabAllocCache ClockCache; | ||
| 22 | |||
| 23 | // The clock that lives in sync variables (mutexes, atomics, etc). | ||
| 24 | class SyncClock { | ||
| 25 | public: | ||
| 26 | SyncClock(); | ||
| 27 | ~SyncClock(); | ||
| 28 | |||
| 29 | uptr size() const; | ||
| 30 | |||
| 31 | // These are used only in tests. | ||
| 32 | u64 get(unsigned tid) const; | ||
| 33 | u64 get_clean(unsigned tid) const; | ||
| 34 | |||
| 35 | void Resize(ClockCache *c, uptr nclk); | ||
| 36 | void Reset(ClockCache *c); | ||
| 37 | |||
| 38 | void DebugDump(int(*printf)(const char *s, ...)); | ||
| 39 | |||
| 40 | // Clock element iterator. | ||
| 41 | // Note: it iterates only over the table without regard to dirty entries. | ||
| 42 | class Iter { | ||
| 43 | public: | ||
| 44 | explicit Iter(SyncClock* parent); | ||
| 45 | Iter& operator++(); | ||
| 46 | bool operator!=(const Iter& other); | ||
| 47 | ClockElem &operator*(); | ||
| 48 | |||
| 49 | private: | ||
| 50 | SyncClock *parent_; | ||
| 51 | // [pos_, end_) is the current continuous range of clock elements. | ||
| 52 | ClockElem *pos_; | ||
| 53 | ClockElem *end_; | ||
| 54 | int block_; // Current number of second level block. | ||
| 55 | |||
| 56 | NOINLINE void Next(); | ||
| 57 | }; | ||
| 58 | |||
| 59 | Iter begin(); | ||
| 60 | Iter end(); | ||
| 61 | |||
| 62 | private: | ||
| 63 | friend class ThreadClock; | ||
| 64 | friend class Iter; | ||
| 65 | static const uptr kDirtyTids = 2; | ||
| 66 | |||
| 67 | struct Dirty { | ||
| 68 | u64 epoch : kClkBits; | ||
| 69 | u64 tid : 64 - kClkBits; // kInvalidId if not active | ||
| 70 | }; | ||
| 71 | |||
| 72 | unsigned release_store_tid_; | ||
| 73 | unsigned release_store_reused_; | ||
| 74 | Dirty dirty_[kDirtyTids]; | ||
| 75 | // If size_ is 0, tab_ is nullptr. | ||
| 76 | // If size <= 64 (kClockCount), tab_ contains pointer to an array with | ||
| 77 | // 64 ClockElem's (ClockBlock::clock). | ||
| 78 | // Otherwise, tab_ points to an array with up to 127 u32 elements, | ||
| 79 | // each pointing to the second-level 512b block with 64 ClockElem's. | ||
| 80 | // Unused space in the first level ClockBlock is used to store additional | ||
| 81 | // clock elements. | ||
| 82 | // The last u32 element in the first level ClockBlock is always used as | ||
| 83 | // reference counter. | ||
| 84 | // | ||
| 85 | // See the following scheme for details. | ||
| 86 | // All memory blocks are 512 bytes (allocated from ClockAlloc). | ||
| 87 | // Clock (clk) elements are 64 bits. | ||
| 88 | // Idx and ref are 32 bits. | ||
| 89 | // | ||
| 90 | // tab_ | ||
| 91 | // | | ||
| 92 | // \/ | ||
| 93 | // +----------------------------------------------------+ | ||
| 94 | // | clk128 | clk129 | ...unused... | idx1 | idx0 | ref | | ||
| 95 | // +----------------------------------------------------+ | ||
| 96 | // | | | ||
| 97 | // | \/ | ||
| 98 | // | +----------------+ | ||
| 99 | // | | clk0 ... clk63 | | ||
| 100 | // | +----------------+ | ||
| 101 | // \/ | ||
| 102 | // +------------------+ | ||
| 103 | // | clk64 ... clk127 | | ||
| 104 | // +------------------+ | ||
| 105 | // | ||
| 106 | // Note: dirty entries, if active, always override what's stored in the clock. | ||
| 107 | ClockBlock *tab_; | ||
| 108 | u32 tab_idx_; | ||
| 109 | u16 size_; | ||
| 110 | u16 blocks_; // Number of second level blocks. | ||
| 111 | |||
| 112 | void Unshare(ClockCache *c); | ||
| 113 | bool IsShared() const; | ||
| 114 | bool Cachable() const; | ||
| 115 | void ResetImpl(); | ||
| 116 | void FlushDirty(); | ||
| 117 | uptr capacity() const; | ||
| 118 | u32 get_block(uptr bi) const; | ||
| 119 | void append_block(u32 idx); | ||
| 120 | ClockElem &elem(unsigned tid) const; | ||
| 121 | }; | ||
| 122 | |||
| 123 | // The clock that lives in threads. | ||
| 124 | class ThreadClock { | ||
| 125 | public: | ||
| 126 | typedef DenseSlabAllocCache Cache; | ||
| 127 | |||
| 128 | explicit ThreadClock(unsigned tid, unsigned reused = 0); | ||
| 129 | |||
| 130 | u64 get(unsigned tid) const; | ||
| 131 | void set(ClockCache *c, unsigned tid, u64 v); | ||
| 132 | void set(u64 v); | ||
| 133 | void tick(); | ||
| 134 | uptr size() const; | ||
| 135 | |||
| 136 | void acquire(ClockCache *c, SyncClock *src); | ||
| 137 | void releaseStoreAcquire(ClockCache *c, SyncClock *src); | ||
| 138 | void release(ClockCache *c, SyncClock *dst); | ||
| 139 | void acq_rel(ClockCache *c, SyncClock *dst); | ||
| 140 | void ReleaseStore(ClockCache *c, SyncClock *dst); | ||
| 141 | void ResetCached(ClockCache *c); | ||
| 142 | void NoteGlobalAcquire(u64 v); | ||
| 143 | |||
| 144 | void DebugReset(); | ||
| 145 | void DebugDump(int(*printf)(const char *s, ...)); | ||
| 146 | |||
| 147 | private: | ||
| 148 | static const uptr kDirtyTids = SyncClock::kDirtyTids; | ||
| 149 | // Index of the thread associated with he clock ("current thread"). | ||
| 150 | const unsigned tid_; | ||
| 151 | const unsigned reused_; // tid_ reuse count. | ||
| 152 | // Current thread time when it acquired something from other threads. | ||
| 153 | u64 last_acquire_; | ||
| 154 | |||
| 155 | // Last time another thread has done a global acquire of this thread's clock. | ||
| 156 | // It helps to avoid problem described in: | ||
| 157 | // https://github.com/golang/go/issues/39186 | ||
| 158 | // See test/tsan/java_finalizer2.cpp for a regression test. | ||
| 159 | // Note the failuire is _extremely_ hard to hit, so if you are trying | ||
| 160 | // to reproduce it, you may want to run something like: | ||
| 161 | // $ go get golang.org/x/tools/cmd/stress | ||
| 162 | // $ stress -p=64 ./a.out | ||
| 163 | // | ||
| 164 | // The crux of the problem is roughly as follows. | ||
| 165 | // A number of O(1) optimizations in the clocks algorithm assume proper | ||
| 166 | // transitive cumulative propagation of clock values. The AcquireGlobal | ||
| 167 | // operation may produce an inconsistent non-linearazable view of | ||
| 168 | // thread clocks. Namely, it may acquire a later value from a thread | ||
| 169 | // with a higher ID, but fail to acquire an earlier value from a thread | ||
| 170 | // with a lower ID. If a thread that executed AcquireGlobal then releases | ||
| 171 | // to a sync clock, it will spoil the sync clock with the inconsistent | ||
| 172 | // values. If another thread later releases to the sync clock, the optimized | ||
| 173 | // algorithm may break. | ||
| 174 | // | ||
| 175 | // The exact sequence of events that leads to the failure. | ||
| 176 | // - thread 1 executes AcquireGlobal | ||
| 177 | // - thread 1 acquires value 1 for thread 2 | ||
| 178 | // - thread 2 increments clock to 2 | ||
| 179 | // - thread 2 releases to sync object 1 | ||
| 180 | // - thread 3 at time 1 | ||
| 181 | // - thread 3 acquires from sync object 1 | ||
| 182 | // - thread 3 increments clock to 2 | ||
| 183 | // - thread 1 acquires value 2 for thread 3 | ||
| 184 | // - thread 1 releases to sync object 2 | ||
| 185 | // - sync object 2 clock has 1 for thread 2 and 2 for thread 3 | ||
| 186 | // - thread 3 releases to sync object 2 | ||
| 187 | // - thread 3 sees value 2 in the clock for itself | ||
| 188 | // and decides that it has already released to the clock | ||
| 189 | // and did not acquire anything from other threads after that | ||
| 190 | // (the last_acquire_ check in release operation) | ||
| 191 | // - thread 3 does not update the value for thread 2 in the clock from 1 to 2 | ||
| 192 | // - thread 4 acquires from sync object 2 | ||
| 193 | // - thread 4 detects a false race with thread 2 | ||
| 194 | // as it should have been synchronized with thread 2 up to time 2, | ||
| 195 | // but because of the broken clock it is now synchronized only up to time 1 | ||
| 196 | // | ||
| 197 | // The global_acquire_ value helps to prevent this scenario. | ||
| 198 | // Namely, thread 3 will not trust any own clock values up to global_acquire_ | ||
| 199 | // for the purposes of the last_acquire_ optimization. | ||
| 200 | atomic_uint64_t global_acquire_; | ||
| 201 | |||
| 202 | // Cached SyncClock (without dirty entries and release_store_tid_). | ||
| 203 | // We reuse it for subsequent store-release operations without intervening | ||
| 204 | // acquire operations. Since it is shared (and thus constant), clock value | ||
| 205 | // for the current thread is then stored in dirty entries in the SyncClock. | ||
| 206 | // We host a refernece to the table while it is cached here. | ||
| 207 | u32 cached_idx_; | ||
| 208 | u16 cached_size_; | ||
| 209 | u16 cached_blocks_; | ||
| 210 | |||
| 211 | // Number of active elements in the clk_ table (the rest is zeros). | ||
| 212 | uptr nclk_; | ||
| 213 | u64 clk_[kMaxTidInClock]; // Fixed size vector clock. | ||
| 214 | |||
| 215 | bool IsAlreadyAcquired(const SyncClock *src) const; | ||
| 216 | bool HasAcquiredAfterRelease(const SyncClock *dst) const; | ||
| 217 | void UpdateCurrentThread(ClockCache *c, SyncClock *dst) const; | ||
| 218 | }; | ||
| 219 | |||
| 220 | ALWAYS_INLINE u64 ThreadClock::get(unsigned tid) const { | ||
| 221 | DCHECK_LT(tid, kMaxTidInClock); | ||
| 222 | return clk_[tid]; | ||
| 223 | } | ||
| 224 | |||
| 225 | ALWAYS_INLINE void ThreadClock::set(u64 v) { | ||
| 226 | DCHECK_GE(v, clk_[tid_]); | ||
| 227 | clk_[tid_] = v; | ||
| 228 | } | ||
| 229 | |||
| 230 | ALWAYS_INLINE void ThreadClock::tick() { | ||
| 231 | clk_[tid_]++; | ||
| 232 | } | ||
| 233 | |||
| 234 | ALWAYS_INLINE uptr ThreadClock::size() const { | ||
| 235 | return nclk_; | ||
| 236 | } | ||
| 237 | |||
| 238 | ALWAYS_INLINE void ThreadClock::NoteGlobalAcquire(u64 v) { | ||
| 239 | // Here we rely on the fact that AcquireGlobal is protected by | ||
| 240 | // ThreadRegistryLock, thus only one thread at a time executes it | ||
| 241 | // and values passed to this function should not go backwards. | ||
| 242 | CHECK_LE(atomic_load_relaxed(&global_acquire_), v); | ||
| 243 | atomic_store_relaxed(&global_acquire_, v); | ||
| 244 | } | ||
| 245 | |||
| 246 | ALWAYS_INLINE SyncClock::Iter SyncClock::begin() { | ||
| 247 | return Iter(this); | ||
| 248 | } | ||
| 249 | |||
| 250 | ALWAYS_INLINE SyncClock::Iter SyncClock::end() { | ||
| 251 | return Iter(nullptr); | ||
| 252 | } | ||
| 253 | |||
| 254 | ALWAYS_INLINE uptr SyncClock::size() const { | ||
| 255 | return size_; | ||
| 256 | } | ||
| 257 | |||
| 258 | ALWAYS_INLINE SyncClock::Iter::Iter(SyncClock* parent) | ||
| 259 | : parent_(parent) | ||
| 260 | , pos_(nullptr) | ||
| 261 | , end_(nullptr) | ||
| 262 | , block_(-1) { | ||
| 263 | if (parent) | ||
| 264 | Next(); | ||
| 265 | } | ||
| 266 | |||
| 267 | ALWAYS_INLINE SyncClock::Iter& SyncClock::Iter::operator++() { | ||
| 268 | pos_++; | ||
| 269 | if (UNLIKELY(pos_ >= end_)) | ||
| 270 | Next(); | ||
| 271 | return *this; | ||
| 272 | } | ||
| 273 | |||
| 274 | ALWAYS_INLINE bool SyncClock::Iter::operator!=(const SyncClock::Iter& other) { | ||
| 275 | return parent_ != other.parent_; | ||
| 276 | } | ||
| 277 | |||
| 278 | ALWAYS_INLINE ClockElem &SyncClock::Iter::operator*() { | ||
| 279 | return *pos_; | ||
| 280 | } | ||
| 281 | } // namespace __tsan | ||
| 282 | |||
| 283 | #endif // TSAN_CLOCK_H | ||
lib/tsan/tsan_debugging.cpp created+262| ... | @@ -0,0 +1,262 @@ | ||
| 1 | //===-- tsan_debugging.cpp ------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | // TSan debugging API implementation. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | #include "tsan_interface.h" | ||
| 14 | #include "tsan_report.h" | ||
| 15 | #include "tsan_rtl.h" | ||
| 16 | |||
| 17 | #include "sanitizer_common/sanitizer_stackdepot.h" | ||
| 18 | |||
| 19 | using namespace __tsan; | ||
| 20 | |||
| 21 | static const char *ReportTypeDescription(ReportType typ) { | ||
| 22 | switch (typ) { | ||
| 23 | case ReportTypeRace: return "data-race"; | ||
| 24 | case ReportTypeVptrRace: return "data-race-vptr"; | ||
| 25 | case ReportTypeUseAfterFree: return "heap-use-after-free"; | ||
| 26 | case ReportTypeVptrUseAfterFree: return "heap-use-after-free-vptr"; | ||
| 27 | case ReportTypeExternalRace: return "external-race"; | ||
| 28 | case ReportTypeThreadLeak: return "thread-leak"; | ||
| 29 | case ReportTypeMutexDestroyLocked: return "locked-mutex-destroy"; | ||
| 30 | case ReportTypeMutexDoubleLock: return "mutex-double-lock"; | ||
| 31 | case ReportTypeMutexInvalidAccess: return "mutex-invalid-access"; | ||
| 32 | case ReportTypeMutexBadUnlock: return "mutex-bad-unlock"; | ||
| 33 | case ReportTypeMutexBadReadLock: return "mutex-bad-read-lock"; | ||
| 34 | case ReportTypeMutexBadReadUnlock: return "mutex-bad-read-unlock"; | ||
| 35 | case ReportTypeSignalUnsafe: return "signal-unsafe-call"; | ||
| 36 | case ReportTypeErrnoInSignal: return "errno-in-signal-handler"; | ||
| 37 | case ReportTypeDeadlock: return "lock-order-inversion"; | ||
| 38 | // No default case so compiler warns us if we miss one | ||
| 39 | } | ||
| 40 | UNREACHABLE("missing case"); | ||
| 41 | } | ||
| 42 | |||
| 43 | static const char *ReportLocationTypeDescription(ReportLocationType typ) { | ||
| 44 | switch (typ) { | ||
| 45 | case ReportLocationGlobal: return "global"; | ||
| 46 | case ReportLocationHeap: return "heap"; | ||
| 47 | case ReportLocationStack: return "stack"; | ||
| 48 | case ReportLocationTLS: return "tls"; | ||
| 49 | case ReportLocationFD: return "fd"; | ||
| 50 | // No default case so compiler warns us if we miss one | ||
| 51 | } | ||
| 52 | UNREACHABLE("missing case"); | ||
| 53 | } | ||
| 54 | |||
| 55 | static void CopyTrace(SymbolizedStack *first_frame, void **trace, | ||
| 56 | uptr trace_size) { | ||
| 57 | uptr i = 0; | ||
| 58 | for (SymbolizedStack *frame = first_frame; frame != nullptr; | ||
| 59 | frame = frame->next) { | ||
| 60 | trace[i++] = (void *)frame->info.address; | ||
| 61 | if (i >= trace_size) break; | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | // Meant to be called by the debugger. | ||
| 66 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 67 | void *__tsan_get_current_report() { | ||
| 68 | return const_cast<ReportDesc*>(cur_thread()->current_report); | ||
| 69 | } | ||
| 70 | |||
| 71 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 72 | int __tsan_get_report_data(void *report, const char **description, int *count, | ||
| 73 | int *stack_count, int *mop_count, int *loc_count, | ||
| 74 | int *mutex_count, int *thread_count, | ||
| 75 | int *unique_tid_count, void **sleep_trace, | ||
| 76 | uptr trace_size) { | ||
| 77 | const ReportDesc *rep = (ReportDesc *)report; | ||
| 78 | *description = ReportTypeDescription(rep->typ); | ||
| 79 | *count = rep->count; | ||
| 80 | *stack_count = rep->stacks.Size(); | ||
| 81 | *mop_count = rep->mops.Size(); | ||
| 82 | *loc_count = rep->locs.Size(); | ||
| 83 | *mutex_count = rep->mutexes.Size(); | ||
| 84 | *thread_count = rep->threads.Size(); | ||
| 85 | *unique_tid_count = rep->unique_tids.Size(); | ||
| 86 | if (rep->sleep) CopyTrace(rep->sleep->frames, sleep_trace, trace_size); | ||
| 87 | return 1; | ||
| 88 | } | ||
| 89 | |||
| 90 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 91 | int __tsan_get_report_tag(void *report, uptr *tag) { | ||
| 92 | const ReportDesc *rep = (ReportDesc *)report; | ||
| 93 | *tag = rep->tag; | ||
| 94 | return 1; | ||
| 95 | } | ||
| 96 | |||
| 97 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 98 | int __tsan_get_report_stack(void *report, uptr idx, void **trace, | ||
| 99 | uptr trace_size) { | ||
| 100 | const ReportDesc *rep = (ReportDesc *)report; | ||
| 101 | CHECK_LT(idx, rep->stacks.Size()); | ||
| 102 | ReportStack *stack = rep->stacks[idx]; | ||
| 103 | if (stack) CopyTrace(stack->frames, trace, trace_size); | ||
| 104 | return stack ? 1 : 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 108 | int __tsan_get_report_mop(void *report, uptr idx, int *tid, void **addr, | ||
| 109 | int *size, int *write, int *atomic, void **trace, | ||
| 110 | uptr trace_size) { | ||
| 111 | const ReportDesc *rep = (ReportDesc *)report; | ||
| 112 | CHECK_LT(idx, rep->mops.Size()); | ||
| 113 | ReportMop *mop = rep->mops[idx]; | ||
| 114 | *tid = mop->tid; | ||
| 115 | *addr = (void *)mop->addr; | ||
| 116 | *size = mop->size; | ||
| 117 | *write = mop->write ? 1 : 0; | ||
| 118 | *atomic = mop->atomic ? 1 : 0; | ||
| 119 | if (mop->stack) CopyTrace(mop->stack->frames, trace, trace_size); | ||
| 120 | return 1; | ||
| 121 | } | ||
| 122 | |||
| 123 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 124 | int __tsan_get_report_loc(void *report, uptr idx, const char **type, | ||
| 125 | void **addr, uptr *start, uptr *size, int *tid, | ||
| 126 | int *fd, int *suppressable, void **trace, | ||
| 127 | uptr trace_size) { | ||
| 128 | const ReportDesc *rep = (ReportDesc *)report; | ||
| 129 | CHECK_LT(idx, rep->locs.Size()); | ||
| 130 | ReportLocation *loc = rep->locs[idx]; | ||
| 131 | *type = ReportLocationTypeDescription(loc->type); | ||
| 132 | *addr = (void *)loc->global.start; | ||
| 133 | *start = loc->heap_chunk_start; | ||
| 134 | *size = loc->heap_chunk_size; | ||
| 135 | *tid = loc->tid; | ||
| 136 | *fd = loc->fd; | ||
| 137 | *suppressable = loc->suppressable; | ||
| 138 | if (loc->stack) CopyTrace(loc->stack->frames, trace, trace_size); | ||
| 139 | return 1; | ||
| 140 | } | ||
| 141 | |||
| 142 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 143 | int __tsan_get_report_loc_object_type(void *report, uptr idx, | ||
| 144 | const char **object_type) { | ||
| 145 | const ReportDesc *rep = (ReportDesc *)report; | ||
| 146 | CHECK_LT(idx, rep->locs.Size()); | ||
| 147 | ReportLocation *loc = rep->locs[idx]; | ||
| 148 | *object_type = GetObjectTypeFromTag(loc->external_tag); | ||
| 149 | return 1; | ||
| 150 | } | ||
| 151 | |||
| 152 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 153 | int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr, | ||
| 154 | int *destroyed, void **trace, uptr trace_size) { | ||
| 155 | const ReportDesc *rep = (ReportDesc *)report; | ||
| 156 | CHECK_LT(idx, rep->mutexes.Size()); | ||
| 157 | ReportMutex *mutex = rep->mutexes[idx]; | ||
| 158 | *mutex_id = mutex->id; | ||
| 159 | *addr = (void *)mutex->addr; | ||
| 160 | *destroyed = mutex->destroyed; | ||
| 161 | if (mutex->stack) CopyTrace(mutex->stack->frames, trace, trace_size); | ||
| 162 | return 1; | ||
| 163 | } | ||
| 164 | |||
| 165 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 166 | int __tsan_get_report_thread(void *report, uptr idx, int *tid, tid_t *os_id, | ||
| 167 | int *running, const char **name, int *parent_tid, | ||
| 168 | void **trace, uptr trace_size) { | ||
| 169 | const ReportDesc *rep = (ReportDesc *)report; | ||
| 170 | CHECK_LT(idx, rep->threads.Size()); | ||
| 171 | ReportThread *thread = rep->threads[idx]; | ||
| 172 | *tid = thread->id; | ||
| 173 | *os_id = thread->os_id; | ||
| 174 | *running = thread->running; | ||
| 175 | *name = thread->name; | ||
| 176 | *parent_tid = thread->parent_tid; | ||
| 177 | if (thread->stack) CopyTrace(thread->stack->frames, trace, trace_size); | ||
| 178 | return 1; | ||
| 179 | } | ||
| 180 | |||
| 181 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 182 | int __tsan_get_report_unique_tid(void *report, uptr idx, int *tid) { | ||
| 183 | const ReportDesc *rep = (ReportDesc *)report; | ||
| 184 | CHECK_LT(idx, rep->unique_tids.Size()); | ||
| 185 | *tid = rep->unique_tids[idx]; | ||
| 186 | return 1; | ||
| 187 | } | ||
| 188 | |||
| 189 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 190 | const char *__tsan_locate_address(uptr addr, char *name, uptr name_size, | ||
| 191 | uptr *region_address_ptr, | ||
| 192 | uptr *region_size_ptr) { | ||
| 193 | uptr region_address = 0; | ||
| 194 | uptr region_size = 0; | ||
| 195 | const char *region_kind = nullptr; | ||
| 196 | if (name && name_size > 0) name[0] = 0; | ||
| 197 | |||
| 198 | if (IsMetaMem(addr)) { | ||
| 199 | region_kind = "meta shadow"; | ||
| 200 | } else if (IsShadowMem(addr)) { | ||
| 201 | region_kind = "shadow"; | ||
| 202 | } else { | ||
| 203 | bool is_stack = false; | ||
| 204 | MBlock *b = 0; | ||
| 205 | Allocator *a = allocator(); | ||
| 206 | if (a->PointerIsMine((void *)addr)) { | ||
| 207 | void *block_begin = a->GetBlockBegin((void *)addr); | ||
| 208 | if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin); | ||
| 209 | } | ||
| 210 | |||
| 211 | if (b != 0) { | ||
| 212 | region_address = (uptr)allocator()->GetBlockBegin((void *)addr); | ||
| 213 | region_size = b->siz; | ||
| 214 | region_kind = "heap"; | ||
| 215 | } else { | ||
| 216 | // TODO(kuba.brecka): We should not lock. This is supposed to be called | ||
| 217 | // from within the debugger when other threads are stopped. | ||
| 218 | ctx->thread_registry->Lock(); | ||
| 219 | ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack); | ||
| 220 | ctx->thread_registry->Unlock(); | ||
| 221 | if (tctx) { | ||
| 222 | region_kind = is_stack ? "stack" : "tls"; | ||
| 223 | } else { | ||
| 224 | region_kind = "global"; | ||
| 225 | DataInfo info; | ||
| 226 | if (Symbolizer::GetOrInit()->SymbolizeData(addr, &info)) { | ||
| 227 | internal_strncpy(name, info.name, name_size); | ||
| 228 | region_address = info.start; | ||
| 229 | region_size = info.size; | ||
| 230 | } | ||
| 231 | } | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | CHECK(region_kind); | ||
| 236 | if (region_address_ptr) *region_address_ptr = region_address; | ||
| 237 | if (region_size_ptr) *region_size_ptr = region_size; | ||
| 238 | return region_kind; | ||
| 239 | } | ||
| 240 | |||
| 241 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 242 | int __tsan_get_alloc_stack(uptr addr, uptr *trace, uptr size, int *thread_id, | ||
| 243 | tid_t *os_id) { | ||
| 244 | MBlock *b = 0; | ||
| 245 | Allocator *a = allocator(); | ||
| 246 | if (a->PointerIsMine((void *)addr)) { | ||
| 247 | void *block_begin = a->GetBlockBegin((void *)addr); | ||
| 248 | if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin); | ||
| 249 | } | ||
| 250 | if (b == 0) return 0; | ||
| 251 | |||
| 252 | *thread_id = b->tid; | ||
| 253 | // No locking. This is supposed to be called from within the debugger when | ||
| 254 | // other threads are stopped. | ||
| 255 | ThreadContextBase *tctx = ctx->thread_registry->GetThreadLocked(b->tid); | ||
| 256 | *os_id = tctx->os_id; | ||
| 257 | |||
| 258 | StackTrace stack = StackDepotGet(b->stk); | ||
| 259 | size = Min(size, (uptr)stack.size); | ||
| 260 | for (uptr i = 0; i < size; i++) trace[i] = stack.trace[stack.size - i - 1]; | ||
| 261 | return size; | ||
| 262 | } | ||
lib/tsan/tsan_defs.h created+195| ... | @@ -0,0 +1,195 @@ | ||
| 1 | //===-- tsan_defs.h ---------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef TSAN_DEFS_H | ||
| 14 | #define TSAN_DEFS_H | ||
| 15 | |||
| 16 | #include "sanitizer_common/sanitizer_internal_defs.h" | ||
| 17 | #include "sanitizer_common/sanitizer_libc.h" | ||
| 18 | #include "tsan_stat.h" | ||
| 19 | #include "ubsan/ubsan_platform.h" | ||
| 20 | |||
| 21 | // Setup defaults for compile definitions. | ||
| 22 | #ifndef TSAN_NO_HISTORY | ||
| 23 | # define TSAN_NO_HISTORY 0 | ||
| 24 | #endif | ||
| 25 | |||
| 26 | #ifndef TSAN_COLLECT_STATS | ||
| 27 | # define TSAN_COLLECT_STATS 0 | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #ifndef TSAN_CONTAINS_UBSAN | ||
| 31 | # if CAN_SANITIZE_UB && !SANITIZER_GO | ||
| 32 | # define TSAN_CONTAINS_UBSAN 1 | ||
| 33 | # else | ||
| 34 | # define TSAN_CONTAINS_UBSAN 0 | ||
| 35 | # endif | ||
| 36 | #endif | ||
| 37 | |||
| 38 | namespace __tsan { | ||
| 39 | |||
| 40 | const int kClkBits = 42; | ||
| 41 | const unsigned kMaxTidReuse = (1 << (64 - kClkBits)) - 1; | ||
| 42 | |||
| 43 | struct ClockElem { | ||
| 44 | u64 epoch : kClkBits; | ||
| 45 | u64 reused : 64 - kClkBits; // tid reuse count | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct ClockBlock { | ||
| 49 | static const uptr kSize = 512; | ||
| 50 | static const uptr kTableSize = kSize / sizeof(u32); | ||
| 51 | static const uptr kClockCount = kSize / sizeof(ClockElem); | ||
| 52 | static const uptr kRefIdx = kTableSize - 1; | ||
| 53 | static const uptr kBlockIdx = kTableSize - 2; | ||
| 54 | |||
| 55 | union { | ||
| 56 | u32 table[kTableSize]; | ||
| 57 | ClockElem clock[kClockCount]; | ||
| 58 | }; | ||
| 59 | |||
| 60 | ClockBlock() { | ||
| 61 | } | ||
| 62 | }; | ||
| 63 | |||
| 64 | const int kTidBits = 13; | ||
| 65 | // Reduce kMaxTid by kClockCount because one slot in ClockBlock table is | ||
| 66 | // occupied by reference counter, so total number of elements we can store | ||
| 67 | // in SyncClock is kClockCount * (kTableSize - 1). | ||
| 68 | const unsigned kMaxTid = (1 << kTidBits) - ClockBlock::kClockCount; | ||
| 69 | #if !SANITIZER_GO | ||
| 70 | const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit. | ||
| 71 | #else | ||
| 72 | const unsigned kMaxTidInClock = kMaxTid; // Go does not track freed memory. | ||
| 73 | #endif | ||
| 74 | const uptr kShadowStackSize = 64 * 1024; | ||
| 75 | |||
| 76 | // Count of shadow values in a shadow cell. | ||
| 77 | const uptr kShadowCnt = 4; | ||
| 78 | |||
| 79 | // That many user bytes are mapped onto a single shadow cell. | ||
| 80 | const uptr kShadowCell = 8; | ||
| 81 | |||
| 82 | // Size of a single shadow value (u64). | ||
| 83 | const uptr kShadowSize = 8; | ||
| 84 | |||
| 85 | // Shadow memory is kShadowMultiplier times larger than user memory. | ||
| 86 | const uptr kShadowMultiplier = kShadowSize * kShadowCnt / kShadowCell; | ||
| 87 | |||
| 88 | // That many user bytes are mapped onto a single meta shadow cell. | ||
| 89 | // Must be less or equal to minimal memory allocator alignment. | ||
| 90 | const uptr kMetaShadowCell = 8; | ||
| 91 | |||
| 92 | // Size of a single meta shadow value (u32). | ||
| 93 | const uptr kMetaShadowSize = 4; | ||
| 94 | |||
| 95 | #if TSAN_NO_HISTORY | ||
| 96 | const bool kCollectHistory = false; | ||
| 97 | #else | ||
| 98 | const bool kCollectHistory = true; | ||
| 99 | #endif | ||
| 100 | |||
| 101 | const u16 kInvalidTid = kMaxTid + 1; | ||
| 102 | |||
| 103 | // The following "build consistency" machinery ensures that all source files | ||
| 104 | // are built in the same configuration. Inconsistent builds lead to | ||
| 105 | // hard to debug crashes. | ||
| 106 | #if SANITIZER_DEBUG | ||
| 107 | void build_consistency_debug(); | ||
| 108 | #else | ||
| 109 | void build_consistency_release(); | ||
| 110 | #endif | ||
| 111 | |||
| 112 | #if TSAN_COLLECT_STATS | ||
| 113 | void build_consistency_stats(); | ||
| 114 | #else | ||
| 115 | void build_consistency_nostats(); | ||
| 116 | #endif | ||
| 117 | |||
| 118 | static inline void USED build_consistency() { | ||
| 119 | #if SANITIZER_DEBUG | ||
| 120 | build_consistency_debug(); | ||
| 121 | #else | ||
| 122 | build_consistency_release(); | ||
| 123 | #endif | ||
| 124 | #if TSAN_COLLECT_STATS | ||
| 125 | build_consistency_stats(); | ||
| 126 | #else | ||
| 127 | build_consistency_nostats(); | ||
| 128 | #endif | ||
| 129 | } | ||
| 130 | |||
| 131 | template<typename T> | ||
| 132 | T min(T a, T b) { | ||
| 133 | return a < b ? a : b; | ||
| 134 | } | ||
| 135 | |||
| 136 | template<typename T> | ||
| 137 | T max(T a, T b) { | ||
| 138 | return a > b ? a : b; | ||
| 139 | } | ||
| 140 | |||
| 141 | template<typename T> | ||
| 142 | T RoundUp(T p, u64 align) { | ||
| 143 | DCHECK_EQ(align & (align - 1), 0); | ||
| 144 | return (T)(((u64)p + align - 1) & ~(align - 1)); | ||
| 145 | } | ||
| 146 | |||
| 147 | template<typename T> | ||
| 148 | T RoundDown(T p, u64 align) { | ||
| 149 | DCHECK_EQ(align & (align - 1), 0); | ||
| 150 | return (T)((u64)p & ~(align - 1)); | ||
| 151 | } | ||
| 152 | |||
| 153 | // Zeroizes high part, returns 'bits' lsb bits. | ||
| 154 | template<typename T> | ||
| 155 | T GetLsb(T v, int bits) { | ||
| 156 | return (T)((u64)v & ((1ull << bits) - 1)); | ||
| 157 | } | ||
| 158 | |||
| 159 | struct MD5Hash { | ||
| 160 | u64 hash[2]; | ||
| 161 | bool operator==(const MD5Hash &other) const; | ||
| 162 | }; | ||
| 163 | |||
| 164 | MD5Hash md5_hash(const void *data, uptr size); | ||
| 165 | |||
| 166 | struct Processor; | ||
| 167 | struct ThreadState; | ||
| 168 | class ThreadContext; | ||
| 169 | struct Context; | ||
| 170 | struct ReportStack; | ||
| 171 | class ReportDesc; | ||
| 172 | class RegionAlloc; | ||
| 173 | |||
| 174 | // Descriptor of user's memory block. | ||
| 175 | struct MBlock { | ||
| 176 | u64 siz : 48; | ||
| 177 | u64 tag : 16; | ||
| 178 | u32 stk; | ||
| 179 | u16 tid; | ||
| 180 | }; | ||
| 181 | |||
| 182 | COMPILER_CHECK(sizeof(MBlock) == 16); | ||
| 183 | |||
| 184 | enum ExternalTag : uptr { | ||
| 185 | kExternalTagNone = 0, | ||
| 186 | kExternalTagSwiftModifyingAccess = 1, | ||
| 187 | kExternalTagFirstUserAvailable = 2, | ||
| 188 | kExternalTagMax = 1024, | ||
| 189 | // Don't set kExternalTagMax over 65,536, since MBlock only stores tags | ||
| 190 | // as 16-bit values, see tsan_defs.h. | ||
| 191 | }; | ||
| 192 | |||
| 193 | } // namespace __tsan | ||
| 194 | |||
| 195 | #endif // TSAN_DEFS_H | ||
lib/tsan/tsan_dense_alloc.h created+141| ... | @@ -0,0 +1,141 @@ | ||
| 1 | //===-- tsan_dense_alloc.h --------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | // A DenseSlabAlloc is a freelist-based allocator of fixed-size objects. | ||
| 12 | // DenseSlabAllocCache is a thread-local cache for DenseSlabAlloc. | ||
| 13 | // The only difference with traditional slab allocators is that DenseSlabAlloc | ||
| 14 | // allocates/free indices of objects and provide a functionality to map | ||
| 15 | // the index onto the real pointer. The index is u32, that is, 2 times smaller | ||
| 16 | // than uptr (hense the Dense prefix). | ||
| 17 | //===----------------------------------------------------------------------===// | ||
| 18 | #ifndef TSAN_DENSE_ALLOC_H | ||
| 19 | #define TSAN_DENSE_ALLOC_H | ||
| 20 | |||
| 21 | #include "sanitizer_common/sanitizer_common.h" | ||
| 22 | #include "tsan_defs.h" | ||
| 23 | #include "tsan_mutex.h" | ||
| 24 | |||
| 25 | namespace __tsan { | ||
| 26 | |||
| 27 | class DenseSlabAllocCache { | ||
| 28 | static const uptr kSize = 128; | ||
| 29 | typedef u32 IndexT; | ||
| 30 | uptr pos; | ||
| 31 | IndexT cache[kSize]; | ||
| 32 | template<typename T, uptr kL1Size, uptr kL2Size> friend class DenseSlabAlloc; | ||
| 33 | }; | ||
| 34 | |||
| 35 | template<typename T, uptr kL1Size, uptr kL2Size> | ||
| 36 | class DenseSlabAlloc { | ||
| 37 | public: | ||
| 38 | typedef DenseSlabAllocCache Cache; | ||
| 39 | typedef typename Cache::IndexT IndexT; | ||
| 40 | |||
| 41 | explicit DenseSlabAlloc(const char *name) { | ||
| 42 | // Check that kL1Size and kL2Size are sane. | ||
| 43 | CHECK_EQ(kL1Size & (kL1Size - 1), 0); | ||
| 44 | CHECK_EQ(kL2Size & (kL2Size - 1), 0); | ||
| 45 | CHECK_GE(1ull << (sizeof(IndexT) * 8), kL1Size * kL2Size); | ||
| 46 | // Check that it makes sense to use the dense alloc. | ||
| 47 | CHECK_GE(sizeof(T), sizeof(IndexT)); | ||
| 48 | internal_memset(map_, 0, sizeof(map_)); | ||
| 49 | freelist_ = 0; | ||
| 50 | fillpos_ = 0; | ||
| 51 | name_ = name; | ||
| 52 | } | ||
| 53 | |||
| 54 | ~DenseSlabAlloc() { | ||
| 55 | for (uptr i = 0; i < kL1Size; i++) { | ||
| 56 | if (map_[i] != 0) | ||
| 57 | UnmapOrDie(map_[i], kL2Size * sizeof(T)); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | IndexT Alloc(Cache *c) { | ||
| 62 | if (c->pos == 0) | ||
| 63 | Refill(c); | ||
| 64 | return c->cache[--c->pos]; | ||
| 65 | } | ||
| 66 | |||
| 67 | void Free(Cache *c, IndexT idx) { | ||
| 68 | DCHECK_NE(idx, 0); | ||
| 69 | if (c->pos == Cache::kSize) | ||
| 70 | Drain(c); | ||
| 71 | c->cache[c->pos++] = idx; | ||
| 72 | } | ||
| 73 | |||
| 74 | T *Map(IndexT idx) { | ||
| 75 | DCHECK_NE(idx, 0); | ||
| 76 | DCHECK_LE(idx, kL1Size * kL2Size); | ||
| 77 | return &map_[idx / kL2Size][idx % kL2Size]; | ||
| 78 | } | ||
| 79 | |||
| 80 | void FlushCache(Cache *c) { | ||
| 81 | SpinMutexLock lock(&mtx_); | ||
| 82 | while (c->pos) { | ||
| 83 | IndexT idx = c->cache[--c->pos]; | ||
| 84 | *(IndexT*)Map(idx) = freelist_; | ||
| 85 | freelist_ = idx; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | void InitCache(Cache *c) { | ||
| 90 | c->pos = 0; | ||
| 91 | internal_memset(c->cache, 0, sizeof(c->cache)); | ||
| 92 | } | ||
| 93 | |||
| 94 | private: | ||
| 95 | T *map_[kL1Size]; | ||
| 96 | SpinMutex mtx_; | ||
| 97 | IndexT freelist_; | ||
| 98 | uptr fillpos_; | ||
| 99 | const char *name_; | ||
| 100 | |||
| 101 | void Refill(Cache *c) { | ||
| 102 | SpinMutexLock lock(&mtx_); | ||
| 103 | if (freelist_ == 0) { | ||
| 104 | if (fillpos_ == kL1Size) { | ||
| 105 | Printf("ThreadSanitizer: %s overflow (%zu*%zu). Dying.\n", | ||
| 106 | name_, kL1Size, kL2Size); | ||
| 107 | Die(); | ||
| 108 | } | ||
| 109 | VPrintf(2, "ThreadSanitizer: growing %s: %zu out of %zu*%zu\n", | ||
| 110 | name_, fillpos_, kL1Size, kL2Size); | ||
| 111 | T *batch = (T*)MmapOrDie(kL2Size * sizeof(T), name_); | ||
| 112 | // Reserve 0 as invalid index. | ||
| 113 | IndexT start = fillpos_ == 0 ? 1 : 0; | ||
| 114 | for (IndexT i = start; i < kL2Size; i++) { | ||
| 115 | new(batch + i) T; | ||
| 116 | *(IndexT*)(batch + i) = i + 1 + fillpos_ * kL2Size; | ||
| 117 | } | ||
| 118 | *(IndexT*)(batch + kL2Size - 1) = 0; | ||
| 119 | freelist_ = fillpos_ * kL2Size + start; | ||
| 120 | map_[fillpos_++] = batch; | ||
| 121 | } | ||
| 122 | for (uptr i = 0; i < Cache::kSize / 2 && freelist_ != 0; i++) { | ||
| 123 | IndexT idx = freelist_; | ||
| 124 | c->cache[c->pos++] = idx; | ||
| 125 | freelist_ = *(IndexT*)Map(idx); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | void Drain(Cache *c) { | ||
| 130 | SpinMutexLock lock(&mtx_); | ||
| 131 | for (uptr i = 0; i < Cache::kSize / 2; i++) { | ||
| 132 | IndexT idx = c->cache[--c->pos]; | ||
| 133 | *(IndexT*)Map(idx) = freelist_; | ||
| 134 | freelist_ = idx; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | }; | ||
| 138 | |||
| 139 | } // namespace __tsan | ||
| 140 | |||
| 141 | #endif // TSAN_DENSE_ALLOC_H | ||
lib/tsan/tsan_external.cpp created+124| ... | @@ -0,0 +1,124 @@ | ||
| 1 | //===-- tsan_external.cpp -------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #include "tsan_rtl.h" | ||
| 13 | #include "tsan_interceptors.h" | ||
| 14 | |||
| 15 | namespace __tsan { | ||
| 16 | |||
| 17 | #define CALLERPC ((uptr)__builtin_return_address(0)) | ||
| 18 | |||
| 19 | struct TagData { | ||
| 20 | const char *object_type; | ||
| 21 | const char *header; | ||
| 22 | }; | ||
| 23 | |||
| 24 | static TagData registered_tags[kExternalTagMax] = { | ||
| 25 | {}, | ||
| 26 | {"Swift variable", "Swift access race"}, | ||
| 27 | }; | ||
| 28 | static atomic_uint32_t used_tags{kExternalTagFirstUserAvailable}; | ||
| 29 | static TagData *GetTagData(uptr tag) { | ||
| 30 | // Invalid/corrupted tag? Better return NULL and let the caller deal with it. | ||
| 31 | if (tag >= atomic_load(&used_tags, memory_order_relaxed)) return nullptr; | ||
| 32 | return &registered_tags[tag]; | ||
| 33 | } | ||
| 34 | |||
| 35 | const char *GetObjectTypeFromTag(uptr tag) { | ||
| 36 | TagData *tag_data = GetTagData(tag); | ||
| 37 | return tag_data ? tag_data->object_type : nullptr; | ||
| 38 | } | ||
| 39 | |||
| 40 | const char *GetReportHeaderFromTag(uptr tag) { | ||
| 41 | TagData *tag_data = GetTagData(tag); | ||
| 42 | return tag_data ? tag_data->header : nullptr; | ||
| 43 | } | ||
| 44 | |||
| 45 | void InsertShadowStackFrameForTag(ThreadState *thr, uptr tag) { | ||
| 46 | FuncEntry(thr, (uptr)&registered_tags[tag]); | ||
| 47 | } | ||
| 48 | |||
| 49 | uptr TagFromShadowStackFrame(uptr pc) { | ||
| 50 | uptr tag_count = atomic_load(&used_tags, memory_order_relaxed); | ||
| 51 | void *pc_ptr = (void *)pc; | ||
| 52 | if (pc_ptr < GetTagData(0) || pc_ptr > GetTagData(tag_count - 1)) | ||
| 53 | return 0; | ||
| 54 | return (TagData *)pc_ptr - GetTagData(0); | ||
| 55 | } | ||
| 56 | |||
| 57 | #if !SANITIZER_GO | ||
| 58 | |||
| 59 | typedef void(*AccessFunc)(ThreadState *, uptr, uptr, int); | ||
| 60 | void ExternalAccess(void *addr, void *caller_pc, void *tag, AccessFunc access) { | ||
| 61 | CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed)); | ||
| 62 | ThreadState *thr = cur_thread(); | ||
| 63 | if (caller_pc) FuncEntry(thr, (uptr)caller_pc); | ||
| 64 | InsertShadowStackFrameForTag(thr, (uptr)tag); | ||
| 65 | bool in_ignored_lib; | ||
| 66 | if (!caller_pc || !libignore()->IsIgnored((uptr)caller_pc, &in_ignored_lib)) { | ||
| 67 | access(thr, CALLERPC, (uptr)addr, kSizeLog1); | ||
| 68 | } | ||
| 69 | FuncExit(thr); | ||
| 70 | if (caller_pc) FuncExit(thr); | ||
| 71 | } | ||
| 72 | |||
| 73 | extern "C" { | ||
| 74 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 75 | void *__tsan_external_register_tag(const char *object_type) { | ||
| 76 | uptr new_tag = atomic_fetch_add(&used_tags, 1, memory_order_relaxed); | ||
| 77 | CHECK_LT(new_tag, kExternalTagMax); | ||
| 78 | GetTagData(new_tag)->object_type = internal_strdup(object_type); | ||
| 79 | char header[127] = {0}; | ||
| 80 | internal_snprintf(header, sizeof(header), "race on %s", object_type); | ||
| 81 | GetTagData(new_tag)->header = internal_strdup(header); | ||
| 82 | return (void *)new_tag; | ||
| 83 | } | ||
| 84 | |||
| 85 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 86 | void __tsan_external_register_header(void *tag, const char *header) { | ||
| 87 | CHECK_GE((uptr)tag, kExternalTagFirstUserAvailable); | ||
| 88 | CHECK_LT((uptr)tag, kExternalTagMax); | ||
| 89 | atomic_uintptr_t *header_ptr = | ||
| 90 | (atomic_uintptr_t *)&GetTagData((uptr)tag)->header; | ||
| 91 | header = internal_strdup(header); | ||
| 92 | char *old_header = | ||
| 93 | (char *)atomic_exchange(header_ptr, (uptr)header, memory_order_seq_cst); | ||
| 94 | if (old_header) internal_free(old_header); | ||
| 95 | } | ||
| 96 | |||
| 97 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 98 | void __tsan_external_assign_tag(void *addr, void *tag) { | ||
| 99 | CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed)); | ||
| 100 | Allocator *a = allocator(); | ||
| 101 | MBlock *b = nullptr; | ||
| 102 | if (a->PointerIsMine((void *)addr)) { | ||
| 103 | void *block_begin = a->GetBlockBegin((void *)addr); | ||
| 104 | if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin); | ||
| 105 | } | ||
| 106 | if (b) { | ||
| 107 | b->tag = (uptr)tag; | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 112 | void __tsan_external_read(void *addr, void *caller_pc, void *tag) { | ||
| 113 | ExternalAccess(addr, caller_pc, tag, MemoryRead); | ||
| 114 | } | ||
| 115 | |||
| 116 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 117 | void __tsan_external_write(void *addr, void *caller_pc, void *tag) { | ||
| 118 | ExternalAccess(addr, caller_pc, tag, MemoryWrite); | ||
| 119 | } | ||
| 120 | } // extern "C" | ||
| 121 | |||
| 122 | #endif // !SANITIZER_GO | ||
| 123 | |||
| 124 | } // namespace __tsan | ||
lib/tsan/tsan_fd.cpp created+316| ... | @@ -0,0 +1,316 @@ | ||
| 1 | //===-- tsan_fd.cpp -------------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "tsan_fd.h" | ||
| 14 | #include "tsan_rtl.h" | ||
| 15 | #include <sanitizer_common/sanitizer_atomic.h> | ||
| 16 | |||
| 17 | namespace __tsan { | ||
| 18 | |||
| 19 | const int kTableSizeL1 = 1024; | ||
| 20 | const int kTableSizeL2 = 1024; | ||
| 21 | const int kTableSize = kTableSizeL1 * kTableSizeL2; | ||
| 22 | |||
| 23 | struct FdSync { | ||
| 24 | atomic_uint64_t rc; | ||
| 25 | }; | ||
| 26 | |||
| 27 | struct FdDesc { | ||
| 28 | FdSync *sync; | ||
| 29 | int creation_tid; | ||
| 30 | u32 creation_stack; | ||
| 31 | }; | ||
| 32 | |||
| 33 | struct FdContext { | ||
| 34 | atomic_uintptr_t tab[kTableSizeL1]; | ||
| 35 | // Addresses used for synchronization. | ||
| 36 | FdSync globsync; | ||
| 37 | FdSync filesync; | ||
| 38 | FdSync socksync; | ||
| 39 | u64 connectsync; | ||
| 40 | }; | ||
| 41 | |||
| 42 | static FdContext fdctx; | ||
| 43 | |||
| 44 | static bool bogusfd(int fd) { | ||
| 45 | // Apparently a bogus fd value. | ||
| 46 | return fd < 0 || fd >= kTableSize; | ||
| 47 | } | ||
| 48 | |||
| 49 | static FdSync *allocsync(ThreadState *thr, uptr pc) { | ||
| 50 | FdSync *s = (FdSync*)user_alloc_internal(thr, pc, sizeof(FdSync), | ||
| 51 | kDefaultAlignment, false); | ||
| 52 | atomic_store(&s->rc, 1, memory_order_relaxed); | ||
| 53 | return s; | ||
| 54 | } | ||
| 55 | |||
| 56 | static FdSync *ref(FdSync *s) { | ||
| 57 | if (s && atomic_load(&s->rc, memory_order_relaxed) != (u64)-1) | ||
| 58 | atomic_fetch_add(&s->rc, 1, memory_order_relaxed); | ||
| 59 | return s; | ||
| 60 | } | ||
| 61 | |||
| 62 | static void unref(ThreadState *thr, uptr pc, FdSync *s) { | ||
| 63 | if (s && atomic_load(&s->rc, memory_order_relaxed) != (u64)-1) { | ||
| 64 | if (atomic_fetch_sub(&s->rc, 1, memory_order_acq_rel) == 1) { | ||
| 65 | CHECK_NE(s, &fdctx.globsync); | ||
| 66 | CHECK_NE(s, &fdctx.filesync); | ||
| 67 | CHECK_NE(s, &fdctx.socksync); | ||
| 68 | user_free(thr, pc, s, false); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | static FdDesc *fddesc(ThreadState *thr, uptr pc, int fd) { | ||
| 74 | CHECK_GE(fd, 0); | ||
| 75 | CHECK_LT(fd, kTableSize); | ||
| 76 | atomic_uintptr_t *pl1 = &fdctx.tab[fd / kTableSizeL2]; | ||
| 77 | uptr l1 = atomic_load(pl1, memory_order_consume); | ||
| 78 | if (l1 == 0) { | ||
| 79 | uptr size = kTableSizeL2 * sizeof(FdDesc); | ||
| 80 | // We need this to reside in user memory to properly catch races on it. | ||
| 81 | void *p = user_alloc_internal(thr, pc, size, kDefaultAlignment, false); | ||
| 82 | internal_memset(p, 0, size); | ||
| 83 | MemoryResetRange(thr, (uptr)&fddesc, (uptr)p, size); | ||
| 84 | if (atomic_compare_exchange_strong(pl1, &l1, (uptr)p, memory_order_acq_rel)) | ||
| 85 | l1 = (uptr)p; | ||
| 86 | else | ||
| 87 | user_free(thr, pc, p, false); | ||
| 88 | } | ||
| 89 | FdDesc *fds = reinterpret_cast<FdDesc *>(l1); | ||
| 90 | return &fds[fd % kTableSizeL2]; | ||
| 91 | } | ||
| 92 | |||
| 93 | // pd must be already ref'ed. | ||
| 94 | static void init(ThreadState *thr, uptr pc, int fd, FdSync *s, | ||
| 95 | bool write = true) { | ||
| 96 | FdDesc *d = fddesc(thr, pc, fd); | ||
| 97 | // As a matter of fact, we don't intercept all close calls. | ||
| 98 | // See e.g. libc __res_iclose(). | ||
| 99 | if (d->sync) { | ||
| 100 | unref(thr, pc, d->sync); | ||
| 101 | d->sync = 0; | ||
| 102 | } | ||
| 103 | if (flags()->io_sync == 0) { | ||
| 104 | unref(thr, pc, s); | ||
| 105 | } else if (flags()->io_sync == 1) { | ||
| 106 | d->sync = s; | ||
| 107 | } else if (flags()->io_sync == 2) { | ||
| 108 | unref(thr, pc, s); | ||
| 109 | d->sync = &fdctx.globsync; | ||
| 110 | } | ||
| 111 | d->creation_tid = thr->tid; | ||
| 112 | d->creation_stack = CurrentStackId(thr, pc); | ||
| 113 | if (write) { | ||
| 114 | // To catch races between fd usage and open. | ||
| 115 | MemoryRangeImitateWrite(thr, pc, (uptr)d, 8); | ||
| 116 | } else { | ||
| 117 | // See the dup-related comment in FdClose. | ||
| 118 | MemoryRead(thr, pc, (uptr)d, kSizeLog8); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | void FdInit() { | ||
| 123 | atomic_store(&fdctx.globsync.rc, (u64)-1, memory_order_relaxed); | ||
| 124 | atomic_store(&fdctx.filesync.rc, (u64)-1, memory_order_relaxed); | ||
| 125 | atomic_store(&fdctx.socksync.rc, (u64)-1, memory_order_relaxed); | ||
| 126 | } | ||
| 127 | |||
| 128 | void FdOnFork(ThreadState *thr, uptr pc) { | ||
| 129 | // On fork() we need to reset all fd's, because the child is going | ||
| 130 | // close all them, and that will cause races between previous read/write | ||
| 131 | // and the close. | ||
| 132 | for (int l1 = 0; l1 < kTableSizeL1; l1++) { | ||
| 133 | FdDesc *tab = (FdDesc*)atomic_load(&fdctx.tab[l1], memory_order_relaxed); | ||
| 134 | if (tab == 0) | ||
| 135 | break; | ||
| 136 | for (int l2 = 0; l2 < kTableSizeL2; l2++) { | ||
| 137 | FdDesc *d = &tab[l2]; | ||
| 138 | MemoryResetRange(thr, pc, (uptr)d, 8); | ||
| 139 | } | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | bool FdLocation(uptr addr, int *fd, int *tid, u32 *stack) { | ||
| 144 | for (int l1 = 0; l1 < kTableSizeL1; l1++) { | ||
| 145 | FdDesc *tab = (FdDesc*)atomic_load(&fdctx.tab[l1], memory_order_relaxed); | ||
| 146 | if (tab == 0) | ||
| 147 | break; | ||
| 148 | if (addr >= (uptr)tab && addr < (uptr)(tab + kTableSizeL2)) { | ||
| 149 | int l2 = (addr - (uptr)tab) / sizeof(FdDesc); | ||
| 150 | FdDesc *d = &tab[l2]; | ||
| 151 | *fd = l1 * kTableSizeL1 + l2; | ||
| 152 | *tid = d->creation_tid; | ||
| 153 | *stack = d->creation_stack; | ||
| 154 | return true; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | return false; | ||
| 158 | } | ||
| 159 | |||
| 160 | void FdAcquire(ThreadState *thr, uptr pc, int fd) { | ||
| 161 | if (bogusfd(fd)) | ||
| 162 | return; | ||
| 163 | FdDesc *d = fddesc(thr, pc, fd); | ||
| 164 | FdSync *s = d->sync; | ||
| 165 | DPrintf("#%d: FdAcquire(%d) -> %p\n", thr->tid, fd, s); | ||
| 166 | MemoryRead(thr, pc, (uptr)d, kSizeLog8); | ||
| 167 | if (s) | ||
| 168 | Acquire(thr, pc, (uptr)s); | ||
| 169 | } | ||
| 170 | |||
| 171 | void FdRelease(ThreadState *thr, uptr pc, int fd) { | ||
| 172 | if (bogusfd(fd)) | ||
| 173 | return; | ||
| 174 | FdDesc *d = fddesc(thr, pc, fd); | ||
| 175 | FdSync *s = d->sync; | ||
| 176 | DPrintf("#%d: FdRelease(%d) -> %p\n", thr->tid, fd, s); | ||
| 177 | MemoryRead(thr, pc, (uptr)d, kSizeLog8); | ||
| 178 | if (s) | ||
| 179 | Release(thr, pc, (uptr)s); | ||
| 180 | } | ||
| 181 | |||
| 182 | void FdAccess(ThreadState *thr, uptr pc, int fd) { | ||
| 183 | DPrintf("#%d: FdAccess(%d)\n", thr->tid, fd); | ||
| 184 | if (bogusfd(fd)) | ||
| 185 | return; | ||
| 186 | FdDesc *d = fddesc(thr, pc, fd); | ||
| 187 | MemoryRead(thr, pc, (uptr)d, kSizeLog8); | ||
| 188 | } | ||
| 189 | |||
| 190 | void FdClose(ThreadState *thr, uptr pc, int fd, bool write) { | ||
| 191 | DPrintf("#%d: FdClose(%d)\n", thr->tid, fd); | ||
| 192 | if (bogusfd(fd)) | ||
| 193 | return; | ||
| 194 | FdDesc *d = fddesc(thr, pc, fd); | ||
| 195 | if (write) { | ||
| 196 | // To catch races between fd usage and close. | ||
| 197 | MemoryWrite(thr, pc, (uptr)d, kSizeLog8); | ||
| 198 | } else { | ||
| 199 | // This path is used only by dup2/dup3 calls. | ||
| 200 | // We do read instead of write because there is a number of legitimate | ||
| 201 | // cases where write would lead to false positives: | ||
| 202 | // 1. Some software dups a closed pipe in place of a socket before closing | ||
| 203 | // the socket (to prevent races actually). | ||
| 204 | // 2. Some daemons dup /dev/null in place of stdin/stdout. | ||
| 205 | // On the other hand we have not seen cases when write here catches real | ||
| 206 | // bugs. | ||
| 207 | MemoryRead(thr, pc, (uptr)d, kSizeLog8); | ||
| 208 | } | ||
| 209 | // We need to clear it, because if we do not intercept any call out there | ||
| 210 | // that creates fd, we will hit false postives. | ||
| 211 | MemoryResetRange(thr, pc, (uptr)d, 8); | ||
| 212 | unref(thr, pc, d->sync); | ||
| 213 | d->sync = 0; | ||
| 214 | d->creation_tid = 0; | ||
| 215 | d->creation_stack = 0; | ||
| 216 | } | ||
| 217 | |||
| 218 | void FdFileCreate(ThreadState *thr, uptr pc, int fd) { | ||
| 219 | DPrintf("#%d: FdFileCreate(%d)\n", thr->tid, fd); | ||
| 220 | if (bogusfd(fd)) | ||
| 221 | return; | ||
| 222 | init(thr, pc, fd, &fdctx.filesync); | ||
| 223 | } | ||
| 224 | |||
| 225 | void FdDup(ThreadState *thr, uptr pc, int oldfd, int newfd, bool write) { | ||
| 226 | DPrintf("#%d: FdDup(%d, %d)\n", thr->tid, oldfd, newfd); | ||
| 227 | if (bogusfd(oldfd) || bogusfd(newfd)) | ||
| 228 | return; | ||
| 229 | // Ignore the case when user dups not yet connected socket. | ||
| 230 | FdDesc *od = fddesc(thr, pc, oldfd); | ||
| 231 | MemoryRead(thr, pc, (uptr)od, kSizeLog8); | ||
| 232 | FdClose(thr, pc, newfd, write); | ||
| 233 | init(thr, pc, newfd, ref(od->sync), write); | ||
| 234 | } | ||
| 235 | |||
| 236 | void FdPipeCreate(ThreadState *thr, uptr pc, int rfd, int wfd) { | ||
| 237 | DPrintf("#%d: FdCreatePipe(%d, %d)\n", thr->tid, rfd, wfd); | ||
| 238 | FdSync *s = allocsync(thr, pc); | ||
| 239 | init(thr, pc, rfd, ref(s)); | ||
| 240 | init(thr, pc, wfd, ref(s)); | ||
| 241 | unref(thr, pc, s); | ||
| 242 | } | ||
| 243 | |||
| 244 | void FdEventCreate(ThreadState *thr, uptr pc, int fd) { | ||
| 245 | DPrintf("#%d: FdEventCreate(%d)\n", thr->tid, fd); | ||
| 246 | if (bogusfd(fd)) | ||
| 247 | return; | ||
| 248 | init(thr, pc, fd, allocsync(thr, pc)); | ||
| 249 | } | ||
| 250 | |||
| 251 | void FdSignalCreate(ThreadState *thr, uptr pc, int fd) { | ||
| 252 | DPrintf("#%d: FdSignalCreate(%d)\n", thr->tid, fd); | ||
| 253 | if (bogusfd(fd)) | ||
| 254 | return; | ||
| 255 | init(thr, pc, fd, 0); | ||
| 256 | } | ||
| 257 | |||
| 258 | void FdInotifyCreate(ThreadState *thr, uptr pc, int fd) { | ||
| 259 | DPrintf("#%d: FdInotifyCreate(%d)\n", thr->tid, fd); | ||
| 260 | if (bogusfd(fd)) | ||
| 261 | return; | ||
| 262 | init(thr, pc, fd, 0); | ||
| 263 | } | ||
| 264 | |||
| 265 | void FdPollCreate(ThreadState *thr, uptr pc, int fd) { | ||
| 266 | DPrintf("#%d: FdPollCreate(%d)\n", thr->tid, fd); | ||
| 267 | if (bogusfd(fd)) | ||
| 268 | return; | ||
| 269 | init(thr, pc, fd, allocsync(thr, pc)); | ||
| 270 | } | ||
| 271 | |||
| 272 | void FdSocketCreate(ThreadState *thr, uptr pc, int fd) { | ||
| 273 | DPrintf("#%d: FdSocketCreate(%d)\n", thr->tid, fd); | ||
| 274 | if (bogusfd(fd)) | ||
| 275 | return; | ||
| 276 | // It can be a UDP socket. | ||
| 277 | init(thr, pc, fd, &fdctx.socksync); | ||
| 278 | } | ||
| 279 | |||
| 280 | void FdSocketAccept(ThreadState *thr, uptr pc, int fd, int newfd) { | ||
| 281 | DPrintf("#%d: FdSocketAccept(%d, %d)\n", thr->tid, fd, newfd); | ||
| 282 | if (bogusfd(fd)) | ||
| 283 | return; | ||
| 284 | // Synchronize connect->accept. | ||
| 285 | Acquire(thr, pc, (uptr)&fdctx.connectsync); | ||
| 286 | init(thr, pc, newfd, &fdctx.socksync); | ||
| 287 | } | ||
| 288 | |||
| 289 | void FdSocketConnecting(ThreadState *thr, uptr pc, int fd) { | ||
| 290 | DPrintf("#%d: FdSocketConnecting(%d)\n", thr->tid, fd); | ||
| 291 | if (bogusfd(fd)) | ||
| 292 | return; | ||
| 293 | // Synchronize connect->accept. | ||
| 294 | Release(thr, pc, (uptr)&fdctx.connectsync); | ||
| 295 | } | ||
| 296 | |||
| 297 | void FdSocketConnect(ThreadState *thr, uptr pc, int fd) { | ||
| 298 | DPrintf("#%d: FdSocketConnect(%d)\n", thr->tid, fd); | ||
| 299 | if (bogusfd(fd)) | ||
| 300 | return; | ||
| 301 | init(thr, pc, fd, &fdctx.socksync); | ||
| 302 | } | ||
| 303 | |||
| 304 | uptr File2addr(const char *path) { | ||
| 305 | (void)path; | ||
| 306 | static u64 addr; | ||
| 307 | return (uptr)&addr; | ||
| 308 | } | ||
| 309 | |||
| 310 | uptr Dir2addr(const char *path) { | ||
| 311 | (void)path; | ||
| 312 | static u64 addr; | ||
| 313 | return (uptr)&addr; | ||
| 314 | } | ||
| 315 | |||
| 316 | } // namespace __tsan | ||
lib/tsan/tsan_fd.h created+64| ... | @@ -0,0 +1,64 @@ | ||
| 1 | //===-- tsan_fd.h -----------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | // This file handles synchronization via IO. | ||
| 12 | // People use IO for synchronization along the lines of: | ||
| 13 | // | ||
| 14 | // int X; | ||
| 15 | // int client_socket; // initialized elsewhere | ||
| 16 | // int server_socket; // initialized elsewhere | ||
| 17 | // | ||
| 18 | // Thread 1: | ||
| 19 | // X = 42; | ||
| 20 | // send(client_socket, ...); | ||
| 21 | // | ||
| 22 | // Thread 2: | ||
| 23 | // if (recv(server_socket, ...) > 0) | ||
| 24 | // assert(X == 42); | ||
| 25 | // | ||
| 26 | // This file determines the scope of the file descriptor (pipe, socket, | ||
| 27 | // all local files, etc) and executes acquire and release operations on | ||
| 28 | // the scope as necessary. Some scopes are very fine grained (e.g. pipe | ||
| 29 | // operations synchronize only with operations on the same pipe), while | ||
| 30 | // others are corse-grained (e.g. all operations on local files synchronize | ||
| 31 | // with each other). | ||
| 32 | //===----------------------------------------------------------------------===// | ||
| 33 | #ifndef TSAN_FD_H | ||
| 34 | #define TSAN_FD_H | ||
| 35 | |||
| 36 | #include "tsan_rtl.h" | ||
| 37 | |||
| 38 | namespace __tsan { | ||
| 39 | |||
| 40 | void FdInit(); | ||
| 41 | void FdAcquire(ThreadState *thr, uptr pc, int fd); | ||
| 42 | void FdRelease(ThreadState *thr, uptr pc, int fd); | ||
| 43 | void FdAccess(ThreadState *thr, uptr pc, int fd); | ||
| 44 | void FdClose(ThreadState *thr, uptr pc, int fd, bool write = true); | ||
| 45 | void FdFileCreate(ThreadState *thr, uptr pc, int fd); | ||
| 46 | void FdDup(ThreadState *thr, uptr pc, int oldfd, int newfd, bool write); | ||
| 47 | void FdPipeCreate(ThreadState *thr, uptr pc, int rfd, int wfd); | ||
| 48 | void FdEventCreate(ThreadState *thr, uptr pc, int fd); | ||
| 49 | void FdSignalCreate(ThreadState *thr, uptr pc, int fd); | ||
| 50 | void FdInotifyCreate(ThreadState *thr, uptr pc, int fd); | ||
| 51 | void FdPollCreate(ThreadState *thr, uptr pc, int fd); | ||
| 52 | void FdSocketCreate(ThreadState *thr, uptr pc, int fd); | ||
| 53 | void FdSocketAccept(ThreadState *thr, uptr pc, int fd, int newfd); | ||
| 54 | void FdSocketConnecting(ThreadState *thr, uptr pc, int fd); | ||
| 55 | void FdSocketConnect(ThreadState *thr, uptr pc, int fd); | ||
| 56 | bool FdLocation(uptr addr, int *fd, int *tid, u32 *stack); | ||
| 57 | void FdOnFork(ThreadState *thr, uptr pc); | ||
| 58 | |||
| 59 | uptr File2addr(const char *path); | ||
| 60 | uptr Dir2addr(const char *path); | ||
| 61 | |||
| 62 | } // namespace __tsan | ||
| 63 | |||
| 64 | #endif // TSAN_INTERFACE_H | ||
lib/tsan/tsan_flags.cpp created+125| ... | @@ -0,0 +1,125 @@ | ||
| 1 | //===-- tsan_flags.cpp ----------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_common/sanitizer_flags.h" | ||
| 14 | #include "sanitizer_common/sanitizer_flag_parser.h" | ||
| 15 | #include "sanitizer_common/sanitizer_libc.h" | ||
| 16 | #include "tsan_flags.h" | ||
| 17 | #include "tsan_rtl.h" | ||
| 18 | #include "tsan_mman.h" | ||
| 19 | #include "ubsan/ubsan_flags.h" | ||
| 20 | |||
| 21 | namespace __tsan { | ||
| 22 | |||
| 23 | // Can be overriden in frontend. | ||
| 24 | #ifdef TSAN_EXTERNAL_HOOKS | ||
| 25 | extern "C" const char* __tsan_default_options(); | ||
| 26 | #else | ||
| 27 | SANITIZER_WEAK_DEFAULT_IMPL | ||
| 28 | const char *__tsan_default_options() { | ||
| 29 | return ""; | ||
| 30 | } | ||
| 31 | #endif | ||
| 32 | |||
| 33 | void Flags::SetDefaults() { | ||
| 34 | #define TSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; | ||
| 35 | #include "tsan_flags.inc" | ||
| 36 | #undef TSAN_FLAG | ||
| 37 | // DDFlags | ||
| 38 | second_deadlock_stack = false; | ||
| 39 | } | ||
| 40 | |||
| 41 | void RegisterTsanFlags(FlagParser *parser, Flags *f) { | ||
| 42 | #define TSAN_FLAG(Type, Name, DefaultValue, Description) \ | ||
| 43 | RegisterFlag(parser, #Name, Description, &f->Name); | ||
| 44 | #include "tsan_flags.inc" | ||
| 45 | #undef TSAN_FLAG | ||
| 46 | // DDFlags | ||
| 47 | RegisterFlag(parser, "second_deadlock_stack", | ||
| 48 | "Report where each mutex is locked in deadlock reports", | ||
| 49 | &f->second_deadlock_stack); | ||
| 50 | } | ||
| 51 | |||
| 52 | void InitializeFlags(Flags *f, const char *env, const char *env_option_name) { | ||
| 53 | SetCommonFlagsDefaults(); | ||
| 54 | { | ||
| 55 | // Override some common flags defaults. | ||
| 56 | CommonFlags cf; | ||
| 57 | cf.CopyFrom(*common_flags()); | ||
| 58 | cf.allow_addr2line = true; | ||
| 59 | if (SANITIZER_GO) { | ||
| 60 | // Does not work as expected for Go: runtime handles SIGABRT and crashes. | ||
| 61 | cf.abort_on_error = false; | ||
| 62 | // Go does not have mutexes. | ||
| 63 | cf.detect_deadlocks = false; | ||
| 64 | } | ||
| 65 | cf.print_suppressions = false; | ||
| 66 | cf.stack_trace_format = " #%n %f %S %M"; | ||
| 67 | cf.exitcode = 66; | ||
| 68 | cf.intercept_tls_get_addr = true; | ||
| 69 | OverrideCommonFlags(cf); | ||
| 70 | } | ||
| 71 | |||
| 72 | f->SetDefaults(); | ||
| 73 | |||
| 74 | FlagParser parser; | ||
| 75 | RegisterTsanFlags(&parser, f); | ||
| 76 | RegisterCommonFlags(&parser); | ||
| 77 | |||
| 78 | #if TSAN_CONTAINS_UBSAN | ||
| 79 | __ubsan::Flags *uf = __ubsan::flags(); | ||
| 80 | uf->SetDefaults(); | ||
| 81 | |||
| 82 | FlagParser ubsan_parser; | ||
| 83 | __ubsan::RegisterUbsanFlags(&ubsan_parser, uf); | ||
| 84 | RegisterCommonFlags(&ubsan_parser); | ||
| 85 | #endif | ||
| 86 | |||
| 87 | // Let a frontend override. | ||
| 88 | parser.ParseString(__tsan_default_options()); | ||
| 89 | #if TSAN_CONTAINS_UBSAN | ||
| 90 | const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions(); | ||
| 91 | ubsan_parser.ParseString(ubsan_default_options); | ||
| 92 | #endif | ||
| 93 | // Override from command line. | ||
| 94 | parser.ParseString(env, env_option_name); | ||
| 95 | #if TSAN_CONTAINS_UBSAN | ||
| 96 | ubsan_parser.ParseStringFromEnv("UBSAN_OPTIONS"); | ||
| 97 | #endif | ||
| 98 | |||
| 99 | // Sanity check. | ||
| 100 | if (!f->report_bugs) { | ||
| 101 | f->report_thread_leaks = false; | ||
| 102 | f->report_destroy_locked = false; | ||
| 103 | f->report_signal_unsafe = false; | ||
| 104 | } | ||
| 105 | |||
| 106 | InitializeCommonFlags(); | ||
| 107 | |||
| 108 | if (Verbosity()) ReportUnrecognizedFlags(); | ||
| 109 | |||
| 110 | if (common_flags()->help) parser.PrintFlagDescriptions(); | ||
| 111 | |||
| 112 | if (f->history_size < 0 || f->history_size > 7) { | ||
| 113 | Printf("ThreadSanitizer: incorrect value for history_size" | ||
| 114 | " (must be [0..7])\n"); | ||
| 115 | Die(); | ||
| 116 | } | ||
| 117 | |||
| 118 | if (f->io_sync < 0 || f->io_sync > 2) { | ||
| 119 | Printf("ThreadSanitizer: incorrect value for io_sync" | ||
| 120 | " (must be [0..2])\n"); | ||
| 121 | Die(); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | } // namespace __tsan | ||
lib/tsan/tsan_flags.h created+34| ... | @@ -0,0 +1,34 @@ | ||
| 1 | //===-- tsan_flags.h --------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // NOTE: This file may be included into user code. | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef TSAN_FLAGS_H | ||
| 14 | #define TSAN_FLAGS_H | ||
| 15 | |||
| 16 | #include "sanitizer_common/sanitizer_flags.h" | ||
| 17 | #include "sanitizer_common/sanitizer_deadlock_detector_interface.h" | ||
| 18 | |||
| 19 | namespace __tsan { | ||
| 20 | |||
| 21 | struct Flags : DDFlags { | ||
| 22 | #define TSAN_FLAG(Type, Name, DefaultValue, Description) Type Name; | ||
| 23 | #include "tsan_flags.inc" | ||
| 24 | #undef TSAN_FLAG | ||
| 25 | |||
| 26 | void SetDefaults(); | ||
| 27 | void ParseFromString(const char *str); | ||
| 28 | }; | ||
| 29 | |||
| 30 | void InitializeFlags(Flags *flags, const char *env, | ||
| 31 | const char *env_option_name = nullptr); | ||
| 32 | } // namespace __tsan | ||
| 33 | |||
| 34 | #endif // TSAN_FLAGS_H | ||
lib/tsan/tsan_flags.inc created+85| ... | @@ -0,0 +1,85 @@ | ||
| 1 | //===-- tsan_flags.inc ------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // TSan runtime flags. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef TSAN_FLAG | ||
| 13 | # error "Define TSAN_FLAG prior to including this file!" | ||
| 14 | #endif | ||
| 15 | |||
| 16 | // TSAN_FLAG(Type, Name, DefaultValue, Description) | ||
| 17 | // See COMMON_FLAG in sanitizer_flags.inc for more details. | ||
| 18 | |||
| 19 | TSAN_FLAG(bool, enable_annotations, true, | ||
| 20 | "Enable dynamic annotations, otherwise they are no-ops.") | ||
| 21 | // Suppress a race report if we've already output another race report | ||
| 22 | // with the same stack. | ||
| 23 | TSAN_FLAG(bool, suppress_equal_stacks, true, | ||
| 24 | "Suppress a race report if we've already output another race report " | ||
| 25 | "with the same stack.") | ||
| 26 | TSAN_FLAG(bool, suppress_equal_addresses, true, | ||
| 27 | "Suppress a race report if we've already output another race report " | ||
| 28 | "on the same address.") | ||
| 29 | |||
| 30 | TSAN_FLAG(bool, report_bugs, true, | ||
| 31 | "Turns off bug reporting entirely (useful for benchmarking).") | ||
| 32 | TSAN_FLAG(bool, report_thread_leaks, true, "Report thread leaks at exit?") | ||
| 33 | TSAN_FLAG(bool, report_destroy_locked, true, | ||
| 34 | "Report destruction of a locked mutex?") | ||
| 35 | TSAN_FLAG(bool, report_mutex_bugs, true, | ||
| 36 | "Report incorrect usages of mutexes and mutex annotations?") | ||
| 37 | TSAN_FLAG(bool, report_signal_unsafe, true, | ||
| 38 | "Report violations of async signal-safety " | ||
| 39 | "(e.g. malloc() call from a signal handler).") | ||
| 40 | TSAN_FLAG(bool, report_atomic_races, true, | ||
| 41 | "Report races between atomic and plain memory accesses.") | ||
| 42 | TSAN_FLAG( | ||
| 43 | bool, force_seq_cst_atomics, false, | ||
| 44 | "If set, all atomics are effectively sequentially consistent (seq_cst), " | ||
| 45 | "regardless of what user actually specified.") | ||
| 46 | TSAN_FLAG(bool, print_benign, false, "Print matched \"benign\" races at exit.") | ||
| 47 | TSAN_FLAG(bool, halt_on_error, false, "Exit after first reported error.") | ||
| 48 | TSAN_FLAG(int, atexit_sleep_ms, 1000, | ||
| 49 | "Sleep in main thread before exiting for that many ms " | ||
| 50 | "(useful to catch \"at exit\" races).") | ||
| 51 | TSAN_FLAG(const char *, profile_memory, "", | ||
| 52 | "If set, periodically write memory profile to that file.") | ||
| 53 | TSAN_FLAG(int, flush_memory_ms, 0, "Flush shadow memory every X ms.") | ||
| 54 | TSAN_FLAG(int, flush_symbolizer_ms, 5000, "Flush symbolizer caches every X ms.") | ||
| 55 | TSAN_FLAG( | ||
| 56 | int, memory_limit_mb, 0, | ||
| 57 | "Resident memory limit in MB to aim at." | ||
| 58 | "If the process consumes more memory, then TSan will flush shadow memory.") | ||
| 59 | TSAN_FLAG(bool, stop_on_start, false, | ||
| 60 | "Stops on start until __tsan_resume() is called (for debugging).") | ||
| 61 | TSAN_FLAG(bool, running_on_valgrind, false, | ||
| 62 | "Controls whether RunningOnValgrind() returns true or false.") | ||
| 63 | // There are a lot of goroutines in Go, so we use smaller history. | ||
| 64 | TSAN_FLAG( | ||
| 65 | int, history_size, SANITIZER_GO ? 1 : 3, | ||
| 66 | "Per-thread history size, controls how many previous memory accesses " | ||
| 67 | "are remembered per thread. Possible values are [0..7]. " | ||
| 68 | "history_size=0 amounts to 32K memory accesses. Each next value doubles " | ||
| 69 | "the amount of memory accesses, up to history_size=7 that amounts to " | ||
| 70 | "4M memory accesses. The default value is 2 (128K memory accesses).") | ||
| 71 | TSAN_FLAG(int, io_sync, 1, | ||
| 72 | "Controls level of synchronization implied by IO operations. " | ||
| 73 | "0 - no synchronization " | ||
| 74 | "1 - reasonable level of synchronization (write->read)" | ||
| 75 | "2 - global synchronization of all IO operations.") | ||
| 76 | TSAN_FLAG(bool, die_after_fork, true, | ||
| 77 | "Die after multi-threaded fork if the child creates new threads.") | ||
| 78 | TSAN_FLAG(const char *, suppressions, "", "Suppressions file name.") | ||
| 79 | TSAN_FLAG(bool, ignore_interceptors_accesses, SANITIZER_MAC ? true : false, | ||
| 80 | "Ignore reads and writes from all interceptors.") | ||
| 81 | TSAN_FLAG(bool, ignore_noninstrumented_modules, SANITIZER_MAC ? true : false, | ||
| 82 | "Interceptors should only detect races when called from instrumented " | ||
| 83 | "modules.") | ||
| 84 | TSAN_FLAG(bool, shared_ptr_interceptor, true, | ||
| 85 | "Track atomic reference counting in libc++ shared_ptr and weak_ptr.") | ||
lib/tsan/tsan_ignoreset.cpp created+46| ... | @@ -0,0 +1,46 @@ | ||
| 1 | //===-- tsan_ignoreset.cpp ------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #include "tsan_ignoreset.h" | ||
| 13 | |||
| 14 | namespace __tsan { | ||
| 15 | |||
| 16 | const uptr IgnoreSet::kMaxSize; | ||
| 17 | |||
| 18 | IgnoreSet::IgnoreSet() | ||
| 19 | : size_() { | ||
| 20 | } | ||
| 21 | |||
| 22 | void IgnoreSet::Add(u32 stack_id) { | ||
| 23 | if (size_ == kMaxSize) | ||
| 24 | return; | ||
| 25 | for (uptr i = 0; i < size_; i++) { | ||
| 26 | if (stacks_[i] == stack_id) | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | stacks_[size_++] = stack_id; | ||
| 30 | } | ||
| 31 | |||
| 32 | void IgnoreSet::Reset() { | ||
| 33 | size_ = 0; | ||
| 34 | } | ||
| 35 | |||
| 36 | uptr IgnoreSet::Size() const { | ||
| 37 | return size_; | ||
| 38 | } | ||
| 39 | |||
| 40 | u32 IgnoreSet::At(uptr i) const { | ||
| 41 | CHECK_LT(i, size_); | ||
| 42 | CHECK_LE(size_, kMaxSize); | ||
| 43 | return stacks_[i]; | ||
| 44 | } | ||
| 45 | |||
| 46 | } // namespace __tsan | ||
lib/tsan/tsan_ignoreset.h created+37| ... | @@ -0,0 +1,37 @@ | ||
| 1 | //===-- tsan_ignoreset.h ----------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | // IgnoreSet holds a set of stack traces where ignores were enabled. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | #ifndef TSAN_IGNORESET_H | ||
| 14 | #define TSAN_IGNORESET_H | ||
| 15 | |||
| 16 | #include "tsan_defs.h" | ||
| 17 | |||
| 18 | namespace __tsan { | ||
| 19 | |||
| 20 | class IgnoreSet { | ||
| 21 | public: | ||
| 22 | static const uptr kMaxSize = 16; | ||
| 23 | |||
| 24 | IgnoreSet(); | ||
| 25 | void Add(u32 stack_id); | ||
| 26 | void Reset(); | ||
| 27 | uptr Size() const; | ||
| 28 | u32 At(uptr i) const; | ||
| 29 | |||
| 30 | private: | ||
| 31 | uptr size_; | ||
| 32 | u32 stacks_[kMaxSize]; | ||
| 33 | }; | ||
| 34 | |||
| 35 | } // namespace __tsan | ||
| 36 | |||
| 37 | #endif // TSAN_IGNORESET_H | ||
lib/tsan/tsan_interceptors.h created+76| ... | @@ -0,0 +1,76 @@ | ||
| 1 | #ifndef TSAN_INTERCEPTORS_H | ||
| 2 | #define TSAN_INTERCEPTORS_H | ||
| 3 | |||
| 4 | #include "sanitizer_common/sanitizer_stacktrace.h" | ||
| 5 | #include "tsan_rtl.h" | ||
| 6 | |||
| 7 | namespace __tsan { | ||
| 8 | |||
| 9 | class ScopedInterceptor { | ||
| 10 | public: | ||
| 11 | ScopedInterceptor(ThreadState *thr, const char *fname, uptr pc); | ||
| 12 | ~ScopedInterceptor(); | ||
| 13 | void DisableIgnores(); | ||
| 14 | void EnableIgnores(); | ||
| 15 | private: | ||
| 16 | ThreadState *const thr_; | ||
| 17 | const uptr pc_; | ||
| 18 | bool in_ignored_lib_; | ||
| 19 | bool ignoring_; | ||
| 20 | }; | ||
| 21 | |||
| 22 | LibIgnore *libignore(); | ||
| 23 | |||
| 24 | #if !SANITIZER_GO | ||
| 25 | INLINE bool in_symbolizer() { | ||
| 26 | cur_thread_init(); | ||
| 27 | return UNLIKELY(cur_thread()->in_symbolizer); | ||
| 28 | } | ||
| 29 | #endif | ||
| 30 | |||
| 31 | } // namespace __tsan | ||
| 32 | |||
| 33 | #define SCOPED_INTERCEPTOR_RAW(func, ...) \ | ||
| 34 | cur_thread_init(); \ | ||
| 35 | ThreadState *thr = cur_thread(); \ | ||
| 36 | const uptr caller_pc = GET_CALLER_PC(); \ | ||
| 37 | ScopedInterceptor si(thr, #func, caller_pc); \ | ||
| 38 | const uptr pc = StackTrace::GetCurrentPc(); \ | ||
| 39 | (void)pc; \ | ||
| 40 | /**/ | ||
| 41 | |||
| 42 | #define SCOPED_TSAN_INTERCEPTOR(func, ...) \ | ||
| 43 | SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \ | ||
| 44 | if (REAL(func) == 0) { \ | ||
| 45 | Report("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \ | ||
| 46 | Die(); \ | ||
| 47 | } \ | ||
| 48 | if (!thr->is_inited || thr->ignore_interceptors || thr->in_ignored_lib) \ | ||
| 49 | return REAL(func)(__VA_ARGS__); \ | ||
| 50 | /**/ | ||
| 51 | |||
| 52 | #define SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START() \ | ||
| 53 | si.DisableIgnores(); | ||
| 54 | |||
| 55 | #define SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END() \ | ||
| 56 | si.EnableIgnores(); | ||
| 57 | |||
| 58 | #define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__) | ||
| 59 | |||
| 60 | #if SANITIZER_NETBSD | ||
| 61 | # define TSAN_INTERCEPTOR_NETBSD_ALIAS(ret, func, ...) \ | ||
| 62 | TSAN_INTERCEPTOR(ret, __libc_##func, __VA_ARGS__) \ | ||
| 63 | ALIAS(WRAPPER_NAME(pthread_##func)); | ||
| 64 | # define TSAN_INTERCEPTOR_NETBSD_ALIAS_THR(ret, func, ...) \ | ||
| 65 | TSAN_INTERCEPTOR(ret, __libc_thr_##func, __VA_ARGS__) \ | ||
| 66 | ALIAS(WRAPPER_NAME(pthread_##func)); | ||
| 67 | # define TSAN_INTERCEPTOR_NETBSD_ALIAS_THR2(ret, func, func2, ...) \ | ||
| 68 | TSAN_INTERCEPTOR(ret, __libc_thr_##func, __VA_ARGS__) \ | ||
| 69 | ALIAS(WRAPPER_NAME(pthread_##func2)); | ||
| 70 | #else | ||
| 71 | # define TSAN_INTERCEPTOR_NETBSD_ALIAS(ret, func, ...) | ||
| 72 | # define TSAN_INTERCEPTOR_NETBSD_ALIAS_THR(ret, func, ...) | ||
| 73 | # define TSAN_INTERCEPTOR_NETBSD_ALIAS_THR2(ret, func, func2, ...) | ||
| 74 | #endif | ||
| 75 | |||
| 76 | #endif // TSAN_INTERCEPTORS_H | ||
lib/tsan/tsan_interceptors_posix.cpp created+2854| ... | @@ -0,0 +1,2854 @@ | ||
| 1 | //===-- tsan_interceptors_posix.cpp ---------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | // FIXME: move as many interceptors as possible into | ||
| 12 | // sanitizer_common/sanitizer_common_interceptors.inc | ||
| 13 | //===----------------------------------------------------------------------===// | ||
| 14 | |||
| 15 | #include "sanitizer_common/sanitizer_atomic.h" | ||
| 16 | #include "sanitizer_common/sanitizer_errno.h" | ||
| 17 | #include "sanitizer_common/sanitizer_libc.h" | ||
| 18 | #include "sanitizer_common/sanitizer_linux.h" | ||
| 19 | #include "sanitizer_common/sanitizer_platform_limits_netbsd.h" | ||
| 20 | #include "sanitizer_common/sanitizer_platform_limits_posix.h" | ||
| 21 | #include "sanitizer_common/sanitizer_placement_new.h" | ||
| 22 | #include "sanitizer_common/sanitizer_posix.h" | ||
| 23 | #include "sanitizer_common/sanitizer_stacktrace.h" | ||
| 24 | #include "sanitizer_common/sanitizer_tls_get_addr.h" | ||
| 25 | #include "interception/interception.h" | ||
| 26 | #include "tsan_interceptors.h" | ||
| 27 | #include "tsan_interface.h" | ||
| 28 | #include "tsan_platform.h" | ||
| 29 | #include "tsan_suppressions.h" | ||
| 30 | #include "tsan_rtl.h" | ||
| 31 | #include "tsan_mman.h" | ||
| 32 | #include "tsan_fd.h" | ||
| 33 | |||
| 34 | using namespace __tsan; | ||
| 35 | |||
| 36 | #if SANITIZER_FREEBSD || SANITIZER_MAC | ||
| 37 | #define stdout __stdoutp | ||
| 38 | #define stderr __stderrp | ||
| 39 | #endif | ||
| 40 | |||
| 41 | #if SANITIZER_NETBSD | ||
| 42 | #define dirfd(dirp) (*(int *)(dirp)) | ||
| 43 | #define fileno_unlocked(fp) \ | ||
| 44 | (((__sanitizer_FILE *)fp)->_file == -1 \ | ||
| 45 | ? -1 \ | ||
| 46 | : (int)(unsigned short)(((__sanitizer_FILE *)fp)->_file)) | ||
| 47 | |||
| 48 | #define stdout ((__sanitizer_FILE*)&__sF[1]) | ||
| 49 | #define stderr ((__sanitizer_FILE*)&__sF[2]) | ||
| 50 | |||
| 51 | #define nanosleep __nanosleep50 | ||
| 52 | #define vfork __vfork14 | ||
| 53 | #endif | ||
| 54 | |||
| 55 | #if SANITIZER_ANDROID | ||
| 56 | #define mallopt(a, b) | ||
| 57 | #endif | ||
| 58 | |||
| 59 | #ifdef __mips__ | ||
| 60 | const int kSigCount = 129; | ||
| 61 | #else | ||
| 62 | const int kSigCount = 65; | ||
| 63 | #endif | ||
| 64 | |||
| 65 | #ifdef __mips__ | ||
| 66 | struct ucontext_t { | ||
| 67 | u64 opaque[768 / sizeof(u64) + 1]; | ||
| 68 | }; | ||
| 69 | #else | ||
| 70 | struct ucontext_t { | ||
| 71 | // The size is determined by looking at sizeof of real ucontext_t on linux. | ||
| 72 | u64 opaque[936 / sizeof(u64) + 1]; | ||
| 73 | }; | ||
| 74 | #endif | ||
| 75 | |||
| 76 | #if defined(__x86_64__) || defined(__mips__) || SANITIZER_PPC64V1 | ||
| 77 | #define PTHREAD_ABI_BASE "GLIBC_2.3.2" | ||
| 78 | #elif defined(__aarch64__) || SANITIZER_PPC64V2 | ||
| 79 | #define PTHREAD_ABI_BASE "GLIBC_2.17" | ||
| 80 | #endif | ||
| 81 | |||
| 82 | extern "C" int pthread_attr_init(void *attr); | ||
| 83 | extern "C" int pthread_attr_destroy(void *attr); | ||
| 84 | DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *) | ||
| 85 | extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize); | ||
| 86 | extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v)); | ||
| 87 | extern "C" int pthread_setspecific(unsigned key, const void *v); | ||
| 88 | DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *) | ||
| 89 | DECLARE_REAL(int, fflush, __sanitizer_FILE *fp) | ||
| 90 | DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr size) | ||
| 91 | DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr) | ||
| 92 | extern "C" void *pthread_self(); | ||
| 93 | extern "C" void _exit(int status); | ||
| 94 | #if !SANITIZER_NETBSD | ||
| 95 | extern "C" int fileno_unlocked(void *stream); | ||
| 96 | extern "C" int dirfd(void *dirp); | ||
| 97 | #endif | ||
| 98 | #if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_NETBSD | ||
| 99 | extern "C" int mallopt(int param, int value); | ||
| 100 | #endif | ||
| 101 | #if SANITIZER_NETBSD | ||
| 102 | extern __sanitizer_FILE __sF[]; | ||
| 103 | #else | ||
| 104 | extern __sanitizer_FILE *stdout, *stderr; | ||
| 105 | #endif | ||
| 106 | #if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD | ||
| 107 | const int PTHREAD_MUTEX_RECURSIVE = 1; | ||
| 108 | const int PTHREAD_MUTEX_RECURSIVE_NP = 1; | ||
| 109 | #else | ||
| 110 | const int PTHREAD_MUTEX_RECURSIVE = 2; | ||
| 111 | const int PTHREAD_MUTEX_RECURSIVE_NP = 2; | ||
| 112 | #endif | ||
| 113 | #if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD | ||
| 114 | const int EPOLL_CTL_ADD = 1; | ||
| 115 | #endif | ||
| 116 | const int SIGILL = 4; | ||
| 117 | const int SIGTRAP = 5; | ||
| 118 | const int SIGABRT = 6; | ||
| 119 | const int SIGFPE = 8; | ||
| 120 | const int SIGSEGV = 11; | ||
| 121 | const int SIGPIPE = 13; | ||
| 122 | const int SIGTERM = 15; | ||
| 123 | #if defined(__mips__) || SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD | ||
| 124 | const int SIGBUS = 10; | ||
| 125 | const int SIGSYS = 12; | ||
| 126 | #else | ||
| 127 | const int SIGBUS = 7; | ||
| 128 | const int SIGSYS = 31; | ||
| 129 | #endif | ||
| 130 | void *const MAP_FAILED = (void*)-1; | ||
| 131 | #if SANITIZER_NETBSD | ||
| 132 | const int PTHREAD_BARRIER_SERIAL_THREAD = 1234567; | ||
| 133 | #elif !SANITIZER_MAC | ||
| 134 | const int PTHREAD_BARRIER_SERIAL_THREAD = -1; | ||
| 135 | #endif | ||
| 136 | const int MAP_FIXED = 0x10; | ||
| 137 | typedef long long_t; | ||
| 138 | |||
| 139 | // From /usr/include/unistd.h | ||
| 140 | # define F_ULOCK 0 /* Unlock a previously locked region. */ | ||
| 141 | # define F_LOCK 1 /* Lock a region for exclusive use. */ | ||
| 142 | # define F_TLOCK 2 /* Test and lock a region for exclusive use. */ | ||
| 143 | # define F_TEST 3 /* Test a region for other processes locks. */ | ||
| 144 | |||
| 145 | #if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD | ||
| 146 | const int SA_SIGINFO = 0x40; | ||
| 147 | const int SIG_SETMASK = 3; | ||
| 148 | #elif defined(__mips__) | ||
| 149 | const int SA_SIGINFO = 8; | ||
| 150 | const int SIG_SETMASK = 3; | ||
| 151 | #else | ||
| 152 | const int SA_SIGINFO = 4; | ||
| 153 | const int SIG_SETMASK = 2; | ||
| 154 | #endif | ||
| 155 | |||
| 156 | #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED \ | ||
| 157 | (cur_thread_init(), !cur_thread()->is_inited) | ||
| 158 | |||
| 159 | namespace __tsan { | ||
| 160 | struct SignalDesc { | ||
| 161 | bool armed; | ||
| 162 | bool sigaction; | ||
| 163 | __sanitizer_siginfo siginfo; | ||
| 164 | ucontext_t ctx; | ||
| 165 | }; | ||
| 166 | |||
| 167 | struct ThreadSignalContext { | ||
| 168 | int int_signal_send; | ||
| 169 | atomic_uintptr_t in_blocking_func; | ||
| 170 | atomic_uintptr_t have_pending_signals; | ||
| 171 | SignalDesc pending_signals[kSigCount]; | ||
| 172 | // emptyset and oldset are too big for stack. | ||
| 173 | __sanitizer_sigset_t emptyset; | ||
| 174 | __sanitizer_sigset_t oldset; | ||
| 175 | }; | ||
| 176 | |||
| 177 | // The sole reason tsan wraps atexit callbacks is to establish synchronization | ||
| 178 | // between callback setup and callback execution. | ||
| 179 | struct AtExitCtx { | ||
| 180 | void (*f)(); | ||
| 181 | void *arg; | ||
| 182 | }; | ||
| 183 | |||
| 184 | // InterceptorContext holds all global data required for interceptors. | ||
| 185 | // It's explicitly constructed in InitializeInterceptors with placement new | ||
| 186 | // and is never destroyed. This allows usage of members with non-trivial | ||
| 187 | // constructors and destructors. | ||
| 188 | struct InterceptorContext { | ||
| 189 | // The object is 64-byte aligned, because we want hot data to be located | ||
| 190 | // in a single cache line if possible (it's accessed in every interceptor). | ||
| 191 | ALIGNED(64) LibIgnore libignore; | ||
| 192 | __sanitizer_sigaction sigactions[kSigCount]; | ||
| 193 | #if !SANITIZER_MAC && !SANITIZER_NETBSD | ||
| 194 | unsigned finalize_key; | ||
| 195 | #endif | ||
| 196 | |||
| 197 | BlockingMutex atexit_mu; | ||
| 198 | Vector<struct AtExitCtx *> AtExitStack; | ||
| 199 | |||
| 200 | InterceptorContext() | ||
| 201 | : libignore(LINKER_INITIALIZED), AtExitStack() { | ||
| 202 | } | ||
| 203 | }; | ||
| 204 | |||
| 205 | static ALIGNED(64) char interceptor_placeholder[sizeof(InterceptorContext)]; | ||
| 206 | InterceptorContext *interceptor_ctx() { | ||
| 207 | return reinterpret_cast<InterceptorContext*>(&interceptor_placeholder[0]); | ||
| 208 | } | ||
| 209 | |||
| 210 | LibIgnore *libignore() { | ||
| 211 | return &interceptor_ctx()->libignore; | ||
| 212 | } | ||
| 213 | |||
| 214 | void InitializeLibIgnore() { | ||
| 215 | const SuppressionContext &supp = *Suppressions(); | ||
| 216 | const uptr n = supp.SuppressionCount(); | ||
| 217 | for (uptr i = 0; i < n; i++) { | ||
| 218 | const Suppression *s = supp.SuppressionAt(i); | ||
| 219 | if (0 == internal_strcmp(s->type, kSuppressionLib)) | ||
| 220 | libignore()->AddIgnoredLibrary(s->templ); | ||
| 221 | } | ||
| 222 | if (flags()->ignore_noninstrumented_modules) | ||
| 223 | libignore()->IgnoreNoninstrumentedModules(true); | ||
| 224 | libignore()->OnLibraryLoaded(0); | ||
| 225 | } | ||
| 226 | |||
| 227 | // The following two hooks can be used by for cooperative scheduling when | ||
| 228 | // locking. | ||
| 229 | #ifdef TSAN_EXTERNAL_HOOKS | ||
| 230 | void OnPotentiallyBlockingRegionBegin(); | ||
| 231 | void OnPotentiallyBlockingRegionEnd(); | ||
| 232 | #else | ||
| 233 | SANITIZER_WEAK_CXX_DEFAULT_IMPL void OnPotentiallyBlockingRegionBegin() {} | ||
| 234 | SANITIZER_WEAK_CXX_DEFAULT_IMPL void OnPotentiallyBlockingRegionEnd() {} | ||
| 235 | #endif | ||
| 236 | |||
| 237 | } // namespace __tsan | ||
| 238 | |||
| 239 | static ThreadSignalContext *SigCtx(ThreadState *thr) { | ||
| 240 | ThreadSignalContext *ctx = (ThreadSignalContext*)thr->signal_ctx; | ||
| 241 | if (ctx == 0 && !thr->is_dead) { | ||
| 242 | ctx = (ThreadSignalContext*)MmapOrDie(sizeof(*ctx), "ThreadSignalContext"); | ||
| 243 | MemoryResetRange(thr, (uptr)&SigCtx, (uptr)ctx, sizeof(*ctx)); | ||
| 244 | thr->signal_ctx = ctx; | ||
| 245 | } | ||
| 246 | return ctx; | ||
| 247 | } | ||
| 248 | |||
| 249 | ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname, | ||
| 250 | uptr pc) | ||
| 251 | : thr_(thr), pc_(pc), in_ignored_lib_(false), ignoring_(false) { | ||
| 252 | Initialize(thr); | ||
| 253 | if (!thr_->is_inited) return; | ||
| 254 | if (!thr_->ignore_interceptors) FuncEntry(thr, pc); | ||
| 255 | DPrintf("#%d: intercept %s()\n", thr_->tid, fname); | ||
| 256 | ignoring_ = | ||
| 257 | !thr_->in_ignored_lib && (flags()->ignore_interceptors_accesses || | ||
| 258 | libignore()->IsIgnored(pc, &in_ignored_lib_)); | ||
| 259 | EnableIgnores(); | ||
| 260 | } | ||
| 261 | |||
| 262 | ScopedInterceptor::~ScopedInterceptor() { | ||
| 263 | if (!thr_->is_inited) return; | ||
| 264 | DisableIgnores(); | ||
| 265 | if (!thr_->ignore_interceptors) { | ||
| 266 | ProcessPendingSignals(thr_); | ||
| 267 | FuncExit(thr_); | ||
| 268 | CheckNoLocks(thr_); | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | void ScopedInterceptor::EnableIgnores() { | ||
| 273 | if (ignoring_) { | ||
| 274 | ThreadIgnoreBegin(thr_, pc_, /*save_stack=*/false); | ||
| 275 | if (flags()->ignore_noninstrumented_modules) thr_->suppress_reports++; | ||
| 276 | if (in_ignored_lib_) { | ||
| 277 | DCHECK(!thr_->in_ignored_lib); | ||
| 278 | thr_->in_ignored_lib = true; | ||
| 279 | } | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | void ScopedInterceptor::DisableIgnores() { | ||
| 284 | if (ignoring_) { | ||
| 285 | ThreadIgnoreEnd(thr_, pc_); | ||
| 286 | if (flags()->ignore_noninstrumented_modules) thr_->suppress_reports--; | ||
| 287 | if (in_ignored_lib_) { | ||
| 288 | DCHECK(thr_->in_ignored_lib); | ||
| 289 | thr_->in_ignored_lib = false; | ||
| 290 | } | ||
| 291 | } | ||
| 292 | } | ||
| 293 | |||
| 294 | #define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func) | ||
| 295 | #if SANITIZER_FREEBSD | ||
| 296 | # define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func) | ||
| 297 | # define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(func) | ||
| 298 | # define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(func) | ||
| 299 | #elif SANITIZER_NETBSD | ||
| 300 | # define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func) | ||
| 301 | # define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(func) \ | ||
| 302 | INTERCEPT_FUNCTION(__libc_##func) | ||
| 303 | # define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(func) \ | ||
| 304 | INTERCEPT_FUNCTION(__libc_thr_##func) | ||
| 305 | #else | ||
| 306 | # define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver) | ||
| 307 | # define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(func) | ||
| 308 | # define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(func) | ||
| 309 | #endif | ||
| 310 | |||
| 311 | #define READ_STRING_OF_LEN(thr, pc, s, len, n) \ | ||
| 312 | MemoryAccessRange((thr), (pc), (uptr)(s), \ | ||
| 313 | common_flags()->strict_string_checks ? (len) + 1 : (n), false) | ||
| 314 | |||
| 315 | #define READ_STRING(thr, pc, s, n) \ | ||
| 316 | READ_STRING_OF_LEN((thr), (pc), (s), internal_strlen(s), (n)) | ||
| 317 | |||
| 318 | #define BLOCK_REAL(name) (BlockingCall(thr), REAL(name)) | ||
| 319 | |||
| 320 | struct BlockingCall { | ||
| 321 | explicit BlockingCall(ThreadState *thr) | ||
| 322 | : thr(thr) | ||
| 323 | , ctx(SigCtx(thr)) { | ||
| 324 | for (;;) { | ||
| 325 | atomic_store(&ctx->in_blocking_func, 1, memory_order_relaxed); | ||
| 326 | if (atomic_load(&ctx->have_pending_signals, memory_order_relaxed) == 0) | ||
| 327 | break; | ||
| 328 | atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed); | ||
| 329 | ProcessPendingSignals(thr); | ||
| 330 | } | ||
| 331 | // When we are in a "blocking call", we process signals asynchronously | ||
| 332 | // (right when they arrive). In this context we do not expect to be | ||
| 333 | // executing any user/runtime code. The known interceptor sequence when | ||
| 334 | // this is not true is: pthread_join -> munmap(stack). It's fine | ||
| 335 | // to ignore munmap in this case -- we handle stack shadow separately. | ||
| 336 | thr->ignore_interceptors++; | ||
| 337 | } | ||
| 338 | |||
| 339 | ~BlockingCall() { | ||
| 340 | thr->ignore_interceptors--; | ||
| 341 | atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed); | ||
| 342 | } | ||
| 343 | |||
| 344 | ThreadState *thr; | ||
| 345 | ThreadSignalContext *ctx; | ||
| 346 | }; | ||
| 347 | |||
| 348 | TSAN_INTERCEPTOR(unsigned, sleep, unsigned sec) { | ||
| 349 | SCOPED_TSAN_INTERCEPTOR(sleep, sec); | ||
| 350 | unsigned res = BLOCK_REAL(sleep)(sec); | ||
| 351 | AfterSleep(thr, pc); | ||
| 352 | return res; | ||
| 353 | } | ||
| 354 | |||
| 355 | TSAN_INTERCEPTOR(int, usleep, long_t usec) { | ||
| 356 | SCOPED_TSAN_INTERCEPTOR(usleep, usec); | ||
| 357 | int res = BLOCK_REAL(usleep)(usec); | ||
| 358 | AfterSleep(thr, pc); | ||
| 359 | return res; | ||
| 360 | } | ||
| 361 | |||
| 362 | TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) { | ||
| 363 | SCOPED_TSAN_INTERCEPTOR(nanosleep, req, rem); | ||
| 364 | int res = BLOCK_REAL(nanosleep)(req, rem); | ||
| 365 | AfterSleep(thr, pc); | ||
| 366 | return res; | ||
| 367 | } | ||
| 368 | |||
| 369 | TSAN_INTERCEPTOR(int, pause, int fake) { | ||
| 370 | SCOPED_TSAN_INTERCEPTOR(pause, fake); | ||
| 371 | return BLOCK_REAL(pause)(fake); | ||
| 372 | } | ||
| 373 | |||
| 374 | static void at_exit_wrapper() { | ||
| 375 | AtExitCtx *ctx; | ||
| 376 | { | ||
| 377 | // Ensure thread-safety. | ||
| 378 | BlockingMutexLock l(&interceptor_ctx()->atexit_mu); | ||
| 379 | |||
| 380 | // Pop AtExitCtx from the top of the stack of callback functions | ||
| 381 | uptr element = interceptor_ctx()->AtExitStack.Size() - 1; | ||
| 382 | ctx = interceptor_ctx()->AtExitStack[element]; | ||
| 383 | interceptor_ctx()->AtExitStack.PopBack(); | ||
| 384 | } | ||
| 385 | |||
| 386 | Acquire(cur_thread(), (uptr)0, (uptr)ctx); | ||
| 387 | ((void(*)())ctx->f)(); | ||
| 388 | InternalFree(ctx); | ||
| 389 | } | ||
| 390 | |||
| 391 | static void cxa_at_exit_wrapper(void *arg) { | ||
| 392 | Acquire(cur_thread(), 0, (uptr)arg); | ||
| 393 | AtExitCtx *ctx = (AtExitCtx*)arg; | ||
| 394 | ((void(*)(void *arg))ctx->f)(ctx->arg); | ||
| 395 | InternalFree(ctx); | ||
| 396 | } | ||
| 397 | |||
| 398 | static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(), | ||
| 399 | void *arg, void *dso); | ||
| 400 | |||
| 401 | #if !SANITIZER_ANDROID | ||
| 402 | TSAN_INTERCEPTOR(int, atexit, void (*f)()) { | ||
| 403 | if (in_symbolizer()) | ||
| 404 | return 0; | ||
| 405 | // We want to setup the atexit callback even if we are in ignored lib | ||
| 406 | // or after fork. | ||
| 407 | SCOPED_INTERCEPTOR_RAW(atexit, f); | ||
| 408 | return setup_at_exit_wrapper(thr, pc, (void(*)())f, 0, 0); | ||
| 409 | } | ||
| 410 | #endif | ||
| 411 | |||
| 412 | TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) { | ||
| 413 | if (in_symbolizer()) | ||
| 414 | return 0; | ||
| 415 | SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso); | ||
| 416 | return setup_at_exit_wrapper(thr, pc, (void(*)())f, arg, dso); | ||
| 417 | } | ||
| 418 | |||
| 419 | static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(), | ||
| 420 | void *arg, void *dso) { | ||
| 421 | AtExitCtx *ctx = (AtExitCtx*)InternalAlloc(sizeof(AtExitCtx)); | ||
| 422 | ctx->f = f; | ||
| 423 | ctx->arg = arg; | ||
| 424 | Release(thr, pc, (uptr)ctx); | ||
| 425 | // Memory allocation in __cxa_atexit will race with free during exit, | ||
| 426 | // because we do not see synchronization around atexit callback list. | ||
| 427 | ThreadIgnoreBegin(thr, pc); | ||
| 428 | int res; | ||
| 429 | if (!dso) { | ||
| 430 | // NetBSD does not preserve the 2nd argument if dso is equal to 0 | ||
| 431 | // Store ctx in a local stack-like structure | ||
| 432 | |||
| 433 | // Ensure thread-safety. | ||
| 434 | BlockingMutexLock l(&interceptor_ctx()->atexit_mu); | ||
| 435 | |||
| 436 | res = REAL(__cxa_atexit)((void (*)(void *a))at_exit_wrapper, 0, 0); | ||
| 437 | // Push AtExitCtx on the top of the stack of callback functions | ||
| 438 | if (!res) { | ||
| 439 | interceptor_ctx()->AtExitStack.PushBack(ctx); | ||
| 440 | } | ||
| 441 | } else { | ||
| 442 | res = REAL(__cxa_atexit)(cxa_at_exit_wrapper, ctx, dso); | ||
| 443 | } | ||
| 444 | ThreadIgnoreEnd(thr, pc); | ||
| 445 | return res; | ||
| 446 | } | ||
| 447 | |||
| 448 | #if !SANITIZER_MAC && !SANITIZER_NETBSD | ||
| 449 | static void on_exit_wrapper(int status, void *arg) { | ||
| 450 | ThreadState *thr = cur_thread(); | ||
| 451 | uptr pc = 0; | ||
| 452 | Acquire(thr, pc, (uptr)arg); | ||
| 453 | AtExitCtx *ctx = (AtExitCtx*)arg; | ||
| 454 | ((void(*)(int status, void *arg))ctx->f)(status, ctx->arg); | ||
| 455 | InternalFree(ctx); | ||
| 456 | } | ||
| 457 | |||
| 458 | TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) { | ||
| 459 | if (in_symbolizer()) | ||
| 460 | return 0; | ||
| 461 | SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg); | ||
| 462 | AtExitCtx *ctx = (AtExitCtx*)InternalAlloc(sizeof(AtExitCtx)); | ||
| 463 | ctx->f = (void(*)())f; | ||
| 464 | ctx->arg = arg; | ||
| 465 | Release(thr, pc, (uptr)ctx); | ||
| 466 | // Memory allocation in __cxa_atexit will race with free during exit, | ||
| 467 | // because we do not see synchronization around atexit callback list. | ||
| 468 | ThreadIgnoreBegin(thr, pc); | ||
| 469 | int res = REAL(on_exit)(on_exit_wrapper, ctx); | ||
| 470 | ThreadIgnoreEnd(thr, pc); | ||
| 471 | return res; | ||
| 472 | } | ||
| 473 | #define TSAN_MAYBE_INTERCEPT_ON_EXIT TSAN_INTERCEPT(on_exit) | ||
| 474 | #else | ||
| 475 | #define TSAN_MAYBE_INTERCEPT_ON_EXIT | ||
| 476 | #endif | ||
| 477 | |||
| 478 | // Cleanup old bufs. | ||
| 479 | static void JmpBufGarbageCollect(ThreadState *thr, uptr sp) { | ||
| 480 | for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) { | ||
| 481 | JmpBuf *buf = &thr->jmp_bufs[i]; | ||
| 482 | if (buf->sp <= sp) { | ||
| 483 | uptr sz = thr->jmp_bufs.Size(); | ||
| 484 | internal_memcpy(buf, &thr->jmp_bufs[sz - 1], sizeof(*buf)); | ||
| 485 | thr->jmp_bufs.PopBack(); | ||
| 486 | i--; | ||
| 487 | } | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | static void SetJmp(ThreadState *thr, uptr sp) { | ||
| 492 | if (!thr->is_inited) // called from libc guts during bootstrap | ||
| 493 | return; | ||
| 494 | // Cleanup old bufs. | ||
| 495 | JmpBufGarbageCollect(thr, sp); | ||
| 496 | // Remember the buf. | ||
| 497 | JmpBuf *buf = thr->jmp_bufs.PushBack(); | ||
| 498 | buf->sp = sp; | ||
| 499 | buf->shadow_stack_pos = thr->shadow_stack_pos; | ||
| 500 | ThreadSignalContext *sctx = SigCtx(thr); | ||
| 501 | buf->int_signal_send = sctx ? sctx->int_signal_send : 0; | ||
| 502 | buf->in_blocking_func = sctx ? | ||
| 503 | atomic_load(&sctx->in_blocking_func, memory_order_relaxed) : | ||
| 504 | false; | ||
| 505 | buf->in_signal_handler = atomic_load(&thr->in_signal_handler, | ||
| 506 | memory_order_relaxed); | ||
| 507 | } | ||
| 508 | |||
| 509 | static void LongJmp(ThreadState *thr, uptr *env) { | ||
| 510 | uptr sp = ExtractLongJmpSp(env); | ||
| 511 | // Find the saved buf with matching sp. | ||
| 512 | for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) { | ||
| 513 | JmpBuf *buf = &thr->jmp_bufs[i]; | ||
| 514 | if (buf->sp == sp) { | ||
| 515 | CHECK_GE(thr->shadow_stack_pos, buf->shadow_stack_pos); | ||
| 516 | // Unwind the stack. | ||
| 517 | while (thr->shadow_stack_pos > buf->shadow_stack_pos) | ||
| 518 | FuncExit(thr); | ||
| 519 | ThreadSignalContext *sctx = SigCtx(thr); | ||
| 520 | if (sctx) { | ||
| 521 | sctx->int_signal_send = buf->int_signal_send; | ||
| 522 | atomic_store(&sctx->in_blocking_func, buf->in_blocking_func, | ||
| 523 | memory_order_relaxed); | ||
| 524 | } | ||
| 525 | atomic_store(&thr->in_signal_handler, buf->in_signal_handler, | ||
| 526 | memory_order_relaxed); | ||
| 527 | JmpBufGarbageCollect(thr, buf->sp - 1); // do not collect buf->sp | ||
| 528 | return; | ||
| 529 | } | ||
| 530 | } | ||
| 531 | Printf("ThreadSanitizer: can't find longjmp buf\n"); | ||
| 532 | CHECK(0); | ||
| 533 | } | ||
| 534 | |||
| 535 | // FIXME: put everything below into a common extern "C" block? | ||
| 536 | extern "C" void __tsan_setjmp(uptr sp) { | ||
| 537 | cur_thread_init(); | ||
| 538 | SetJmp(cur_thread(), sp); | ||
| 539 | } | ||
| 540 | |||
| 541 | #if SANITIZER_MAC | ||
| 542 | TSAN_INTERCEPTOR(int, setjmp, void *env); | ||
| 543 | TSAN_INTERCEPTOR(int, _setjmp, void *env); | ||
| 544 | TSAN_INTERCEPTOR(int, sigsetjmp, void *env); | ||
| 545 | #else // SANITIZER_MAC | ||
| 546 | |||
| 547 | #if SANITIZER_NETBSD | ||
| 548 | #define setjmp_symname __setjmp14 | ||
| 549 | #define sigsetjmp_symname __sigsetjmp14 | ||
| 550 | #else | ||
| 551 | #define setjmp_symname setjmp | ||
| 552 | #define sigsetjmp_symname sigsetjmp | ||
| 553 | #endif | ||
| 554 | |||
| 555 | #define TSAN_INTERCEPTOR_SETJMP_(x) __interceptor_ ## x | ||
| 556 | #define TSAN_INTERCEPTOR_SETJMP__(x) TSAN_INTERCEPTOR_SETJMP_(x) | ||
| 557 | #define TSAN_INTERCEPTOR_SETJMP TSAN_INTERCEPTOR_SETJMP__(setjmp_symname) | ||
| 558 | #define TSAN_INTERCEPTOR_SIGSETJMP TSAN_INTERCEPTOR_SETJMP__(sigsetjmp_symname) | ||
| 559 | |||
| 560 | #define TSAN_STRING_SETJMP SANITIZER_STRINGIFY(setjmp_symname) | ||
| 561 | #define TSAN_STRING_SIGSETJMP SANITIZER_STRINGIFY(sigsetjmp_symname) | ||
| 562 | |||
| 563 | // Not called. Merely to satisfy TSAN_INTERCEPT(). | ||
| 564 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE | ||
| 565 | int TSAN_INTERCEPTOR_SETJMP(void *env); | ||
| 566 | extern "C" int TSAN_INTERCEPTOR_SETJMP(void *env) { | ||
| 567 | CHECK(0); | ||
| 568 | return 0; | ||
| 569 | } | ||
| 570 | |||
| 571 | // FIXME: any reason to have a separate declaration? | ||
| 572 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE | ||
| 573 | int __interceptor__setjmp(void *env); | ||
| 574 | extern "C" int __interceptor__setjmp(void *env) { | ||
| 575 | CHECK(0); | ||
| 576 | return 0; | ||
| 577 | } | ||
| 578 | |||
| 579 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE | ||
| 580 | int TSAN_INTERCEPTOR_SIGSETJMP(void *env); | ||
| 581 | extern "C" int TSAN_INTERCEPTOR_SIGSETJMP(void *env) { | ||
| 582 | CHECK(0); | ||
| 583 | return 0; | ||
| 584 | } | ||
| 585 | |||
| 586 | #if !SANITIZER_NETBSD | ||
| 587 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE | ||
| 588 | int __interceptor___sigsetjmp(void *env); | ||
| 589 | extern "C" int __interceptor___sigsetjmp(void *env) { | ||
| 590 | CHECK(0); | ||
| 591 | return 0; | ||
| 592 | } | ||
| 593 | #endif | ||
| 594 | |||
| 595 | extern "C" int setjmp_symname(void *env); | ||
| 596 | extern "C" int _setjmp(void *env); | ||
| 597 | extern "C" int sigsetjmp_symname(void *env); | ||
| 598 | #if !SANITIZER_NETBSD | ||
| 599 | extern "C" int __sigsetjmp(void *env); | ||
| 600 | #endif | ||
| 601 | DEFINE_REAL(int, setjmp_symname, void *env) | ||
| 602 | DEFINE_REAL(int, _setjmp, void *env) | ||
| 603 | DEFINE_REAL(int, sigsetjmp_symname, void *env) | ||
| 604 | #if !SANITIZER_NETBSD | ||
| 605 | DEFINE_REAL(int, __sigsetjmp, void *env) | ||
| 606 | #endif | ||
| 607 | #endif // SANITIZER_MAC | ||
| 608 | |||
| 609 | #if SANITIZER_NETBSD | ||
| 610 | #define longjmp_symname __longjmp14 | ||
| 611 | #define siglongjmp_symname __siglongjmp14 | ||
| 612 | #else | ||
| 613 | #define longjmp_symname longjmp | ||
| 614 | #define siglongjmp_symname siglongjmp | ||
| 615 | #endif | ||
| 616 | |||
| 617 | TSAN_INTERCEPTOR(void, longjmp_symname, uptr *env, int val) { | ||
| 618 | // Note: if we call REAL(longjmp) in the context of ScopedInterceptor, | ||
| 619 | // bad things will happen. We will jump over ScopedInterceptor dtor and can | ||
| 620 | // leave thr->in_ignored_lib set. | ||
| 621 | { | ||
| 622 | SCOPED_INTERCEPTOR_RAW(longjmp_symname, env, val); | ||
| 623 | } | ||
| 624 | LongJmp(cur_thread(), env); | ||
| 625 | REAL(longjmp_symname)(env, val); | ||
| 626 | } | ||
| 627 | |||
| 628 | TSAN_INTERCEPTOR(void, siglongjmp_symname, uptr *env, int val) { | ||
| 629 | { | ||
| 630 | SCOPED_INTERCEPTOR_RAW(siglongjmp_symname, env, val); | ||
| 631 | } | ||
| 632 | LongJmp(cur_thread(), env); | ||
| 633 | REAL(siglongjmp_symname)(env, val); | ||
| 634 | } | ||
| 635 | |||
| 636 | #if SANITIZER_NETBSD | ||
| 637 | TSAN_INTERCEPTOR(void, _longjmp, uptr *env, int val) { | ||
| 638 | { | ||
| 639 | SCOPED_INTERCEPTOR_RAW(_longjmp, env, val); | ||
| 640 | } | ||
| 641 | LongJmp(cur_thread(), env); | ||
| 642 | REAL(_longjmp)(env, val); | ||
| 643 | } | ||
| 644 | #endif | ||
| 645 | |||
| 646 | #if !SANITIZER_MAC | ||
| 647 | TSAN_INTERCEPTOR(void*, malloc, uptr size) { | ||
| 648 | if (in_symbolizer()) | ||
| 649 | return InternalAlloc(size); | ||
| 650 | void *p = 0; | ||
| 651 | { | ||
| 652 | SCOPED_INTERCEPTOR_RAW(malloc, size); | ||
| 653 | p = user_alloc(thr, pc, size); | ||
| 654 | } | ||
| 655 | invoke_malloc_hook(p, size); | ||
| 656 | return p; | ||
| 657 | } | ||
| 658 | |||
| 659 | TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) { | ||
| 660 | SCOPED_TSAN_INTERCEPTOR(__libc_memalign, align, sz); | ||
| 661 | return user_memalign(thr, pc, align, sz); | ||
| 662 | } | ||
| 663 | |||
| 664 | TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) { | ||
| 665 | if (in_symbolizer()) | ||
| 666 | return InternalCalloc(size, n); | ||
| 667 | void *p = 0; | ||
| 668 | { | ||
| 669 | SCOPED_INTERCEPTOR_RAW(calloc, size, n); | ||
| 670 | p = user_calloc(thr, pc, size, n); | ||
| 671 | } | ||
| 672 | invoke_malloc_hook(p, n * size); | ||
| 673 | return p; | ||
| 674 | } | ||
| 675 | |||
| 676 | TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) { | ||
| 677 | if (in_symbolizer()) | ||
| 678 | return InternalRealloc(p, size); | ||
| 679 | if (p) | ||
| 680 | invoke_free_hook(p); | ||
| 681 | { | ||
| 682 | SCOPED_INTERCEPTOR_RAW(realloc, p, size); | ||
| 683 | p = user_realloc(thr, pc, p, size); | ||
| 684 | } | ||
| 685 | invoke_malloc_hook(p, size); | ||
| 686 | return p; | ||
| 687 | } | ||
| 688 | |||
| 689 | TSAN_INTERCEPTOR(void*, reallocarray, void *p, uptr size, uptr n) { | ||
| 690 | if (in_symbolizer()) | ||
| 691 | return InternalReallocArray(p, size, n); | ||
| 692 | if (p) | ||
| 693 | invoke_free_hook(p); | ||
| 694 | { | ||
| 695 | SCOPED_INTERCEPTOR_RAW(reallocarray, p, size, n); | ||
| 696 | p = user_reallocarray(thr, pc, p, size, n); | ||
| 697 | } | ||
| 698 | invoke_malloc_hook(p, size); | ||
| 699 | return p; | ||
| 700 | } | ||
| 701 | |||
| 702 | TSAN_INTERCEPTOR(void, free, void *p) { | ||
| 703 | if (p == 0) | ||
| 704 | return; | ||
| 705 | if (in_symbolizer()) | ||
| 706 | return InternalFree(p); | ||
| 707 | invoke_free_hook(p); | ||
| 708 | SCOPED_INTERCEPTOR_RAW(free, p); | ||
| 709 | user_free(thr, pc, p); | ||
| 710 | } | ||
| 711 | |||
| 712 | TSAN_INTERCEPTOR(void, cfree, void *p) { | ||
| 713 | if (p == 0) | ||
| 714 | return; | ||
| 715 | if (in_symbolizer()) | ||
| 716 | return InternalFree(p); | ||
| 717 | invoke_free_hook(p); | ||
| 718 | SCOPED_INTERCEPTOR_RAW(cfree, p); | ||
| 719 | user_free(thr, pc, p); | ||
| 720 | } | ||
| 721 | |||
| 722 | TSAN_INTERCEPTOR(uptr, malloc_usable_size, void *p) { | ||
| 723 | SCOPED_INTERCEPTOR_RAW(malloc_usable_size, p); | ||
| 724 | return user_alloc_usable_size(p); | ||
| 725 | } | ||
| 726 | #endif | ||
| 727 | |||
| 728 | TSAN_INTERCEPTOR(char *, strcpy, char *dst, const char *src) { | ||
| 729 | SCOPED_TSAN_INTERCEPTOR(strcpy, dst, src); | ||
| 730 | uptr srclen = internal_strlen(src); | ||
| 731 | MemoryAccessRange(thr, pc, (uptr)dst, srclen + 1, true); | ||
| 732 | MemoryAccessRange(thr, pc, (uptr)src, srclen + 1, false); | ||
| 733 | return REAL(strcpy)(dst, src); | ||
| 734 | } | ||
| 735 | |||
| 736 | TSAN_INTERCEPTOR(char*, strncpy, char *dst, char *src, uptr n) { | ||
| 737 | SCOPED_TSAN_INTERCEPTOR(strncpy, dst, src, n); | ||
| 738 | uptr srclen = internal_strnlen(src, n); | ||
| 739 | MemoryAccessRange(thr, pc, (uptr)dst, n, true); | ||
| 740 | MemoryAccessRange(thr, pc, (uptr)src, min(srclen + 1, n), false); | ||
| 741 | return REAL(strncpy)(dst, src, n); | ||
| 742 | } | ||
| 743 | |||
| 744 | TSAN_INTERCEPTOR(char*, strdup, const char *str) { | ||
| 745 | SCOPED_TSAN_INTERCEPTOR(strdup, str); | ||
| 746 | // strdup will call malloc, so no instrumentation is required here. | ||
| 747 | return REAL(strdup)(str); | ||
| 748 | } | ||
| 749 | |||
| 750 | // Zero out addr if it points into shadow memory and was provided as a hint | ||
| 751 | // only, i.e., MAP_FIXED is not set. | ||
| 752 | static bool fix_mmap_addr(void **addr, long_t sz, int flags) { | ||
| 753 | if (*addr) { | ||
| 754 | if (!IsAppMem((uptr)*addr) || !IsAppMem((uptr)*addr + sz - 1)) { | ||
| 755 | if (flags & MAP_FIXED) { | ||
| 756 | errno = errno_EINVAL; | ||
| 757 | return false; | ||
| 758 | } else { | ||
| 759 | *addr = 0; | ||
| 760 | } | ||
| 761 | } | ||
| 762 | } | ||
| 763 | return true; | ||
| 764 | } | ||
| 765 | |||
| 766 | template <class Mmap> | ||
| 767 | static void *mmap_interceptor(ThreadState *thr, uptr pc, Mmap real_mmap, | ||
| 768 | void *addr, SIZE_T sz, int prot, int flags, | ||
| 769 | int fd, OFF64_T off) { | ||
| 770 | if (!fix_mmap_addr(&addr, sz, flags)) return MAP_FAILED; | ||
| 771 | void *res = real_mmap(addr, sz, prot, flags, fd, off); | ||
| 772 | if (res != MAP_FAILED) { | ||
| 773 | if (fd > 0) FdAccess(thr, pc, fd); | ||
| 774 | MemoryRangeImitateWriteOrResetRange(thr, pc, (uptr)res, sz); | ||
| 775 | } | ||
| 776 | return res; | ||
| 777 | } | ||
| 778 | |||
| 779 | TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) { | ||
| 780 | SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz); | ||
| 781 | UnmapShadow(thr, (uptr)addr, sz); | ||
| 782 | int res = REAL(munmap)(addr, sz); | ||
| 783 | return res; | ||
| 784 | } | ||
| 785 | |||
| 786 | #if SANITIZER_LINUX | ||
| 787 | TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) { | ||
| 788 | SCOPED_INTERCEPTOR_RAW(memalign, align, sz); | ||
| 789 | return user_memalign(thr, pc, align, sz); | ||
| 790 | } | ||
| 791 | #define TSAN_MAYBE_INTERCEPT_MEMALIGN TSAN_INTERCEPT(memalign) | ||
| 792 | #else | ||
| 793 | #define TSAN_MAYBE_INTERCEPT_MEMALIGN | ||
| 794 | #endif | ||
| 795 | |||
| 796 | #if !SANITIZER_MAC | ||
| 797 | TSAN_INTERCEPTOR(void*, aligned_alloc, uptr align, uptr sz) { | ||
| 798 | if (in_symbolizer()) | ||
| 799 | return InternalAlloc(sz, nullptr, align); | ||
| 800 | SCOPED_INTERCEPTOR_RAW(aligned_alloc, align, sz); | ||
| 801 | return user_aligned_alloc(thr, pc, align, sz); | ||
| 802 | } | ||
| 803 | |||
| 804 | TSAN_INTERCEPTOR(void*, valloc, uptr sz) { | ||
| 805 | if (in_symbolizer()) | ||
| 806 | return InternalAlloc(sz, nullptr, GetPageSizeCached()); | ||
| 807 | SCOPED_INTERCEPTOR_RAW(valloc, sz); | ||
| 808 | return user_valloc(thr, pc, sz); | ||
| 809 | } | ||
| 810 | #endif | ||
| 811 | |||
| 812 | #if SANITIZER_LINUX | ||
| 813 | TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) { | ||
| 814 | if (in_symbolizer()) { | ||
| 815 | uptr PageSize = GetPageSizeCached(); | ||
| 816 | sz = sz ? RoundUpTo(sz, PageSize) : PageSize; | ||
| 817 | return InternalAlloc(sz, nullptr, PageSize); | ||
| 818 | } | ||
| 819 | SCOPED_INTERCEPTOR_RAW(pvalloc, sz); | ||
| 820 | return user_pvalloc(thr, pc, sz); | ||
| 821 | } | ||
| 822 | #define TSAN_MAYBE_INTERCEPT_PVALLOC TSAN_INTERCEPT(pvalloc) | ||
| 823 | #else | ||
| 824 | #define TSAN_MAYBE_INTERCEPT_PVALLOC | ||
| 825 | #endif | ||
| 826 | |||
| 827 | #if !SANITIZER_MAC | ||
| 828 | TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) { | ||
| 829 | if (in_symbolizer()) { | ||
| 830 | void *p = InternalAlloc(sz, nullptr, align); | ||
| 831 | if (!p) | ||
| 832 | return errno_ENOMEM; | ||
| 833 | *memptr = p; | ||
| 834 | return 0; | ||
| 835 | } | ||
| 836 | SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz); | ||
| 837 | return user_posix_memalign(thr, pc, memptr, align, sz); | ||
| 838 | } | ||
| 839 | #endif | ||
| 840 | |||
| 841 | // __cxa_guard_acquire and friends need to be intercepted in a special way - | ||
| 842 | // regular interceptors will break statically-linked libstdc++. Linux | ||
| 843 | // interceptors are especially defined as weak functions (so that they don't | ||
| 844 | // cause link errors when user defines them as well). So they silently | ||
| 845 | // auto-disable themselves when such symbol is already present in the binary. If | ||
| 846 | // we link libstdc++ statically, it will bring own __cxa_guard_acquire which | ||
| 847 | // will silently replace our interceptor. That's why on Linux we simply export | ||
| 848 | // these interceptors with INTERFACE_ATTRIBUTE. | ||
| 849 | // On OS X, we don't support statically linking, so we just use a regular | ||
| 850 | // interceptor. | ||
| 851 | #if SANITIZER_MAC | ||
| 852 | #define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR | ||
| 853 | #else | ||
| 854 | #define STDCXX_INTERCEPTOR(rettype, name, ...) \ | ||
| 855 | extern "C" rettype INTERFACE_ATTRIBUTE name(__VA_ARGS__) | ||
| 856 | #endif | ||
| 857 | |||
| 858 | // Used in thread-safe function static initialization. | ||
| 859 | STDCXX_INTERCEPTOR(int, __cxa_guard_acquire, atomic_uint32_t *g) { | ||
| 860 | SCOPED_INTERCEPTOR_RAW(__cxa_guard_acquire, g); | ||
| 861 | OnPotentiallyBlockingRegionBegin(); | ||
| 862 | auto on_exit = at_scope_exit(&OnPotentiallyBlockingRegionEnd); | ||
| 863 | for (;;) { | ||
| 864 | u32 cmp = atomic_load(g, memory_order_acquire); | ||
| 865 | if (cmp == 0) { | ||
| 866 | if (atomic_compare_exchange_strong(g, &cmp, 1<<16, memory_order_relaxed)) | ||
| 867 | return 1; | ||
| 868 | } else if (cmp == 1) { | ||
| 869 | Acquire(thr, pc, (uptr)g); | ||
| 870 | return 0; | ||
| 871 | } else { | ||
| 872 | internal_sched_yield(); | ||
| 873 | } | ||
| 874 | } | ||
| 875 | } | ||
| 876 | |||
| 877 | STDCXX_INTERCEPTOR(void, __cxa_guard_release, atomic_uint32_t *g) { | ||
| 878 | SCOPED_INTERCEPTOR_RAW(__cxa_guard_release, g); | ||
| 879 | Release(thr, pc, (uptr)g); | ||
| 880 | atomic_store(g, 1, memory_order_release); | ||
| 881 | } | ||
| 882 | |||
| 883 | STDCXX_INTERCEPTOR(void, __cxa_guard_abort, atomic_uint32_t *g) { | ||
| 884 | SCOPED_INTERCEPTOR_RAW(__cxa_guard_abort, g); | ||
| 885 | atomic_store(g, 0, memory_order_relaxed); | ||
| 886 | } | ||
| 887 | |||
| 888 | namespace __tsan { | ||
| 889 | void DestroyThreadState() { | ||
| 890 | ThreadState *thr = cur_thread(); | ||
| 891 | Processor *proc = thr->proc(); | ||
| 892 | ThreadFinish(thr); | ||
| 893 | ProcUnwire(proc, thr); | ||
| 894 | ProcDestroy(proc); | ||
| 895 | DTLS_Destroy(); | ||
| 896 | cur_thread_finalize(); | ||
| 897 | } | ||
| 898 | |||
| 899 | void PlatformCleanUpThreadState(ThreadState *thr) { | ||
| 900 | ThreadSignalContext *sctx = thr->signal_ctx; | ||
| 901 | if (sctx) { | ||
| 902 | thr->signal_ctx = 0; | ||
| 903 | UnmapOrDie(sctx, sizeof(*sctx)); | ||
| 904 | } | ||
| 905 | } | ||
| 906 | } // namespace __tsan | ||
| 907 | |||
| 908 | #if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD | ||
| 909 | static void thread_finalize(void *v) { | ||
| 910 | uptr iter = (uptr)v; | ||
| 911 | if (iter > 1) { | ||
| 912 | if (pthread_setspecific(interceptor_ctx()->finalize_key, | ||
| 913 | (void*)(iter - 1))) { | ||
| 914 | Printf("ThreadSanitizer: failed to set thread key\n"); | ||
| 915 | Die(); | ||
| 916 | } | ||
| 917 | return; | ||
| 918 | } | ||
| 919 | DestroyThreadState(); | ||
| 920 | } | ||
| 921 | #endif | ||
| 922 | |||
| 923 | |||
| 924 | struct ThreadParam { | ||
| 925 | void* (*callback)(void *arg); | ||
| 926 | void *param; | ||
| 927 | atomic_uintptr_t tid; | ||
| 928 | }; | ||
| 929 | |||
| 930 | extern "C" void *__tsan_thread_start_func(void *arg) { | ||
| 931 | ThreadParam *p = (ThreadParam*)arg; | ||
| 932 | void* (*callback)(void *arg) = p->callback; | ||
| 933 | void *param = p->param; | ||
| 934 | int tid = 0; | ||
| 935 | { | ||
| 936 | cur_thread_init(); | ||
| 937 | ThreadState *thr = cur_thread(); | ||
| 938 | // Thread-local state is not initialized yet. | ||
| 939 | ScopedIgnoreInterceptors ignore; | ||
| 940 | #if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD | ||
| 941 | ThreadIgnoreBegin(thr, 0); | ||
| 942 | if (pthread_setspecific(interceptor_ctx()->finalize_key, | ||
| 943 | (void *)GetPthreadDestructorIterations())) { | ||
| 944 | Printf("ThreadSanitizer: failed to set thread key\n"); | ||
| 945 | Die(); | ||
| 946 | } | ||
| 947 | ThreadIgnoreEnd(thr, 0); | ||
| 948 | #endif | ||
| 949 | while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) | ||
| 950 | internal_sched_yield(); | ||
| 951 | Processor *proc = ProcCreate(); | ||
| 952 | ProcWire(proc, thr); | ||
| 953 | ThreadStart(thr, tid, GetTid(), ThreadType::Regular); | ||
| 954 | atomic_store(&p->tid, 0, memory_order_release); | ||
| 955 | } | ||
| 956 | void *res = callback(param); | ||
| 957 | // Prevent the callback from being tail called, | ||
| 958 | // it mixes up stack traces. | ||
| 959 | volatile int foo = 42; | ||
| 960 | foo++; | ||
| 961 | return res; | ||
| 962 | } | ||
| 963 | |||
| 964 | TSAN_INTERCEPTOR(int, pthread_create, | ||
| 965 | void *th, void *attr, void *(*callback)(void*), void * param) { | ||
| 966 | SCOPED_INTERCEPTOR_RAW(pthread_create, th, attr, callback, param); | ||
| 967 | |||
| 968 | MaybeSpawnBackgroundThread(); | ||
| 969 | |||
| 970 | if (ctx->after_multithreaded_fork) { | ||
| 971 | if (flags()->die_after_fork) { | ||
| 972 | Report("ThreadSanitizer: starting new threads after multi-threaded " | ||
| 973 | "fork is not supported. Dying (set die_after_fork=0 to override)\n"); | ||
| 974 | Die(); | ||
| 975 | } else { | ||
| 976 | VPrintf(1, "ThreadSanitizer: starting new threads after multi-threaded " | ||
| 977 | "fork is not supported (pid %d). Continuing because of " | ||
| 978 | "die_after_fork=0, but you are on your own\n", internal_getpid()); | ||
| 979 | } | ||
| 980 | } | ||
| 981 | __sanitizer_pthread_attr_t myattr; | ||
| 982 | if (attr == 0) { | ||
| 983 | pthread_attr_init(&myattr); | ||
| 984 | attr = &myattr; | ||
| 985 | } | ||
| 986 | int detached = 0; | ||
| 987 | REAL(pthread_attr_getdetachstate)(attr, &detached); | ||
| 988 | AdjustStackSize(attr); | ||
| 989 | |||
| 990 | ThreadParam p; | ||
| 991 | p.callback = callback; | ||
| 992 | p.param = param; | ||
| 993 | atomic_store(&p.tid, 0, memory_order_relaxed); | ||
| 994 | int res = -1; | ||
| 995 | { | ||
| 996 | // Otherwise we see false positives in pthread stack manipulation. | ||
| 997 | ScopedIgnoreInterceptors ignore; | ||
| 998 | ThreadIgnoreBegin(thr, pc); | ||
| 999 | res = REAL(pthread_create)(th, attr, __tsan_thread_start_func, &p); | ||
| 1000 | ThreadIgnoreEnd(thr, pc); | ||
| 1001 | } | ||
| 1002 | if (res == 0) { | ||
| 1003 | int tid = ThreadCreate(thr, pc, *(uptr*)th, IsStateDetached(detached)); | ||
| 1004 | CHECK_NE(tid, 0); | ||
| 1005 | // Synchronization on p.tid serves two purposes: | ||
| 1006 | // 1. ThreadCreate must finish before the new thread starts. | ||
| 1007 | // Otherwise the new thread can call pthread_detach, but the pthread_t | ||
| 1008 | // identifier is not yet registered in ThreadRegistry by ThreadCreate. | ||
| 1009 | // 2. ThreadStart must finish before this thread continues. | ||
| 1010 | // Otherwise, this thread can call pthread_detach and reset thr->sync | ||
| 1011 | // before the new thread got a chance to acquire from it in ThreadStart. | ||
| 1012 | atomic_store(&p.tid, tid, memory_order_release); | ||
| 1013 | while (atomic_load(&p.tid, memory_order_acquire) != 0) | ||
| 1014 | internal_sched_yield(); | ||
| 1015 | } | ||
| 1016 | if (attr == &myattr) | ||
| 1017 | pthread_attr_destroy(&myattr); | ||
| 1018 | return res; | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) { | ||
| 1022 | SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret); | ||
| 1023 | int tid = ThreadConsumeTid(thr, pc, (uptr)th); | ||
| 1024 | ThreadIgnoreBegin(thr, pc); | ||
| 1025 | int res = BLOCK_REAL(pthread_join)(th, ret); | ||
| 1026 | ThreadIgnoreEnd(thr, pc); | ||
| 1027 | if (res == 0) { | ||
| 1028 | ThreadJoin(thr, pc, tid); | ||
| 1029 | } | ||
| 1030 | return res; | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | DEFINE_REAL_PTHREAD_FUNCTIONS | ||
| 1034 | |||
| 1035 | TSAN_INTERCEPTOR(int, pthread_detach, void *th) { | ||
| 1036 | SCOPED_INTERCEPTOR_RAW(pthread_detach, th); | ||
| 1037 | int tid = ThreadConsumeTid(thr, pc, (uptr)th); | ||
| 1038 | int res = REAL(pthread_detach)(th); | ||
| 1039 | if (res == 0) { | ||
| 1040 | ThreadDetach(thr, pc, tid); | ||
| 1041 | } | ||
| 1042 | return res; | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | TSAN_INTERCEPTOR(void, pthread_exit, void *retval) { | ||
| 1046 | { | ||
| 1047 | SCOPED_INTERCEPTOR_RAW(pthread_exit, retval); | ||
| 1048 | #if !SANITIZER_MAC && !SANITIZER_ANDROID | ||
| 1049 | CHECK_EQ(thr, &cur_thread_placeholder); | ||
| 1050 | #endif | ||
| 1051 | } | ||
| 1052 | REAL(pthread_exit)(retval); | ||
| 1053 | } | ||
| 1054 | |||
| 1055 | #if SANITIZER_LINUX | ||
| 1056 | TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void *th, void **ret) { | ||
| 1057 | SCOPED_INTERCEPTOR_RAW(pthread_tryjoin_np, th, ret); | ||
| 1058 | int tid = ThreadConsumeTid(thr, pc, (uptr)th); | ||
| 1059 | ThreadIgnoreBegin(thr, pc); | ||
| 1060 | int res = REAL(pthread_tryjoin_np)(th, ret); | ||
| 1061 | ThreadIgnoreEnd(thr, pc); | ||
| 1062 | if (res == 0) | ||
| 1063 | ThreadJoin(thr, pc, tid); | ||
| 1064 | else | ||
| 1065 | ThreadNotJoined(thr, pc, tid, (uptr)th); | ||
| 1066 | return res; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | TSAN_INTERCEPTOR(int, pthread_timedjoin_np, void *th, void **ret, | ||
| 1070 | const struct timespec *abstime) { | ||
| 1071 | SCOPED_INTERCEPTOR_RAW(pthread_timedjoin_np, th, ret, abstime); | ||
| 1072 | int tid = ThreadConsumeTid(thr, pc, (uptr)th); | ||
| 1073 | ThreadIgnoreBegin(thr, pc); | ||
| 1074 | int res = BLOCK_REAL(pthread_timedjoin_np)(th, ret, abstime); | ||
| 1075 | ThreadIgnoreEnd(thr, pc); | ||
| 1076 | if (res == 0) | ||
| 1077 | ThreadJoin(thr, pc, tid); | ||
| 1078 | else | ||
| 1079 | ThreadNotJoined(thr, pc, tid, (uptr)th); | ||
| 1080 | return res; | ||
| 1081 | } | ||
| 1082 | #endif | ||
| 1083 | |||
| 1084 | // Problem: | ||
| 1085 | // NPTL implementation of pthread_cond has 2 versions (2.2.5 and 2.3.2). | ||
| 1086 | // pthread_cond_t has different size in the different versions. | ||
| 1087 | // If call new REAL functions for old pthread_cond_t, they will corrupt memory | ||
| 1088 | // after pthread_cond_t (old cond is smaller). | ||
| 1089 | // If we call old REAL functions for new pthread_cond_t, we will lose some | ||
| 1090 | // functionality (e.g. old functions do not support waiting against | ||
| 1091 | // CLOCK_REALTIME). | ||
| 1092 | // Proper handling would require to have 2 versions of interceptors as well. | ||
| 1093 | // But this is messy, in particular requires linker scripts when sanitizer | ||
| 1094 | // runtime is linked into a shared library. | ||
| 1095 | // Instead we assume we don't have dynamic libraries built against old | ||
| 1096 | // pthread (2.2.5 is dated by 2002). And provide legacy_pthread_cond flag | ||
| 1097 | // that allows to work with old libraries (but this mode does not support | ||
| 1098 | // some features, e.g. pthread_condattr_getpshared). | ||
| 1099 | static void *init_cond(void *c, bool force = false) { | ||
| 1100 | // sizeof(pthread_cond_t) >= sizeof(uptr) in both versions. | ||
| 1101 | // So we allocate additional memory on the side large enough to hold | ||
| 1102 | // any pthread_cond_t object. Always call new REAL functions, but pass | ||
| 1103 | // the aux object to them. | ||
| 1104 | // Note: the code assumes that PTHREAD_COND_INITIALIZER initializes | ||
| 1105 | // first word of pthread_cond_t to zero. | ||
| 1106 | // It's all relevant only for linux. | ||
| 1107 | if (!common_flags()->legacy_pthread_cond) | ||
| 1108 | return c; | ||
| 1109 | atomic_uintptr_t *p = (atomic_uintptr_t*)c; | ||
| 1110 | uptr cond = atomic_load(p, memory_order_acquire); | ||
| 1111 | if (!force && cond != 0) | ||
| 1112 | return (void*)cond; | ||
| 1113 | void *newcond = WRAP(malloc)(pthread_cond_t_sz); | ||
| 1114 | internal_memset(newcond, 0, pthread_cond_t_sz); | ||
| 1115 | if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond, | ||
| 1116 | memory_order_acq_rel)) | ||
| 1117 | return newcond; | ||
| 1118 | WRAP(free)(newcond); | ||
| 1119 | return (void*)cond; | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | struct CondMutexUnlockCtx { | ||
| 1123 | ScopedInterceptor *si; | ||
| 1124 | ThreadState *thr; | ||
| 1125 | uptr pc; | ||
| 1126 | void *m; | ||
| 1127 | }; | ||
| 1128 | |||
| 1129 | static void cond_mutex_unlock(CondMutexUnlockCtx *arg) { | ||
| 1130 | // pthread_cond_wait interceptor has enabled async signal delivery | ||
| 1131 | // (see BlockingCall below). Disable async signals since we are running | ||
| 1132 | // tsan code. Also ScopedInterceptor and BlockingCall destructors won't run | ||
| 1133 | // since the thread is cancelled, so we have to manually execute them | ||
| 1134 | // (the thread still can run some user code due to pthread_cleanup_push). | ||
| 1135 | ThreadSignalContext *ctx = SigCtx(arg->thr); | ||
| 1136 | CHECK_EQ(atomic_load(&ctx->in_blocking_func, memory_order_relaxed), 1); | ||
| 1137 | atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed); | ||
| 1138 | MutexPostLock(arg->thr, arg->pc, (uptr)arg->m, MutexFlagDoPreLockOnPostLock); | ||
| 1139 | // Undo BlockingCall ctor effects. | ||
| 1140 | arg->thr->ignore_interceptors--; | ||
| 1141 | arg->si->~ScopedInterceptor(); | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | INTERCEPTOR(int, pthread_cond_init, void *c, void *a) { | ||
| 1145 | void *cond = init_cond(c, true); | ||
| 1146 | SCOPED_TSAN_INTERCEPTOR(pthread_cond_init, cond, a); | ||
| 1147 | MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true); | ||
| 1148 | return REAL(pthread_cond_init)(cond, a); | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si, | ||
| 1152 | int (*fn)(void *c, void *m, void *abstime), void *c, | ||
| 1153 | void *m, void *t) { | ||
| 1154 | MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false); | ||
| 1155 | MutexUnlock(thr, pc, (uptr)m); | ||
| 1156 | CondMutexUnlockCtx arg = {si, thr, pc, m}; | ||
| 1157 | int res = 0; | ||
| 1158 | // This ensures that we handle mutex lock even in case of pthread_cancel. | ||
| 1159 | // See test/tsan/cond_cancel.cpp. | ||
| 1160 | { | ||
| 1161 | // Enable signal delivery while the thread is blocked. | ||
| 1162 | BlockingCall bc(thr); | ||
| 1163 | res = call_pthread_cancel_with_cleanup( | ||
| 1164 | fn, c, m, t, (void (*)(void *arg))cond_mutex_unlock, &arg); | ||
| 1165 | } | ||
| 1166 | if (res == errno_EOWNERDEAD) MutexRepair(thr, pc, (uptr)m); | ||
| 1167 | MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock); | ||
| 1168 | return res; | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) { | ||
| 1172 | void *cond = init_cond(c); | ||
| 1173 | SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m); | ||
| 1174 | return cond_wait(thr, pc, &si, (int (*)(void *c, void *m, void *abstime))REAL( | ||
| 1175 | pthread_cond_wait), | ||
| 1176 | cond, m, 0); | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) { | ||
| 1180 | void *cond = init_cond(c); | ||
| 1181 | SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime); | ||
| 1182 | return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait), cond, m, | ||
| 1183 | abstime); | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | #if SANITIZER_MAC | ||
| 1187 | INTERCEPTOR(int, pthread_cond_timedwait_relative_np, void *c, void *m, | ||
| 1188 | void *reltime) { | ||
| 1189 | void *cond = init_cond(c); | ||
| 1190 | SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait_relative_np, cond, m, reltime); | ||
| 1191 | return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait_relative_np), cond, | ||
| 1192 | m, reltime); | ||
| 1193 | } | ||
| 1194 | #endif | ||
| 1195 | |||
| 1196 | INTERCEPTOR(int, pthread_cond_signal, void *c) { | ||
| 1197 | void *cond = init_cond(c); | ||
| 1198 | SCOPED_TSAN_INTERCEPTOR(pthread_cond_signal, cond); | ||
| 1199 | MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false); | ||
| 1200 | return REAL(pthread_cond_signal)(cond); | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | INTERCEPTOR(int, pthread_cond_broadcast, void *c) { | ||
| 1204 | void *cond = init_cond(c); | ||
| 1205 | SCOPED_TSAN_INTERCEPTOR(pthread_cond_broadcast, cond); | ||
| 1206 | MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false); | ||
| 1207 | return REAL(pthread_cond_broadcast)(cond); | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | INTERCEPTOR(int, pthread_cond_destroy, void *c) { | ||
| 1211 | void *cond = init_cond(c); | ||
| 1212 | SCOPED_TSAN_INTERCEPTOR(pthread_cond_destroy, cond); | ||
| 1213 | MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true); | ||
| 1214 | int res = REAL(pthread_cond_destroy)(cond); | ||
| 1215 | if (common_flags()->legacy_pthread_cond) { | ||
| 1216 | // Free our aux cond and zero the pointer to not leave dangling pointers. | ||
| 1217 | WRAP(free)(cond); | ||
| 1218 | atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed); | ||
| 1219 | } | ||
| 1220 | return res; | ||
| 1221 | } | ||
| 1222 | |||
| 1223 | TSAN_INTERCEPTOR(int, pthread_mutex_init, void *m, void *a) { | ||
| 1224 | SCOPED_TSAN_INTERCEPTOR(pthread_mutex_init, m, a); | ||
| 1225 | int res = REAL(pthread_mutex_init)(m, a); | ||
| 1226 | if (res == 0) { | ||
| 1227 | u32 flagz = 0; | ||
| 1228 | if (a) { | ||
| 1229 | int type = 0; | ||
| 1230 | if (REAL(pthread_mutexattr_gettype)(a, &type) == 0) | ||
| 1231 | if (type == PTHREAD_MUTEX_RECURSIVE || | ||
| 1232 | type == PTHREAD_MUTEX_RECURSIVE_NP) | ||
| 1233 | flagz |= MutexFlagWriteReentrant; | ||
| 1234 | } | ||
| 1235 | MutexCreate(thr, pc, (uptr)m, flagz); | ||
| 1236 | } | ||
| 1237 | return res; | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) { | ||
| 1241 | SCOPED_TSAN_INTERCEPTOR(pthread_mutex_destroy, m); | ||
| 1242 | int res = REAL(pthread_mutex_destroy)(m); | ||
| 1243 | if (res == 0 || res == errno_EBUSY) { | ||
| 1244 | MutexDestroy(thr, pc, (uptr)m); | ||
| 1245 | } | ||
| 1246 | return res; | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) { | ||
| 1250 | SCOPED_TSAN_INTERCEPTOR(pthread_mutex_trylock, m); | ||
| 1251 | int res = REAL(pthread_mutex_trylock)(m); | ||
| 1252 | if (res == errno_EOWNERDEAD) | ||
| 1253 | MutexRepair(thr, pc, (uptr)m); | ||
| 1254 | if (res == 0 || res == errno_EOWNERDEAD) | ||
| 1255 | MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); | ||
| 1256 | return res; | ||
| 1257 | } | ||
| 1258 | |||
| 1259 | #if !SANITIZER_MAC | ||
| 1260 | TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) { | ||
| 1261 | SCOPED_TSAN_INTERCEPTOR(pthread_mutex_timedlock, m, abstime); | ||
| 1262 | int res = REAL(pthread_mutex_timedlock)(m, abstime); | ||
| 1263 | if (res == 0) { | ||
| 1264 | MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); | ||
| 1265 | } | ||
| 1266 | return res; | ||
| 1267 | } | ||
| 1268 | #endif | ||
| 1269 | |||
| 1270 | #if !SANITIZER_MAC | ||
| 1271 | TSAN_INTERCEPTOR(int, pthread_spin_init, void *m, int pshared) { | ||
| 1272 | SCOPED_TSAN_INTERCEPTOR(pthread_spin_init, m, pshared); | ||
| 1273 | int res = REAL(pthread_spin_init)(m, pshared); | ||
| 1274 | if (res == 0) { | ||
| 1275 | MutexCreate(thr, pc, (uptr)m); | ||
| 1276 | } | ||
| 1277 | return res; | ||
| 1278 | } | ||
| 1279 | |||
| 1280 | TSAN_INTERCEPTOR(int, pthread_spin_destroy, void *m) { | ||
| 1281 | SCOPED_TSAN_INTERCEPTOR(pthread_spin_destroy, m); | ||
| 1282 | int res = REAL(pthread_spin_destroy)(m); | ||
| 1283 | if (res == 0) { | ||
| 1284 | MutexDestroy(thr, pc, (uptr)m); | ||
| 1285 | } | ||
| 1286 | return res; | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | TSAN_INTERCEPTOR(int, pthread_spin_lock, void *m) { | ||
| 1290 | SCOPED_TSAN_INTERCEPTOR(pthread_spin_lock, m); | ||
| 1291 | MutexPreLock(thr, pc, (uptr)m); | ||
| 1292 | int res = REAL(pthread_spin_lock)(m); | ||
| 1293 | if (res == 0) { | ||
| 1294 | MutexPostLock(thr, pc, (uptr)m); | ||
| 1295 | } | ||
| 1296 | return res; | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | TSAN_INTERCEPTOR(int, pthread_spin_trylock, void *m) { | ||
| 1300 | SCOPED_TSAN_INTERCEPTOR(pthread_spin_trylock, m); | ||
| 1301 | int res = REAL(pthread_spin_trylock)(m); | ||
| 1302 | if (res == 0) { | ||
| 1303 | MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); | ||
| 1304 | } | ||
| 1305 | return res; | ||
| 1306 | } | ||
| 1307 | |||
| 1308 | TSAN_INTERCEPTOR(int, pthread_spin_unlock, void *m) { | ||
| 1309 | SCOPED_TSAN_INTERCEPTOR(pthread_spin_unlock, m); | ||
| 1310 | MutexUnlock(thr, pc, (uptr)m); | ||
| 1311 | int res = REAL(pthread_spin_unlock)(m); | ||
| 1312 | return res; | ||
| 1313 | } | ||
| 1314 | #endif | ||
| 1315 | |||
| 1316 | TSAN_INTERCEPTOR(int, pthread_rwlock_init, void *m, void *a) { | ||
| 1317 | SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_init, m, a); | ||
| 1318 | int res = REAL(pthread_rwlock_init)(m, a); | ||
| 1319 | if (res == 0) { | ||
| 1320 | MutexCreate(thr, pc, (uptr)m); | ||
| 1321 | } | ||
| 1322 | return res; | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | TSAN_INTERCEPTOR(int, pthread_rwlock_destroy, void *m) { | ||
| 1326 | SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_destroy, m); | ||
| 1327 | int res = REAL(pthread_rwlock_destroy)(m); | ||
| 1328 | if (res == 0) { | ||
| 1329 | MutexDestroy(thr, pc, (uptr)m); | ||
| 1330 | } | ||
| 1331 | return res; | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | TSAN_INTERCEPTOR(int, pthread_rwlock_rdlock, void *m) { | ||
| 1335 | SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_rdlock, m); | ||
| 1336 | MutexPreReadLock(thr, pc, (uptr)m); | ||
| 1337 | int res = REAL(pthread_rwlock_rdlock)(m); | ||
| 1338 | if (res == 0) { | ||
| 1339 | MutexPostReadLock(thr, pc, (uptr)m); | ||
| 1340 | } | ||
| 1341 | return res; | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | TSAN_INTERCEPTOR(int, pthread_rwlock_tryrdlock, void *m) { | ||
| 1345 | SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_tryrdlock, m); | ||
| 1346 | int res = REAL(pthread_rwlock_tryrdlock)(m); | ||
| 1347 | if (res == 0) { | ||
| 1348 | MutexPostReadLock(thr, pc, (uptr)m, MutexFlagTryLock); | ||
| 1349 | } | ||
| 1350 | return res; | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | #if !SANITIZER_MAC | ||
| 1354 | TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) { | ||
| 1355 | SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedrdlock, m, abstime); | ||
| 1356 | int res = REAL(pthread_rwlock_timedrdlock)(m, abstime); | ||
| 1357 | if (res == 0) { | ||
| 1358 | MutexPostReadLock(thr, pc, (uptr)m); | ||
| 1359 | } | ||
| 1360 | return res; | ||
| 1361 | } | ||
| 1362 | #endif | ||
| 1363 | |||
| 1364 | TSAN_INTERCEPTOR(int, pthread_rwlock_wrlock, void *m) { | ||
| 1365 | SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_wrlock, m); | ||
| 1366 | MutexPreLock(thr, pc, (uptr)m); | ||
| 1367 | int res = REAL(pthread_rwlock_wrlock)(m); | ||
| 1368 | if (res == 0) { | ||
| 1369 | MutexPostLock(thr, pc, (uptr)m); | ||
| 1370 | } | ||
| 1371 | return res; | ||
| 1372 | } | ||
| 1373 | |||
| 1374 | TSAN_INTERCEPTOR(int, pthread_rwlock_trywrlock, void *m) { | ||
| 1375 | SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_trywrlock, m); | ||
| 1376 | int res = REAL(pthread_rwlock_trywrlock)(m); | ||
| 1377 | if (res == 0) { | ||
| 1378 | MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); | ||
| 1379 | } | ||
| 1380 | return res; | ||
| 1381 | } | ||
| 1382 | |||
| 1383 | #if !SANITIZER_MAC | ||
| 1384 | TSAN_INTERCEPTOR(int, pthread_rwlock_timedwrlock, void *m, void *abstime) { | ||
| 1385 | SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedwrlock, m, abstime); | ||
| 1386 | int res = REAL(pthread_rwlock_timedwrlock)(m, abstime); | ||
| 1387 | if (res == 0) { | ||
| 1388 | MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock); | ||
| 1389 | } | ||
| 1390 | return res; | ||
| 1391 | } | ||
| 1392 | #endif | ||
| 1393 | |||
| 1394 | TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) { | ||
| 1395 | SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_unlock, m); | ||
| 1396 | MutexReadOrWriteUnlock(thr, pc, (uptr)m); | ||
| 1397 | int res = REAL(pthread_rwlock_unlock)(m); | ||
| 1398 | return res; | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | #if !SANITIZER_MAC | ||
| 1402 | TSAN_INTERCEPTOR(int, pthread_barrier_init, void *b, void *a, unsigned count) { | ||
| 1403 | SCOPED_TSAN_INTERCEPTOR(pthread_barrier_init, b, a, count); | ||
| 1404 | MemoryWrite(thr, pc, (uptr)b, kSizeLog1); | ||
| 1405 | int res = REAL(pthread_barrier_init)(b, a, count); | ||
| 1406 | return res; | ||
| 1407 | } | ||
| 1408 | |||
| 1409 | TSAN_INTERCEPTOR(int, pthread_barrier_destroy, void *b) { | ||
| 1410 | SCOPED_TSAN_INTERCEPTOR(pthread_barrier_destroy, b); | ||
| 1411 | MemoryWrite(thr, pc, (uptr)b, kSizeLog1); | ||
| 1412 | int res = REAL(pthread_barrier_destroy)(b); | ||
| 1413 | return res; | ||
| 1414 | } | ||
| 1415 | |||
| 1416 | TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) { | ||
| 1417 | SCOPED_TSAN_INTERCEPTOR(pthread_barrier_wait, b); | ||
| 1418 | Release(thr, pc, (uptr)b); | ||
| 1419 | MemoryRead(thr, pc, (uptr)b, kSizeLog1); | ||
| 1420 | int res = REAL(pthread_barrier_wait)(b); | ||
| 1421 | MemoryRead(thr, pc, (uptr)b, kSizeLog1); | ||
| 1422 | if (res == 0 || res == PTHREAD_BARRIER_SERIAL_THREAD) { | ||
| 1423 | Acquire(thr, pc, (uptr)b); | ||
| 1424 | } | ||
| 1425 | return res; | ||
| 1426 | } | ||
| 1427 | #endif | ||
| 1428 | |||
| 1429 | TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) { | ||
| 1430 | SCOPED_INTERCEPTOR_RAW(pthread_once, o, f); | ||
| 1431 | if (o == 0 || f == 0) | ||
| 1432 | return errno_EINVAL; | ||
| 1433 | atomic_uint32_t *a; | ||
| 1434 | |||
| 1435 | if (SANITIZER_MAC) | ||
| 1436 | a = static_cast<atomic_uint32_t*>((void *)((char *)o + sizeof(long_t))); | ||
| 1437 | else if (SANITIZER_NETBSD) | ||
| 1438 | a = static_cast<atomic_uint32_t*> | ||
| 1439 | ((void *)((char *)o + __sanitizer::pthread_mutex_t_sz)); | ||
| 1440 | else | ||
| 1441 | a = static_cast<atomic_uint32_t*>(o); | ||
| 1442 | |||
| 1443 | u32 v = atomic_load(a, memory_order_acquire); | ||
| 1444 | if (v == 0 && atomic_compare_exchange_strong(a, &v, 1, | ||
| 1445 | memory_order_relaxed)) { | ||
| 1446 | (*f)(); | ||
| 1447 | if (!thr->in_ignored_lib) | ||
| 1448 | Release(thr, pc, (uptr)o); | ||
| 1449 | atomic_store(a, 2, memory_order_release); | ||
| 1450 | } else { | ||
| 1451 | while (v != 2) { | ||
| 1452 | internal_sched_yield(); | ||
| 1453 | v = atomic_load(a, memory_order_acquire); | ||
| 1454 | } | ||
| 1455 | if (!thr->in_ignored_lib) | ||
| 1456 | Acquire(thr, pc, (uptr)o); | ||
| 1457 | } | ||
| 1458 | return 0; | ||
| 1459 | } | ||
| 1460 | |||
| 1461 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 1462 | TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) { | ||
| 1463 | SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf); | ||
| 1464 | if (fd > 0) | ||
| 1465 | FdAccess(thr, pc, fd); | ||
| 1466 | return REAL(__fxstat)(version, fd, buf); | ||
| 1467 | } | ||
| 1468 | #define TSAN_MAYBE_INTERCEPT___FXSTAT TSAN_INTERCEPT(__fxstat) | ||
| 1469 | #else | ||
| 1470 | #define TSAN_MAYBE_INTERCEPT___FXSTAT | ||
| 1471 | #endif | ||
| 1472 | |||
| 1473 | TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) { | ||
| 1474 | #if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_ANDROID || SANITIZER_NETBSD | ||
| 1475 | SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf); | ||
| 1476 | if (fd > 0) | ||
| 1477 | FdAccess(thr, pc, fd); | ||
| 1478 | return REAL(fstat)(fd, buf); | ||
| 1479 | #else | ||
| 1480 | SCOPED_TSAN_INTERCEPTOR(__fxstat, 0, fd, buf); | ||
| 1481 | if (fd > 0) | ||
| 1482 | FdAccess(thr, pc, fd); | ||
| 1483 | return REAL(__fxstat)(0, fd, buf); | ||
| 1484 | #endif | ||
| 1485 | } | ||
| 1486 | |||
| 1487 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 1488 | TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) { | ||
| 1489 | SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf); | ||
| 1490 | if (fd > 0) | ||
| 1491 | FdAccess(thr, pc, fd); | ||
| 1492 | return REAL(__fxstat64)(version, fd, buf); | ||
| 1493 | } | ||
| 1494 | #define TSAN_MAYBE_INTERCEPT___FXSTAT64 TSAN_INTERCEPT(__fxstat64) | ||
| 1495 | #else | ||
| 1496 | #define TSAN_MAYBE_INTERCEPT___FXSTAT64 | ||
| 1497 | #endif | ||
| 1498 | |||
| 1499 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 1500 | TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) { | ||
| 1501 | SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf); | ||
| 1502 | if (fd > 0) | ||
| 1503 | FdAccess(thr, pc, fd); | ||
| 1504 | return REAL(__fxstat64)(0, fd, buf); | ||
| 1505 | } | ||
| 1506 | #define TSAN_MAYBE_INTERCEPT_FSTAT64 TSAN_INTERCEPT(fstat64) | ||
| 1507 | #else | ||
| 1508 | #define TSAN_MAYBE_INTERCEPT_FSTAT64 | ||
| 1509 | #endif | ||
| 1510 | |||
| 1511 | TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) { | ||
| 1512 | SCOPED_TSAN_INTERCEPTOR(open, name, flags, mode); | ||
| 1513 | READ_STRING(thr, pc, name, 0); | ||
| 1514 | int fd = REAL(open)(name, flags, mode); | ||
| 1515 | if (fd >= 0) | ||
| 1516 | FdFileCreate(thr, pc, fd); | ||
| 1517 | return fd; | ||
| 1518 | } | ||
| 1519 | |||
| 1520 | #if SANITIZER_LINUX | ||
| 1521 | TSAN_INTERCEPTOR(int, open64, const char *name, int flags, int mode) { | ||
| 1522 | SCOPED_TSAN_INTERCEPTOR(open64, name, flags, mode); | ||
| 1523 | READ_STRING(thr, pc, name, 0); | ||
| 1524 | int fd = REAL(open64)(name, flags, mode); | ||
| 1525 | if (fd >= 0) | ||
| 1526 | FdFileCreate(thr, pc, fd); | ||
| 1527 | return fd; | ||
| 1528 | } | ||
| 1529 | #define TSAN_MAYBE_INTERCEPT_OPEN64 TSAN_INTERCEPT(open64) | ||
| 1530 | #else | ||
| 1531 | #define TSAN_MAYBE_INTERCEPT_OPEN64 | ||
| 1532 | #endif | ||
| 1533 | |||
| 1534 | TSAN_INTERCEPTOR(int, creat, const char *name, int mode) { | ||
| 1535 | SCOPED_TSAN_INTERCEPTOR(creat, name, mode); | ||
| 1536 | READ_STRING(thr, pc, name, 0); | ||
| 1537 | int fd = REAL(creat)(name, mode); | ||
| 1538 | if (fd >= 0) | ||
| 1539 | FdFileCreate(thr, pc, fd); | ||
| 1540 | return fd; | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | #if SANITIZER_LINUX | ||
| 1544 | TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) { | ||
| 1545 | SCOPED_TSAN_INTERCEPTOR(creat64, name, mode); | ||
| 1546 | READ_STRING(thr, pc, name, 0); | ||
| 1547 | int fd = REAL(creat64)(name, mode); | ||
| 1548 | if (fd >= 0) | ||
| 1549 | FdFileCreate(thr, pc, fd); | ||
| 1550 | return fd; | ||
| 1551 | } | ||
| 1552 | #define TSAN_MAYBE_INTERCEPT_CREAT64 TSAN_INTERCEPT(creat64) | ||
| 1553 | #else | ||
| 1554 | #define TSAN_MAYBE_INTERCEPT_CREAT64 | ||
| 1555 | #endif | ||
| 1556 | |||
| 1557 | TSAN_INTERCEPTOR(int, dup, int oldfd) { | ||
| 1558 | SCOPED_TSAN_INTERCEPTOR(dup, oldfd); | ||
| 1559 | int newfd = REAL(dup)(oldfd); | ||
| 1560 | if (oldfd >= 0 && newfd >= 0 && newfd != oldfd) | ||
| 1561 | FdDup(thr, pc, oldfd, newfd, true); | ||
| 1562 | return newfd; | ||
| 1563 | } | ||
| 1564 | |||
| 1565 | TSAN_INTERCEPTOR(int, dup2, int oldfd, int newfd) { | ||
| 1566 | SCOPED_TSAN_INTERCEPTOR(dup2, oldfd, newfd); | ||
| 1567 | int newfd2 = REAL(dup2)(oldfd, newfd); | ||
| 1568 | if (oldfd >= 0 && newfd2 >= 0 && newfd2 != oldfd) | ||
| 1569 | FdDup(thr, pc, oldfd, newfd2, false); | ||
| 1570 | return newfd2; | ||
| 1571 | } | ||
| 1572 | |||
| 1573 | #if !SANITIZER_MAC | ||
| 1574 | TSAN_INTERCEPTOR(int, dup3, int oldfd, int newfd, int flags) { | ||
| 1575 | SCOPED_TSAN_INTERCEPTOR(dup3, oldfd, newfd, flags); | ||
| 1576 | int newfd2 = REAL(dup3)(oldfd, newfd, flags); | ||
| 1577 | if (oldfd >= 0 && newfd2 >= 0 && newfd2 != oldfd) | ||
| 1578 | FdDup(thr, pc, oldfd, newfd2, false); | ||
| 1579 | return newfd2; | ||
| 1580 | } | ||
| 1581 | #endif | ||
| 1582 | |||
| 1583 | #if SANITIZER_LINUX | ||
| 1584 | TSAN_INTERCEPTOR(int, eventfd, unsigned initval, int flags) { | ||
| 1585 | SCOPED_TSAN_INTERCEPTOR(eventfd, initval, flags); | ||
| 1586 | int fd = REAL(eventfd)(initval, flags); | ||
| 1587 | if (fd >= 0) | ||
| 1588 | FdEventCreate(thr, pc, fd); | ||
| 1589 | return fd; | ||
| 1590 | } | ||
| 1591 | #define TSAN_MAYBE_INTERCEPT_EVENTFD TSAN_INTERCEPT(eventfd) | ||
| 1592 | #else | ||
| 1593 | #define TSAN_MAYBE_INTERCEPT_EVENTFD | ||
| 1594 | #endif | ||
| 1595 | |||
| 1596 | #if SANITIZER_LINUX | ||
| 1597 | TSAN_INTERCEPTOR(int, signalfd, int fd, void *mask, int flags) { | ||
| 1598 | SCOPED_TSAN_INTERCEPTOR(signalfd, fd, mask, flags); | ||
| 1599 | if (fd >= 0) | ||
| 1600 | FdClose(thr, pc, fd); | ||
| 1601 | fd = REAL(signalfd)(fd, mask, flags); | ||
| 1602 | if (fd >= 0) | ||
| 1603 | FdSignalCreate(thr, pc, fd); | ||
| 1604 | return fd; | ||
| 1605 | } | ||
| 1606 | #define TSAN_MAYBE_INTERCEPT_SIGNALFD TSAN_INTERCEPT(signalfd) | ||
| 1607 | #else | ||
| 1608 | #define TSAN_MAYBE_INTERCEPT_SIGNALFD | ||
| 1609 | #endif | ||
| 1610 | |||
| 1611 | #if SANITIZER_LINUX | ||
| 1612 | TSAN_INTERCEPTOR(int, inotify_init, int fake) { | ||
| 1613 | SCOPED_TSAN_INTERCEPTOR(inotify_init, fake); | ||
| 1614 | int fd = REAL(inotify_init)(fake); | ||
| 1615 | if (fd >= 0) | ||
| 1616 | FdInotifyCreate(thr, pc, fd); | ||
| 1617 | return fd; | ||
| 1618 | } | ||
| 1619 | #define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT TSAN_INTERCEPT(inotify_init) | ||
| 1620 | #else | ||
| 1621 | #define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT | ||
| 1622 | #endif | ||
| 1623 | |||
| 1624 | #if SANITIZER_LINUX | ||
| 1625 | TSAN_INTERCEPTOR(int, inotify_init1, int flags) { | ||
| 1626 | SCOPED_TSAN_INTERCEPTOR(inotify_init1, flags); | ||
| 1627 | int fd = REAL(inotify_init1)(flags); | ||
| 1628 | if (fd >= 0) | ||
| 1629 | FdInotifyCreate(thr, pc, fd); | ||
| 1630 | return fd; | ||
| 1631 | } | ||
| 1632 | #define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1 TSAN_INTERCEPT(inotify_init1) | ||
| 1633 | #else | ||
| 1634 | #define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1 | ||
| 1635 | #endif | ||
| 1636 | |||
| 1637 | TSAN_INTERCEPTOR(int, socket, int domain, int type, int protocol) { | ||
| 1638 | SCOPED_TSAN_INTERCEPTOR(socket, domain, type, protocol); | ||
| 1639 | int fd = REAL(socket)(domain, type, protocol); | ||
| 1640 | if (fd >= 0) | ||
| 1641 | FdSocketCreate(thr, pc, fd); | ||
| 1642 | return fd; | ||
| 1643 | } | ||
| 1644 | |||
| 1645 | TSAN_INTERCEPTOR(int, socketpair, int domain, int type, int protocol, int *fd) { | ||
| 1646 | SCOPED_TSAN_INTERCEPTOR(socketpair, domain, type, protocol, fd); | ||
| 1647 | int res = REAL(socketpair)(domain, type, protocol, fd); | ||
| 1648 | if (res == 0 && fd[0] >= 0 && fd[1] >= 0) | ||
| 1649 | FdPipeCreate(thr, pc, fd[0], fd[1]); | ||
| 1650 | return res; | ||
| 1651 | } | ||
| 1652 | |||
| 1653 | TSAN_INTERCEPTOR(int, connect, int fd, void *addr, unsigned addrlen) { | ||
| 1654 | SCOPED_TSAN_INTERCEPTOR(connect, fd, addr, addrlen); | ||
| 1655 | FdSocketConnecting(thr, pc, fd); | ||
| 1656 | int res = REAL(connect)(fd, addr, addrlen); | ||
| 1657 | if (res == 0 && fd >= 0) | ||
| 1658 | FdSocketConnect(thr, pc, fd); | ||
| 1659 | return res; | ||
| 1660 | } | ||
| 1661 | |||
| 1662 | TSAN_INTERCEPTOR(int, bind, int fd, void *addr, unsigned addrlen) { | ||
| 1663 | SCOPED_TSAN_INTERCEPTOR(bind, fd, addr, addrlen); | ||
| 1664 | int res = REAL(bind)(fd, addr, addrlen); | ||
| 1665 | if (fd > 0 && res == 0) | ||
| 1666 | FdAccess(thr, pc, fd); | ||
| 1667 | return res; | ||
| 1668 | } | ||
| 1669 | |||
| 1670 | TSAN_INTERCEPTOR(int, listen, int fd, int backlog) { | ||
| 1671 | SCOPED_TSAN_INTERCEPTOR(listen, fd, backlog); | ||
| 1672 | int res = REAL(listen)(fd, backlog); | ||
| 1673 | if (fd > 0 && res == 0) | ||
| 1674 | FdAccess(thr, pc, fd); | ||
| 1675 | return res; | ||
| 1676 | } | ||
| 1677 | |||
| 1678 | TSAN_INTERCEPTOR(int, close, int fd) { | ||
| 1679 | SCOPED_TSAN_INTERCEPTOR(close, fd); | ||
| 1680 | if (fd >= 0) | ||
| 1681 | FdClose(thr, pc, fd); | ||
| 1682 | return REAL(close)(fd); | ||
| 1683 | } | ||
| 1684 | |||
| 1685 | #if SANITIZER_LINUX | ||
| 1686 | TSAN_INTERCEPTOR(int, __close, int fd) { | ||
| 1687 | SCOPED_TSAN_INTERCEPTOR(__close, fd); | ||
| 1688 | if (fd >= 0) | ||
| 1689 | FdClose(thr, pc, fd); | ||
| 1690 | return REAL(__close)(fd); | ||
| 1691 | } | ||
| 1692 | #define TSAN_MAYBE_INTERCEPT___CLOSE TSAN_INTERCEPT(__close) | ||
| 1693 | #else | ||
| 1694 | #define TSAN_MAYBE_INTERCEPT___CLOSE | ||
| 1695 | #endif | ||
| 1696 | |||
| 1697 | // glibc guts | ||
| 1698 | #if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
| 1699 | TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) { | ||
| 1700 | SCOPED_TSAN_INTERCEPTOR(__res_iclose, state, free_addr); | ||
| 1701 | int fds[64]; | ||
| 1702 | int cnt = ExtractResolvFDs(state, fds, ARRAY_SIZE(fds)); | ||
| 1703 | for (int i = 0; i < cnt; i++) { | ||
| 1704 | if (fds[i] > 0) | ||
| 1705 | FdClose(thr, pc, fds[i]); | ||
| 1706 | } | ||
| 1707 | REAL(__res_iclose)(state, free_addr); | ||
| 1708 | } | ||
| 1709 | #define TSAN_MAYBE_INTERCEPT___RES_ICLOSE TSAN_INTERCEPT(__res_iclose) | ||
| 1710 | #else | ||
| 1711 | #define TSAN_MAYBE_INTERCEPT___RES_ICLOSE | ||
| 1712 | #endif | ||
| 1713 | |||
| 1714 | TSAN_INTERCEPTOR(int, pipe, int *pipefd) { | ||
| 1715 | SCOPED_TSAN_INTERCEPTOR(pipe, pipefd); | ||
| 1716 | int res = REAL(pipe)(pipefd); | ||
| 1717 | if (res == 0 && pipefd[0] >= 0 && pipefd[1] >= 0) | ||
| 1718 | FdPipeCreate(thr, pc, pipefd[0], pipefd[1]); | ||
| 1719 | return res; | ||
| 1720 | } | ||
| 1721 | |||
| 1722 | #if !SANITIZER_MAC | ||
| 1723 | TSAN_INTERCEPTOR(int, pipe2, int *pipefd, int flags) { | ||
| 1724 | SCOPED_TSAN_INTERCEPTOR(pipe2, pipefd, flags); | ||
| 1725 | int res = REAL(pipe2)(pipefd, flags); | ||
| 1726 | if (res == 0 && pipefd[0] >= 0 && pipefd[1] >= 0) | ||
| 1727 | FdPipeCreate(thr, pc, pipefd[0], pipefd[1]); | ||
| 1728 | return res; | ||
| 1729 | } | ||
| 1730 | #endif | ||
| 1731 | |||
| 1732 | TSAN_INTERCEPTOR(int, unlink, char *path) { | ||
| 1733 | SCOPED_TSAN_INTERCEPTOR(unlink, path); | ||
| 1734 | Release(thr, pc, File2addr(path)); | ||
| 1735 | int res = REAL(unlink)(path); | ||
| 1736 | return res; | ||
| 1737 | } | ||
| 1738 | |||
| 1739 | TSAN_INTERCEPTOR(void*, tmpfile, int fake) { | ||
| 1740 | SCOPED_TSAN_INTERCEPTOR(tmpfile, fake); | ||
| 1741 | void *res = REAL(tmpfile)(fake); | ||
| 1742 | if (res) { | ||
| 1743 | int fd = fileno_unlocked(res); | ||
| 1744 | if (fd >= 0) | ||
| 1745 | FdFileCreate(thr, pc, fd); | ||
| 1746 | } | ||
| 1747 | return res; | ||
| 1748 | } | ||
| 1749 | |||
| 1750 | #if SANITIZER_LINUX | ||
| 1751 | TSAN_INTERCEPTOR(void*, tmpfile64, int fake) { | ||
| 1752 | SCOPED_TSAN_INTERCEPTOR(tmpfile64, fake); | ||
| 1753 | void *res = REAL(tmpfile64)(fake); | ||
| 1754 | if (res) { | ||
| 1755 | int fd = fileno_unlocked(res); | ||
| 1756 | if (fd >= 0) | ||
| 1757 | FdFileCreate(thr, pc, fd); | ||
| 1758 | } | ||
| 1759 | return res; | ||
| 1760 | } | ||
| 1761 | #define TSAN_MAYBE_INTERCEPT_TMPFILE64 TSAN_INTERCEPT(tmpfile64) | ||
| 1762 | #else | ||
| 1763 | #define TSAN_MAYBE_INTERCEPT_TMPFILE64 | ||
| 1764 | #endif | ||
| 1765 | |||
| 1766 | static void FlushStreams() { | ||
| 1767 | // Flushing all the streams here may freeze the process if a child thread is | ||
| 1768 | // performing file stream operations at the same time. | ||
| 1769 | REAL(fflush)(stdout); | ||
| 1770 | REAL(fflush)(stderr); | ||
| 1771 | } | ||
| 1772 | |||
| 1773 | TSAN_INTERCEPTOR(void, abort, int fake) { | ||
| 1774 | SCOPED_TSAN_INTERCEPTOR(abort, fake); | ||
| 1775 | FlushStreams(); | ||
| 1776 | REAL(abort)(fake); | ||
| 1777 | } | ||
| 1778 | |||
| 1779 | TSAN_INTERCEPTOR(int, rmdir, char *path) { | ||
| 1780 | SCOPED_TSAN_INTERCEPTOR(rmdir, path); | ||
| 1781 | Release(thr, pc, Dir2addr(path)); | ||
| 1782 | int res = REAL(rmdir)(path); | ||
| 1783 | return res; | ||
| 1784 | } | ||
| 1785 | |||
| 1786 | TSAN_INTERCEPTOR(int, closedir, void *dirp) { | ||
| 1787 | SCOPED_TSAN_INTERCEPTOR(closedir, dirp); | ||
| 1788 | if (dirp) { | ||
| 1789 | int fd = dirfd(dirp); | ||
| 1790 | FdClose(thr, pc, fd); | ||
| 1791 | } | ||
| 1792 | return REAL(closedir)(dirp); | ||
| 1793 | } | ||
| 1794 | |||
| 1795 | #if SANITIZER_LINUX | ||
| 1796 | TSAN_INTERCEPTOR(int, epoll_create, int size) { | ||
| 1797 | SCOPED_TSAN_INTERCEPTOR(epoll_create, size); | ||
| 1798 | int fd = REAL(epoll_create)(size); | ||
| 1799 | if (fd >= 0) | ||
| 1800 | FdPollCreate(thr, pc, fd); | ||
| 1801 | return fd; | ||
| 1802 | } | ||
| 1803 | |||
| 1804 | TSAN_INTERCEPTOR(int, epoll_create1, int flags) { | ||
| 1805 | SCOPED_TSAN_INTERCEPTOR(epoll_create1, flags); | ||
| 1806 | int fd = REAL(epoll_create1)(flags); | ||
| 1807 | if (fd >= 0) | ||
| 1808 | FdPollCreate(thr, pc, fd); | ||
| 1809 | return fd; | ||
| 1810 | } | ||
| 1811 | |||
| 1812 | TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) { | ||
| 1813 | SCOPED_TSAN_INTERCEPTOR(epoll_ctl, epfd, op, fd, ev); | ||
| 1814 | if (epfd >= 0) | ||
| 1815 | FdAccess(thr, pc, epfd); | ||
| 1816 | if (epfd >= 0 && fd >= 0) | ||
| 1817 | FdAccess(thr, pc, fd); | ||
| 1818 | if (op == EPOLL_CTL_ADD && epfd >= 0) | ||
| 1819 | FdRelease(thr, pc, epfd); | ||
| 1820 | int res = REAL(epoll_ctl)(epfd, op, fd, ev); | ||
| 1821 | return res; | ||
| 1822 | } | ||
| 1823 | |||
| 1824 | TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) { | ||
| 1825 | SCOPED_TSAN_INTERCEPTOR(epoll_wait, epfd, ev, cnt, timeout); | ||
| 1826 | if (epfd >= 0) | ||
| 1827 | FdAccess(thr, pc, epfd); | ||
| 1828 | int res = BLOCK_REAL(epoll_wait)(epfd, ev, cnt, timeout); | ||
| 1829 | if (res > 0 && epfd >= 0) | ||
| 1830 | FdAcquire(thr, pc, epfd); | ||
| 1831 | return res; | ||
| 1832 | } | ||
| 1833 | |||
| 1834 | TSAN_INTERCEPTOR(int, epoll_pwait, int epfd, void *ev, int cnt, int timeout, | ||
| 1835 | void *sigmask) { | ||
| 1836 | SCOPED_TSAN_INTERCEPTOR(epoll_pwait, epfd, ev, cnt, timeout, sigmask); | ||
| 1837 | if (epfd >= 0) | ||
| 1838 | FdAccess(thr, pc, epfd); | ||
| 1839 | int res = BLOCK_REAL(epoll_pwait)(epfd, ev, cnt, timeout, sigmask); | ||
| 1840 | if (res > 0 && epfd >= 0) | ||
| 1841 | FdAcquire(thr, pc, epfd); | ||
| 1842 | return res; | ||
| 1843 | } | ||
| 1844 | |||
| 1845 | #define TSAN_MAYBE_INTERCEPT_EPOLL \ | ||
| 1846 | TSAN_INTERCEPT(epoll_create); \ | ||
| 1847 | TSAN_INTERCEPT(epoll_create1); \ | ||
| 1848 | TSAN_INTERCEPT(epoll_ctl); \ | ||
| 1849 | TSAN_INTERCEPT(epoll_wait); \ | ||
| 1850 | TSAN_INTERCEPT(epoll_pwait) | ||
| 1851 | #else | ||
| 1852 | #define TSAN_MAYBE_INTERCEPT_EPOLL | ||
| 1853 | #endif | ||
| 1854 | |||
| 1855 | // The following functions are intercepted merely to process pending signals. | ||
| 1856 | // If program blocks signal X, we must deliver the signal before the function | ||
| 1857 | // returns. Similarly, if program unblocks a signal (or returns from sigsuspend) | ||
| 1858 | // it's better to deliver the signal straight away. | ||
| 1859 | TSAN_INTERCEPTOR(int, sigsuspend, const __sanitizer_sigset_t *mask) { | ||
| 1860 | SCOPED_TSAN_INTERCEPTOR(sigsuspend, mask); | ||
| 1861 | return REAL(sigsuspend)(mask); | ||
| 1862 | } | ||
| 1863 | |||
| 1864 | TSAN_INTERCEPTOR(int, sigblock, int mask) { | ||
| 1865 | SCOPED_TSAN_INTERCEPTOR(sigblock, mask); | ||
| 1866 | return REAL(sigblock)(mask); | ||
| 1867 | } | ||
| 1868 | |||
| 1869 | TSAN_INTERCEPTOR(int, sigsetmask, int mask) { | ||
| 1870 | SCOPED_TSAN_INTERCEPTOR(sigsetmask, mask); | ||
| 1871 | return REAL(sigsetmask)(mask); | ||
| 1872 | } | ||
| 1873 | |||
| 1874 | TSAN_INTERCEPTOR(int, pthread_sigmask, int how, const __sanitizer_sigset_t *set, | ||
| 1875 | __sanitizer_sigset_t *oldset) { | ||
| 1876 | SCOPED_TSAN_INTERCEPTOR(pthread_sigmask, how, set, oldset); | ||
| 1877 | return REAL(pthread_sigmask)(how, set, oldset); | ||
| 1878 | } | ||
| 1879 | |||
| 1880 | namespace __tsan { | ||
| 1881 | |||
| 1882 | static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire, | ||
| 1883 | bool sigact, int sig, | ||
| 1884 | __sanitizer_siginfo *info, void *uctx) { | ||
| 1885 | __sanitizer_sigaction *sigactions = interceptor_ctx()->sigactions; | ||
| 1886 | if (acquire) | ||
| 1887 | Acquire(thr, 0, (uptr)&sigactions[sig]); | ||
| 1888 | // Signals are generally asynchronous, so if we receive a signals when | ||
| 1889 | // ignores are enabled we should disable ignores. This is critical for sync | ||
| 1890 | // and interceptors, because otherwise we can miss syncronization and report | ||
| 1891 | // false races. | ||
| 1892 | int ignore_reads_and_writes = thr->ignore_reads_and_writes; | ||
| 1893 | int ignore_interceptors = thr->ignore_interceptors; | ||
| 1894 | int ignore_sync = thr->ignore_sync; | ||
| 1895 | if (!ctx->after_multithreaded_fork) { | ||
| 1896 | thr->ignore_reads_and_writes = 0; | ||
| 1897 | thr->fast_state.ClearIgnoreBit(); | ||
| 1898 | thr->ignore_interceptors = 0; | ||
| 1899 | thr->ignore_sync = 0; | ||
| 1900 | } | ||
| 1901 | // Ensure that the handler does not spoil errno. | ||
| 1902 | const int saved_errno = errno; | ||
| 1903 | errno = 99; | ||
| 1904 | // This code races with sigaction. Be careful to not read sa_sigaction twice. | ||
| 1905 | // Also need to remember pc for reporting before the call, | ||
| 1906 | // because the handler can reset it. | ||
| 1907 | volatile uptr pc = | ||
| 1908 | sigact ? (uptr)sigactions[sig].sigaction : (uptr)sigactions[sig].handler; | ||
| 1909 | if (pc != sig_dfl && pc != sig_ign) { | ||
| 1910 | if (sigact) | ||
| 1911 | ((__sanitizer_sigactionhandler_ptr)pc)(sig, info, uctx); | ||
| 1912 | else | ||
| 1913 | ((__sanitizer_sighandler_ptr)pc)(sig); | ||
| 1914 | } | ||
| 1915 | if (!ctx->after_multithreaded_fork) { | ||
| 1916 | thr->ignore_reads_and_writes = ignore_reads_and_writes; | ||
| 1917 | if (ignore_reads_and_writes) | ||
| 1918 | thr->fast_state.SetIgnoreBit(); | ||
| 1919 | thr->ignore_interceptors = ignore_interceptors; | ||
| 1920 | thr->ignore_sync = ignore_sync; | ||
| 1921 | } | ||
| 1922 | // We do not detect errno spoiling for SIGTERM, | ||
| 1923 | // because some SIGTERM handlers do spoil errno but reraise SIGTERM, | ||
| 1924 | // tsan reports false positive in such case. | ||
| 1925 | // It's difficult to properly detect this situation (reraise), | ||
| 1926 | // because in async signal processing case (when handler is called directly | ||
| 1927 | // from rtl_generic_sighandler) we have not yet received the reraised | ||
| 1928 | // signal; and it looks too fragile to intercept all ways to reraise a signal. | ||
| 1929 | if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) { | ||
| 1930 | VarSizeStackTrace stack; | ||
| 1931 | // StackTrace::GetNestInstructionPc(pc) is used because return address is | ||
| 1932 | // expected, OutputReport() will undo this. | ||
| 1933 | ObtainCurrentStack(thr, StackTrace::GetNextInstructionPc(pc), &stack); | ||
| 1934 | ThreadRegistryLock l(ctx->thread_registry); | ||
| 1935 | ScopedReport rep(ReportTypeErrnoInSignal); | ||
| 1936 | if (!IsFiredSuppression(ctx, ReportTypeErrnoInSignal, stack)) { | ||
| 1937 | rep.AddStack(stack, true); | ||
| 1938 | OutputReport(thr, rep); | ||
| 1939 | } | ||
| 1940 | } | ||
| 1941 | errno = saved_errno; | ||
| 1942 | } | ||
| 1943 | |||
| 1944 | void ProcessPendingSignals(ThreadState *thr) { | ||
| 1945 | ThreadSignalContext *sctx = SigCtx(thr); | ||
| 1946 | if (sctx == 0 || | ||
| 1947 | atomic_load(&sctx->have_pending_signals, memory_order_relaxed) == 0) | ||
| 1948 | return; | ||
| 1949 | atomic_store(&sctx->have_pending_signals, 0, memory_order_relaxed); | ||
| 1950 | atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed); | ||
| 1951 | internal_sigfillset(&sctx->emptyset); | ||
| 1952 | int res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->emptyset, &sctx->oldset); | ||
| 1953 | CHECK_EQ(res, 0); | ||
| 1954 | for (int sig = 0; sig < kSigCount; sig++) { | ||
| 1955 | SignalDesc *signal = &sctx->pending_signals[sig]; | ||
| 1956 | if (signal->armed) { | ||
| 1957 | signal->armed = false; | ||
| 1958 | CallUserSignalHandler(thr, false, true, signal->sigaction, sig, | ||
| 1959 | &signal->siginfo, &signal->ctx); | ||
| 1960 | } | ||
| 1961 | } | ||
| 1962 | res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->oldset, 0); | ||
| 1963 | CHECK_EQ(res, 0); | ||
| 1964 | atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed); | ||
| 1965 | } | ||
| 1966 | |||
| 1967 | } // namespace __tsan | ||
| 1968 | |||
| 1969 | static bool is_sync_signal(ThreadSignalContext *sctx, int sig) { | ||
| 1970 | return sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || sig == SIGTRAP || | ||
| 1971 | sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS || | ||
| 1972 | // If we are sending signal to ourselves, we must process it now. | ||
| 1973 | (sctx && sig == sctx->int_signal_send); | ||
| 1974 | } | ||
| 1975 | |||
| 1976 | void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig, | ||
| 1977 | __sanitizer_siginfo *info, | ||
| 1978 | void *ctx) { | ||
| 1979 | cur_thread_init(); | ||
| 1980 | ThreadState *thr = cur_thread(); | ||
| 1981 | ThreadSignalContext *sctx = SigCtx(thr); | ||
| 1982 | if (sig < 0 || sig >= kSigCount) { | ||
| 1983 | VPrintf(1, "ThreadSanitizer: ignoring signal %d\n", sig); | ||
| 1984 | return; | ||
| 1985 | } | ||
| 1986 | // Don't mess with synchronous signals. | ||
| 1987 | const bool sync = is_sync_signal(sctx, sig); | ||
| 1988 | if (sync || | ||
| 1989 | // If we are in blocking function, we can safely process it now | ||
| 1990 | // (but check if we are in a recursive interceptor, | ||
| 1991 | // i.e. pthread_join()->munmap()). | ||
| 1992 | (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed))) { | ||
| 1993 | atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed); | ||
| 1994 | if (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed)) { | ||
| 1995 | atomic_store(&sctx->in_blocking_func, 0, memory_order_relaxed); | ||
| 1996 | CallUserSignalHandler(thr, sync, true, sigact, sig, info, ctx); | ||
| 1997 | atomic_store(&sctx->in_blocking_func, 1, memory_order_relaxed); | ||
| 1998 | } else { | ||
| 1999 | // Be very conservative with when we do acquire in this case. | ||
| 2000 | // It's unsafe to do acquire in async handlers, because ThreadState | ||
| 2001 | // can be in inconsistent state. | ||
| 2002 | // SIGSYS looks relatively safe -- it's synchronous and can actually | ||
| 2003 | // need some global state. | ||
| 2004 | bool acq = (sig == SIGSYS); | ||
| 2005 | CallUserSignalHandler(thr, sync, acq, sigact, sig, info, ctx); | ||
| 2006 | } | ||
| 2007 | atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed); | ||
| 2008 | return; | ||
| 2009 | } | ||
| 2010 | |||
| 2011 | if (sctx == 0) | ||
| 2012 | return; | ||
| 2013 | SignalDesc *signal = &sctx->pending_signals[sig]; | ||
| 2014 | if (signal->armed == false) { | ||
| 2015 | signal->armed = true; | ||
| 2016 | signal->sigaction = sigact; | ||
| 2017 | if (info) | ||
| 2018 | internal_memcpy(&signal->siginfo, info, sizeof(*info)); | ||
| 2019 | if (ctx) | ||
| 2020 | internal_memcpy(&signal->ctx, ctx, sizeof(signal->ctx)); | ||
| 2021 | atomic_store(&sctx->have_pending_signals, 1, memory_order_relaxed); | ||
| 2022 | } | ||
| 2023 | } | ||
| 2024 | |||
| 2025 | static void rtl_sighandler(int sig) { | ||
| 2026 | rtl_generic_sighandler(false, sig, 0, 0); | ||
| 2027 | } | ||
| 2028 | |||
| 2029 | static void rtl_sigaction(int sig, __sanitizer_siginfo *info, void *ctx) { | ||
| 2030 | rtl_generic_sighandler(true, sig, info, ctx); | ||
| 2031 | } | ||
| 2032 | |||
| 2033 | TSAN_INTERCEPTOR(int, raise, int sig) { | ||
| 2034 | SCOPED_TSAN_INTERCEPTOR(raise, sig); | ||
| 2035 | ThreadSignalContext *sctx = SigCtx(thr); | ||
| 2036 | CHECK_NE(sctx, 0); | ||
| 2037 | int prev = sctx->int_signal_send; | ||
| 2038 | sctx->int_signal_send = sig; | ||
| 2039 | int res = REAL(raise)(sig); | ||
| 2040 | CHECK_EQ(sctx->int_signal_send, sig); | ||
| 2041 | sctx->int_signal_send = prev; | ||
| 2042 | return res; | ||
| 2043 | } | ||
| 2044 | |||
| 2045 | TSAN_INTERCEPTOR(int, kill, int pid, int sig) { | ||
| 2046 | SCOPED_TSAN_INTERCEPTOR(kill, pid, sig); | ||
| 2047 | ThreadSignalContext *sctx = SigCtx(thr); | ||
| 2048 | CHECK_NE(sctx, 0); | ||
| 2049 | int prev = sctx->int_signal_send; | ||
| 2050 | if (pid == (int)internal_getpid()) { | ||
| 2051 | sctx->int_signal_send = sig; | ||
| 2052 | } | ||
| 2053 | int res = REAL(kill)(pid, sig); | ||
| 2054 | if (pid == (int)internal_getpid()) { | ||
| 2055 | CHECK_EQ(sctx->int_signal_send, sig); | ||
| 2056 | sctx->int_signal_send = prev; | ||
| 2057 | } | ||
| 2058 | return res; | ||
| 2059 | } | ||
| 2060 | |||
| 2061 | TSAN_INTERCEPTOR(int, pthread_kill, void *tid, int sig) { | ||
| 2062 | SCOPED_TSAN_INTERCEPTOR(pthread_kill, tid, sig); | ||
| 2063 | ThreadSignalContext *sctx = SigCtx(thr); | ||
| 2064 | CHECK_NE(sctx, 0); | ||
| 2065 | int prev = sctx->int_signal_send; | ||
| 2066 | if (tid == pthread_self()) { | ||
| 2067 | sctx->int_signal_send = sig; | ||
| 2068 | } | ||
| 2069 | int res = REAL(pthread_kill)(tid, sig); | ||
| 2070 | if (tid == pthread_self()) { | ||
| 2071 | CHECK_EQ(sctx->int_signal_send, sig); | ||
| 2072 | sctx->int_signal_send = prev; | ||
| 2073 | } | ||
| 2074 | return res; | ||
| 2075 | } | ||
| 2076 | |||
| 2077 | TSAN_INTERCEPTOR(int, gettimeofday, void *tv, void *tz) { | ||
| 2078 | SCOPED_TSAN_INTERCEPTOR(gettimeofday, tv, tz); | ||
| 2079 | // It's intercepted merely to process pending signals. | ||
| 2080 | return REAL(gettimeofday)(tv, tz); | ||
| 2081 | } | ||
| 2082 | |||
| 2083 | TSAN_INTERCEPTOR(int, getaddrinfo, void *node, void *service, | ||
| 2084 | void *hints, void *rv) { | ||
| 2085 | SCOPED_TSAN_INTERCEPTOR(getaddrinfo, node, service, hints, rv); | ||
| 2086 | // We miss atomic synchronization in getaddrinfo, | ||
| 2087 | // and can report false race between malloc and free | ||
| 2088 | // inside of getaddrinfo. So ignore memory accesses. | ||
| 2089 | ThreadIgnoreBegin(thr, pc); | ||
| 2090 | int res = REAL(getaddrinfo)(node, service, hints, rv); | ||
| 2091 | ThreadIgnoreEnd(thr, pc); | ||
| 2092 | return res; | ||
| 2093 | } | ||
| 2094 | |||
| 2095 | TSAN_INTERCEPTOR(int, fork, int fake) { | ||
| 2096 | if (in_symbolizer()) | ||
| 2097 | return REAL(fork)(fake); | ||
| 2098 | SCOPED_INTERCEPTOR_RAW(fork, fake); | ||
| 2099 | ForkBefore(thr, pc); | ||
| 2100 | int pid; | ||
| 2101 | { | ||
| 2102 | // On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and | ||
| 2103 | // we'll assert in CheckNoLocks() unless we ignore interceptors. | ||
| 2104 | ScopedIgnoreInterceptors ignore; | ||
| 2105 | pid = REAL(fork)(fake); | ||
| 2106 | } | ||
| 2107 | if (pid == 0) { | ||
| 2108 | // child | ||
| 2109 | ForkChildAfter(thr, pc); | ||
| 2110 | FdOnFork(thr, pc); | ||
| 2111 | } else if (pid > 0) { | ||
| 2112 | // parent | ||
| 2113 | ForkParentAfter(thr, pc); | ||
| 2114 | } else { | ||
| 2115 | // error | ||
| 2116 | ForkParentAfter(thr, pc); | ||
| 2117 | } | ||
| 2118 | return pid; | ||
| 2119 | } | ||
| 2120 | |||
| 2121 | TSAN_INTERCEPTOR(int, vfork, int fake) { | ||
| 2122 | // Some programs (e.g. openjdk) call close for all file descriptors | ||
| 2123 | // in the child process. Under tsan it leads to false positives, because | ||
| 2124 | // address space is shared, so the parent process also thinks that | ||
| 2125 | // the descriptors are closed (while they are actually not). | ||
| 2126 | // This leads to false positives due to missed synchronization. | ||
| 2127 | // Strictly saying this is undefined behavior, because vfork child is not | ||
| 2128 | // allowed to call any functions other than exec/exit. But this is what | ||
| 2129 | // openjdk does, so we want to handle it. | ||
| 2130 | // We could disable interceptors in the child process. But it's not possible | ||
| 2131 | // to simply intercept and wrap vfork, because vfork child is not allowed | ||
| 2132 | // to return from the function that calls vfork, and that's exactly what | ||
| 2133 | // we would do. So this would require some assembly trickery as well. | ||
| 2134 | // Instead we simply turn vfork into fork. | ||
| 2135 | return WRAP(fork)(fake); | ||
| 2136 | } | ||
| 2137 | |||
| 2138 | #if !SANITIZER_MAC && !SANITIZER_ANDROID | ||
| 2139 | typedef int (*dl_iterate_phdr_cb_t)(__sanitizer_dl_phdr_info *info, SIZE_T size, | ||
| 2140 | void *data); | ||
| 2141 | struct dl_iterate_phdr_data { | ||
| 2142 | ThreadState *thr; | ||
| 2143 | uptr pc; | ||
| 2144 | dl_iterate_phdr_cb_t cb; | ||
| 2145 | void *data; | ||
| 2146 | }; | ||
| 2147 | |||
| 2148 | static bool IsAppNotRodata(uptr addr) { | ||
| 2149 | return IsAppMem(addr) && *(u64*)MemToShadow(addr) != kShadowRodata; | ||
| 2150 | } | ||
| 2151 | |||
| 2152 | static int dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size, | ||
| 2153 | void *data) { | ||
| 2154 | dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data; | ||
| 2155 | // dlopen/dlclose allocate/free dynamic-linker-internal memory, which is later | ||
| 2156 | // accessible in dl_iterate_phdr callback. But we don't see synchronization | ||
| 2157 | // inside of dynamic linker, so we "unpoison" it here in order to not | ||
| 2158 | // produce false reports. Ignoring malloc/free in dlopen/dlclose is not enough | ||
| 2159 | // because some libc functions call __libc_dlopen. | ||
| 2160 | if (info && IsAppNotRodata((uptr)info->dlpi_name)) | ||
| 2161 | MemoryResetRange(cbdata->thr, cbdata->pc, (uptr)info->dlpi_name, | ||
| 2162 | internal_strlen(info->dlpi_name)); | ||
| 2163 | int res = cbdata->cb(info, size, cbdata->data); | ||
| 2164 | // Perform the check one more time in case info->dlpi_name was overwritten | ||
| 2165 | // by user callback. | ||
| 2166 | if (info && IsAppNotRodata((uptr)info->dlpi_name)) | ||
| 2167 | MemoryResetRange(cbdata->thr, cbdata->pc, (uptr)info->dlpi_name, | ||
| 2168 | internal_strlen(info->dlpi_name)); | ||
| 2169 | return res; | ||
| 2170 | } | ||
| 2171 | |||
| 2172 | TSAN_INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb_t cb, void *data) { | ||
| 2173 | SCOPED_TSAN_INTERCEPTOR(dl_iterate_phdr, cb, data); | ||
| 2174 | dl_iterate_phdr_data cbdata; | ||
| 2175 | cbdata.thr = thr; | ||
| 2176 | cbdata.pc = pc; | ||
| 2177 | cbdata.cb = cb; | ||
| 2178 | cbdata.data = data; | ||
| 2179 | int res = REAL(dl_iterate_phdr)(dl_iterate_phdr_cb, &cbdata); | ||
| 2180 | return res; | ||
| 2181 | } | ||
| 2182 | #endif | ||
| 2183 | |||
| 2184 | static int OnExit(ThreadState *thr) { | ||
| 2185 | int status = Finalize(thr); | ||
| 2186 | FlushStreams(); | ||
| 2187 | return status; | ||
| 2188 | } | ||
| 2189 | |||
| 2190 | struct TsanInterceptorContext { | ||
| 2191 | ThreadState *thr; | ||
| 2192 | const uptr caller_pc; | ||
| 2193 | const uptr pc; | ||
| 2194 | }; | ||
| 2195 | |||
| 2196 | #if !SANITIZER_MAC | ||
| 2197 | static void HandleRecvmsg(ThreadState *thr, uptr pc, | ||
| 2198 | __sanitizer_msghdr *msg) { | ||
| 2199 | int fds[64]; | ||
| 2200 | int cnt = ExtractRecvmsgFDs(msg, fds, ARRAY_SIZE(fds)); | ||
| 2201 | for (int i = 0; i < cnt; i++) | ||
| 2202 | FdEventCreate(thr, pc, fds[i]); | ||
| 2203 | } | ||
| 2204 | #endif | ||
| 2205 | |||
| 2206 | #include "sanitizer_common/sanitizer_platform_interceptors.h" | ||
| 2207 | // Causes interceptor recursion (getaddrinfo() and fopen()) | ||
| 2208 | #undef SANITIZER_INTERCEPT_GETADDRINFO | ||
| 2209 | // We define our own. | ||
| 2210 | #if SANITIZER_INTERCEPT_TLS_GET_ADDR | ||
| 2211 | #define NEED_TLS_GET_ADDR | ||
| 2212 | #endif | ||
| 2213 | #undef SANITIZER_INTERCEPT_TLS_GET_ADDR | ||
| 2214 | #undef SANITIZER_INTERCEPT_PTHREAD_SIGMASK | ||
| 2215 | |||
| 2216 | #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) | ||
| 2217 | #define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ | ||
| 2218 | INTERCEPT_FUNCTION_VER(name, ver) | ||
| 2219 | |||
| 2220 | #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ | ||
| 2221 | MemoryAccessRange(((TsanInterceptorContext *)ctx)->thr, \ | ||
| 2222 | ((TsanInterceptorContext *)ctx)->pc, (uptr)ptr, size, \ | ||
| 2223 | true) | ||
| 2224 | |||
| 2225 | #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ | ||
| 2226 | MemoryAccessRange(((TsanInterceptorContext *) ctx)->thr, \ | ||
| 2227 | ((TsanInterceptorContext *) ctx)->pc, (uptr) ptr, size, \ | ||
| 2228 | false) | ||
| 2229 | |||
| 2230 | #define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ | ||
| 2231 | SCOPED_TSAN_INTERCEPTOR(func, __VA_ARGS__); \ | ||
| 2232 | TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \ | ||
| 2233 | ctx = (void *)&_ctx; \ | ||
| 2234 | (void) ctx; | ||
| 2235 | |||
| 2236 | #define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, func, ...) \ | ||
| 2237 | SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \ | ||
| 2238 | TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \ | ||
| 2239 | ctx = (void *)&_ctx; \ | ||
| 2240 | (void) ctx; | ||
| 2241 | |||
| 2242 | #define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) \ | ||
| 2243 | if (path) \ | ||
| 2244 | Acquire(thr, pc, File2addr(path)); \ | ||
| 2245 | if (file) { \ | ||
| 2246 | int fd = fileno_unlocked(file); \ | ||
| 2247 | if (fd >= 0) FdFileCreate(thr, pc, fd); \ | ||
| 2248 | } | ||
| 2249 | |||
| 2250 | #define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) \ | ||
| 2251 | if (file) { \ | ||
| 2252 | int fd = fileno_unlocked(file); \ | ||
| 2253 | if (fd >= 0) FdClose(thr, pc, fd); \ | ||
| 2254 | } | ||
| 2255 | |||
| 2256 | #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ | ||
| 2257 | libignore()->OnLibraryLoaded(filename) | ||
| 2258 | |||
| 2259 | #define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() \ | ||
| 2260 | libignore()->OnLibraryUnloaded() | ||
| 2261 | |||
| 2262 | #define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) \ | ||
| 2263 | Acquire(((TsanInterceptorContext *) ctx)->thr, pc, u) | ||
| 2264 | |||
| 2265 | #define COMMON_INTERCEPTOR_RELEASE(ctx, u) \ | ||
| 2266 | Release(((TsanInterceptorContext *) ctx)->thr, pc, u) | ||
| 2267 | |||
| 2268 | #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ | ||
| 2269 | Acquire(((TsanInterceptorContext *) ctx)->thr, pc, Dir2addr(path)) | ||
| 2270 | |||
| 2271 | #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ | ||
| 2272 | FdAcquire(((TsanInterceptorContext *) ctx)->thr, pc, fd) | ||
| 2273 | |||
| 2274 | #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ | ||
| 2275 | FdRelease(((TsanInterceptorContext *) ctx)->thr, pc, fd) | ||
| 2276 | |||
| 2277 | #define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) \ | ||
| 2278 | FdAccess(((TsanInterceptorContext *) ctx)->thr, pc, fd) | ||
| 2279 | |||
| 2280 | #define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ | ||
| 2281 | FdSocketAccept(((TsanInterceptorContext *) ctx)->thr, pc, fd, newfd) | ||
| 2282 | |||
| 2283 | #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \ | ||
| 2284 | ThreadSetName(((TsanInterceptorContext *) ctx)->thr, name) | ||
| 2285 | |||
| 2286 | #define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ | ||
| 2287 | __tsan::ctx->thread_registry->SetThreadNameByUserId(thread, name) | ||
| 2288 | |||
| 2289 | #define COMMON_INTERCEPTOR_BLOCK_REAL(name) BLOCK_REAL(name) | ||
| 2290 | |||
| 2291 | #define COMMON_INTERCEPTOR_ON_EXIT(ctx) \ | ||
| 2292 | OnExit(((TsanInterceptorContext *) ctx)->thr) | ||
| 2293 | |||
| 2294 | #define COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m) \ | ||
| 2295 | MutexPreLock(((TsanInterceptorContext *)ctx)->thr, \ | ||
| 2296 | ((TsanInterceptorContext *)ctx)->pc, (uptr)m) | ||
| 2297 | |||
| 2298 | #define COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m) \ | ||
| 2299 | MutexPostLock(((TsanInterceptorContext *)ctx)->thr, \ | ||
| 2300 | ((TsanInterceptorContext *)ctx)->pc, (uptr)m) | ||
| 2301 | |||
| 2302 | #define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) \ | ||
| 2303 | MutexUnlock(((TsanInterceptorContext *)ctx)->thr, \ | ||
| 2304 | ((TsanInterceptorContext *)ctx)->pc, (uptr)m) | ||
| 2305 | |||
| 2306 | #define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) \ | ||
| 2307 | MutexRepair(((TsanInterceptorContext *)ctx)->thr, \ | ||
| 2308 | ((TsanInterceptorContext *)ctx)->pc, (uptr)m) | ||
| 2309 | |||
| 2310 | #define COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m) \ | ||
| 2311 | MutexInvalidAccess(((TsanInterceptorContext *)ctx)->thr, \ | ||
| 2312 | ((TsanInterceptorContext *)ctx)->pc, (uptr)m) | ||
| 2313 | |||
| 2314 | #define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd, \ | ||
| 2315 | off) \ | ||
| 2316 | do { \ | ||
| 2317 | return mmap_interceptor(thr, pc, REAL(mmap), addr, sz, prot, flags, fd, \ | ||
| 2318 | off); \ | ||
| 2319 | } while (false) | ||
| 2320 | |||
| 2321 | #if !SANITIZER_MAC | ||
| 2322 | #define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \ | ||
| 2323 | HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \ | ||
| 2324 | ((TsanInterceptorContext *)ctx)->pc, msg) | ||
| 2325 | #endif | ||
| 2326 | |||
| 2327 | #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ | ||
| 2328 | if (TsanThread *t = GetCurrentThread()) { \ | ||
| 2329 | *begin = t->tls_begin(); \ | ||
| 2330 | *end = t->tls_end(); \ | ||
| 2331 | } else { \ | ||
| 2332 | *begin = *end = 0; \ | ||
| 2333 | } | ||
| 2334 | |||
| 2335 | #define COMMON_INTERCEPTOR_USER_CALLBACK_START() \ | ||
| 2336 | SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START() | ||
| 2337 | |||
| 2338 | #define COMMON_INTERCEPTOR_USER_CALLBACK_END() \ | ||
| 2339 | SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END() | ||
| 2340 | |||
| 2341 | #include "sanitizer_common/sanitizer_common_interceptors.inc" | ||
| 2342 | |||
| 2343 | static int sigaction_impl(int sig, const __sanitizer_sigaction *act, | ||
| 2344 | __sanitizer_sigaction *old); | ||
| 2345 | static __sanitizer_sighandler_ptr signal_impl(int sig, | ||
| 2346 | __sanitizer_sighandler_ptr h); | ||
| 2347 | |||
| 2348 | #define SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signo, act, oldact) \ | ||
| 2349 | { return sigaction_impl(signo, act, oldact); } | ||
| 2350 | |||
| 2351 | #define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signo, handler) \ | ||
| 2352 | { return (uptr)signal_impl(signo, (__sanitizer_sighandler_ptr)handler); } | ||
| 2353 | |||
| 2354 | #include "sanitizer_common/sanitizer_signal_interceptors.inc" | ||
| 2355 | |||
| 2356 | int sigaction_impl(int sig, const __sanitizer_sigaction *act, | ||
| 2357 | __sanitizer_sigaction *old) { | ||
| 2358 | // Note: if we call REAL(sigaction) directly for any reason without proxying | ||
| 2359 | // the signal handler through rtl_sigaction, very bad things will happen. | ||
| 2360 | // The handler will run synchronously and corrupt tsan per-thread state. | ||
| 2361 | SCOPED_INTERCEPTOR_RAW(sigaction, sig, act, old); | ||
| 2362 | __sanitizer_sigaction *sigactions = interceptor_ctx()->sigactions; | ||
| 2363 | __sanitizer_sigaction old_stored; | ||
| 2364 | if (old) internal_memcpy(&old_stored, &sigactions[sig], sizeof(old_stored)); | ||
| 2365 | __sanitizer_sigaction newact; | ||
| 2366 | if (act) { | ||
| 2367 | // Copy act into sigactions[sig]. | ||
| 2368 | // Can't use struct copy, because compiler can emit call to memcpy. | ||
| 2369 | // Can't use internal_memcpy, because it copies byte-by-byte, | ||
| 2370 | // and signal handler reads the handler concurrently. It it can read | ||
| 2371 | // some bytes from old value and some bytes from new value. | ||
| 2372 | // Use volatile to prevent insertion of memcpy. | ||
| 2373 | sigactions[sig].handler = | ||
| 2374 | *(volatile __sanitizer_sighandler_ptr const *)&act->handler; | ||
| 2375 | sigactions[sig].sa_flags = *(volatile int const *)&act->sa_flags; | ||
| 2376 | internal_memcpy(&sigactions[sig].sa_mask, &act->sa_mask, | ||
| 2377 | sizeof(sigactions[sig].sa_mask)); | ||
| 2378 | #if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD | ||
| 2379 | sigactions[sig].sa_restorer = act->sa_restorer; | ||
| 2380 | #endif | ||
| 2381 | internal_memcpy(&newact, act, sizeof(newact)); | ||
| 2382 | internal_sigfillset(&newact.sa_mask); | ||
| 2383 | if ((uptr)act->handler != sig_ign && (uptr)act->handler != sig_dfl) { | ||
| 2384 | if (newact.sa_flags & SA_SIGINFO) | ||
| 2385 | newact.sigaction = rtl_sigaction; | ||
| 2386 | else | ||
| 2387 | newact.handler = rtl_sighandler; | ||
| 2388 | } | ||
| 2389 | ReleaseStore(thr, pc, (uptr)&sigactions[sig]); | ||
| 2390 | act = &newact; | ||
| 2391 | } | ||
| 2392 | int res = REAL(sigaction)(sig, act, old); | ||
| 2393 | if (res == 0 && old) { | ||
| 2394 | uptr cb = (uptr)old->sigaction; | ||
| 2395 | if (cb == (uptr)rtl_sigaction || cb == (uptr)rtl_sighandler) { | ||
| 2396 | internal_memcpy(old, &old_stored, sizeof(*old)); | ||
| 2397 | } | ||
| 2398 | } | ||
| 2399 | return res; | ||
| 2400 | } | ||
| 2401 | |||
| 2402 | static __sanitizer_sighandler_ptr signal_impl(int sig, | ||
| 2403 | __sanitizer_sighandler_ptr h) { | ||
| 2404 | __sanitizer_sigaction act; | ||
| 2405 | act.handler = h; | ||
| 2406 | internal_memset(&act.sa_mask, -1, sizeof(act.sa_mask)); | ||
| 2407 | act.sa_flags = 0; | ||
| 2408 | __sanitizer_sigaction old; | ||
| 2409 | int res = sigaction_symname(sig, &act, &old); | ||
| 2410 | if (res) return (__sanitizer_sighandler_ptr)sig_err; | ||
| 2411 | return old.handler; | ||
| 2412 | } | ||
| 2413 | |||
| 2414 | #define TSAN_SYSCALL() \ | ||
| 2415 | ThreadState *thr = cur_thread(); \ | ||
| 2416 | if (thr->ignore_interceptors) \ | ||
| 2417 | return; \ | ||
| 2418 | ScopedSyscall scoped_syscall(thr) \ | ||
| 2419 | /**/ | ||
| 2420 | |||
| 2421 | struct ScopedSyscall { | ||
| 2422 | ThreadState *thr; | ||
| 2423 | |||
| 2424 | explicit ScopedSyscall(ThreadState *thr) | ||
| 2425 | : thr(thr) { | ||
| 2426 | Initialize(thr); | ||
| 2427 | } | ||
| 2428 | |||
| 2429 | ~ScopedSyscall() { | ||
| 2430 | ProcessPendingSignals(thr); | ||
| 2431 | } | ||
| 2432 | }; | ||
| 2433 | |||
| 2434 | #if !SANITIZER_FREEBSD && !SANITIZER_MAC | ||
| 2435 | static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) { | ||
| 2436 | TSAN_SYSCALL(); | ||
| 2437 | MemoryAccessRange(thr, pc, p, s, write); | ||
| 2438 | } | ||
| 2439 | |||
| 2440 | static void syscall_acquire(uptr pc, uptr addr) { | ||
| 2441 | TSAN_SYSCALL(); | ||
| 2442 | Acquire(thr, pc, addr); | ||
| 2443 | DPrintf("syscall_acquire(%p)\n", addr); | ||
| 2444 | } | ||
| 2445 | |||
| 2446 | static void syscall_release(uptr pc, uptr addr) { | ||
| 2447 | TSAN_SYSCALL(); | ||
| 2448 | DPrintf("syscall_release(%p)\n", addr); | ||
| 2449 | Release(thr, pc, addr); | ||
| 2450 | } | ||
| 2451 | |||
| 2452 | static void syscall_fd_close(uptr pc, int fd) { | ||
| 2453 | TSAN_SYSCALL(); | ||
| 2454 | FdClose(thr, pc, fd); | ||
| 2455 | } | ||
| 2456 | |||
| 2457 | static USED void syscall_fd_acquire(uptr pc, int fd) { | ||
| 2458 | TSAN_SYSCALL(); | ||
| 2459 | FdAcquire(thr, pc, fd); | ||
| 2460 | DPrintf("syscall_fd_acquire(%p)\n", fd); | ||
| 2461 | } | ||
| 2462 | |||
| 2463 | static USED void syscall_fd_release(uptr pc, int fd) { | ||
| 2464 | TSAN_SYSCALL(); | ||
| 2465 | DPrintf("syscall_fd_release(%p)\n", fd); | ||
| 2466 | FdRelease(thr, pc, fd); | ||
| 2467 | } | ||
| 2468 | |||
| 2469 | static void syscall_pre_fork(uptr pc) { | ||
| 2470 | TSAN_SYSCALL(); | ||
| 2471 | ForkBefore(thr, pc); | ||
| 2472 | } | ||
| 2473 | |||
| 2474 | static void syscall_post_fork(uptr pc, int pid) { | ||
| 2475 | TSAN_SYSCALL(); | ||
| 2476 | if (pid == 0) { | ||
| 2477 | // child | ||
| 2478 | ForkChildAfter(thr, pc); | ||
| 2479 | FdOnFork(thr, pc); | ||
| 2480 | } else if (pid > 0) { | ||
| 2481 | // parent | ||
| 2482 | ForkParentAfter(thr, pc); | ||
| 2483 | } else { | ||
| 2484 | // error | ||
| 2485 | ForkParentAfter(thr, pc); | ||
| 2486 | } | ||
| 2487 | } | ||
| 2488 | #endif | ||
| 2489 | |||
| 2490 | #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) \ | ||
| 2491 | syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), false) | ||
| 2492 | |||
| 2493 | #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \ | ||
| 2494 | syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), true) | ||
| 2495 | |||
| 2496 | #define COMMON_SYSCALL_POST_READ_RANGE(p, s) \ | ||
| 2497 | do { \ | ||
| 2498 | (void)(p); \ | ||
| 2499 | (void)(s); \ | ||
| 2500 | } while (false) | ||
| 2501 | |||
| 2502 | #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \ | ||
| 2503 | do { \ | ||
| 2504 | (void)(p); \ | ||
| 2505 | (void)(s); \ | ||
| 2506 | } while (false) | ||
| 2507 | |||
| 2508 | #define COMMON_SYSCALL_ACQUIRE(addr) \ | ||
| 2509 | syscall_acquire(GET_CALLER_PC(), (uptr)(addr)) | ||
| 2510 | |||
| 2511 | #define COMMON_SYSCALL_RELEASE(addr) \ | ||
| 2512 | syscall_release(GET_CALLER_PC(), (uptr)(addr)) | ||
| 2513 | |||
| 2514 | #define COMMON_SYSCALL_FD_CLOSE(fd) syscall_fd_close(GET_CALLER_PC(), fd) | ||
| 2515 | |||
| 2516 | #define COMMON_SYSCALL_FD_ACQUIRE(fd) syscall_fd_acquire(GET_CALLER_PC(), fd) | ||
| 2517 | |||
| 2518 | #define COMMON_SYSCALL_FD_RELEASE(fd) syscall_fd_release(GET_CALLER_PC(), fd) | ||
| 2519 | |||
| 2520 | #define COMMON_SYSCALL_PRE_FORK() \ | ||
| 2521 | syscall_pre_fork(GET_CALLER_PC()) | ||
| 2522 | |||
| 2523 | #define COMMON_SYSCALL_POST_FORK(res) \ | ||
| 2524 | syscall_post_fork(GET_CALLER_PC(), res) | ||
| 2525 | |||
| 2526 | #include "sanitizer_common/sanitizer_common_syscalls.inc" | ||
| 2527 | #include "sanitizer_common/sanitizer_syscalls_netbsd.inc" | ||
| 2528 | |||
| 2529 | #ifdef NEED_TLS_GET_ADDR | ||
| 2530 | // Define own interceptor instead of sanitizer_common's for three reasons: | ||
| 2531 | // 1. It must not process pending signals. | ||
| 2532 | // Signal handlers may contain MOVDQA instruction (see below). | ||
| 2533 | // 2. It must be as simple as possible to not contain MOVDQA. | ||
| 2534 | // 3. Sanitizer_common version uses COMMON_INTERCEPTOR_INITIALIZE_RANGE which | ||
| 2535 | // is empty for tsan (meant only for msan). | ||
| 2536 | // Note: __tls_get_addr can be called with mis-aligned stack due to: | ||
| 2537 | // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066 | ||
| 2538 | // So the interceptor must work with mis-aligned stack, in particular, does not | ||
| 2539 | // execute MOVDQA with stack addresses. | ||
| 2540 | TSAN_INTERCEPTOR(void *, __tls_get_addr, void *arg) { | ||
| 2541 | void *res = REAL(__tls_get_addr)(arg); | ||
| 2542 | ThreadState *thr = cur_thread(); | ||
| 2543 | if (!thr) | ||
| 2544 | return res; | ||
| 2545 | DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, thr->tls_addr, | ||
| 2546 | thr->tls_addr + thr->tls_size); | ||
| 2547 | if (!dtv) | ||
| 2548 | return res; | ||
| 2549 | // New DTLS block has been allocated. | ||
| 2550 | MemoryResetRange(thr, 0, dtv->beg, dtv->size); | ||
| 2551 | return res; | ||
| 2552 | } | ||
| 2553 | #endif | ||
| 2554 | |||
| 2555 | #if SANITIZER_NETBSD | ||
| 2556 | TSAN_INTERCEPTOR(void, _lwp_exit) { | ||
| 2557 | SCOPED_TSAN_INTERCEPTOR(_lwp_exit); | ||
| 2558 | DestroyThreadState(); | ||
| 2559 | REAL(_lwp_exit)(); | ||
| 2560 | } | ||
| 2561 | #define TSAN_MAYBE_INTERCEPT__LWP_EXIT TSAN_INTERCEPT(_lwp_exit) | ||
| 2562 | #else | ||
| 2563 | #define TSAN_MAYBE_INTERCEPT__LWP_EXIT | ||
| 2564 | #endif | ||
| 2565 | |||
| 2566 | #if SANITIZER_FREEBSD | ||
| 2567 | TSAN_INTERCEPTOR(void, thr_exit, tid_t *state) { | ||
| 2568 | SCOPED_TSAN_INTERCEPTOR(thr_exit, state); | ||
| 2569 | DestroyThreadState(); | ||
| 2570 | REAL(thr_exit(state)); | ||
| 2571 | } | ||
| 2572 | #define TSAN_MAYBE_INTERCEPT_THR_EXIT TSAN_INTERCEPT(thr_exit) | ||
| 2573 | #else | ||
| 2574 | #define TSAN_MAYBE_INTERCEPT_THR_EXIT | ||
| 2575 | #endif | ||
| 2576 | |||
| 2577 | TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_init, void *c, void *a) | ||
| 2578 | TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_signal, void *c) | ||
| 2579 | TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_broadcast, void *c) | ||
| 2580 | TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_wait, void *c, void *m) | ||
| 2581 | TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_destroy, void *c) | ||
| 2582 | TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_init, void *m, void *a) | ||
| 2583 | TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_destroy, void *m) | ||
| 2584 | TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_trylock, void *m) | ||
| 2585 | TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_init, void *m, void *a) | ||
| 2586 | TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_destroy, void *m) | ||
| 2587 | TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_rdlock, void *m) | ||
| 2588 | TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_tryrdlock, void *m) | ||
| 2589 | TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_wrlock, void *m) | ||
| 2590 | TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_trywrlock, void *m) | ||
| 2591 | TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_unlock, void *m) | ||
| 2592 | TSAN_INTERCEPTOR_NETBSD_ALIAS_THR(int, once, void *o, void (*f)()) | ||
| 2593 | TSAN_INTERCEPTOR_NETBSD_ALIAS_THR2(int, sigsetmask, sigmask, int a, void *b, | ||
| 2594 | void *c) | ||
| 2595 | |||
| 2596 | namespace __tsan { | ||
| 2597 | |||
| 2598 | static void finalize(void *arg) { | ||
| 2599 | ThreadState *thr = cur_thread(); | ||
| 2600 | int status = Finalize(thr); | ||
| 2601 | // Make sure the output is not lost. | ||
| 2602 | FlushStreams(); | ||
| 2603 | if (status) | ||
| 2604 | Die(); | ||
| 2605 | } | ||
| 2606 | |||
| 2607 | #if !SANITIZER_MAC && !SANITIZER_ANDROID | ||
| 2608 | static void unreachable() { | ||
| 2609 | Report("FATAL: ThreadSanitizer: unreachable called\n"); | ||
| 2610 | Die(); | ||
| 2611 | } | ||
| 2612 | #endif | ||
| 2613 | |||
| 2614 | // Define default implementation since interception of libdispatch is optional. | ||
| 2615 | SANITIZER_WEAK_ATTRIBUTE void InitializeLibdispatchInterceptors() {} | ||
| 2616 | |||
| 2617 | void InitializeInterceptors() { | ||
| 2618 | #if !SANITIZER_MAC | ||
| 2619 | // We need to setup it early, because functions like dlsym() can call it. | ||
| 2620 | REAL(memset) = internal_memset; | ||
| 2621 | REAL(memcpy) = internal_memcpy; | ||
| 2622 | #endif | ||
| 2623 | |||
| 2624 | // Instruct libc malloc to consume less memory. | ||
| 2625 | #if SANITIZER_LINUX | ||
| 2626 | mallopt(1, 0); // M_MXFAST | ||
| 2627 | mallopt(-3, 32*1024); // M_MMAP_THRESHOLD | ||
| 2628 | #endif | ||
| 2629 | |||
| 2630 | new(interceptor_ctx()) InterceptorContext(); | ||
| 2631 | |||
| 2632 | InitializeCommonInterceptors(); | ||
| 2633 | InitializeSignalInterceptors(); | ||
| 2634 | InitializeLibdispatchInterceptors(); | ||
| 2635 | |||
| 2636 | #if !SANITIZER_MAC | ||
| 2637 | // We can not use TSAN_INTERCEPT to get setjmp addr, | ||
| 2638 | // because it does &setjmp and setjmp is not present in some versions of libc. | ||
| 2639 | using __interception::InterceptFunction; | ||
| 2640 | InterceptFunction(TSAN_STRING_SETJMP, (uptr*)&REAL(setjmp_symname), 0, 0); | ||
| 2641 | InterceptFunction("_setjmp", (uptr*)&REAL(_setjmp), 0, 0); | ||
| 2642 | InterceptFunction(TSAN_STRING_SIGSETJMP, (uptr*)&REAL(sigsetjmp_symname), 0, | ||
| 2643 | 0); | ||
| 2644 | #if !SANITIZER_NETBSD | ||
| 2645 | InterceptFunction("__sigsetjmp", (uptr*)&REAL(__sigsetjmp), 0, 0); | ||
| 2646 | #endif | ||
| 2647 | #endif | ||
| 2648 | |||
| 2649 | TSAN_INTERCEPT(longjmp_symname); | ||
| 2650 | TSAN_INTERCEPT(siglongjmp_symname); | ||
| 2651 | #if SANITIZER_NETBSD | ||
| 2652 | TSAN_INTERCEPT(_longjmp); | ||
| 2653 | #endif | ||
| 2654 | |||
| 2655 | TSAN_INTERCEPT(malloc); | ||
| 2656 | TSAN_INTERCEPT(__libc_memalign); | ||
| 2657 | TSAN_INTERCEPT(calloc); | ||
| 2658 | TSAN_INTERCEPT(realloc); | ||
| 2659 | TSAN_INTERCEPT(reallocarray); | ||
| 2660 | TSAN_INTERCEPT(free); | ||
| 2661 | TSAN_INTERCEPT(cfree); | ||
| 2662 | TSAN_INTERCEPT(munmap); | ||
| 2663 | TSAN_MAYBE_INTERCEPT_MEMALIGN; | ||
| 2664 | TSAN_INTERCEPT(valloc); | ||
| 2665 | TSAN_MAYBE_INTERCEPT_PVALLOC; | ||
| 2666 | TSAN_INTERCEPT(posix_memalign); | ||
| 2667 | |||
| 2668 | TSAN_INTERCEPT(strcpy); | ||
| 2669 | TSAN_INTERCEPT(strncpy); | ||
| 2670 | TSAN_INTERCEPT(strdup); | ||
| 2671 | |||
| 2672 | TSAN_INTERCEPT(pthread_create); | ||
| 2673 | TSAN_INTERCEPT(pthread_join); | ||
| 2674 | TSAN_INTERCEPT(pthread_detach); | ||
| 2675 | TSAN_INTERCEPT(pthread_exit); | ||
| 2676 | #if SANITIZER_LINUX | ||
| 2677 | TSAN_INTERCEPT(pthread_tryjoin_np); | ||
| 2678 | TSAN_INTERCEPT(pthread_timedjoin_np); | ||
| 2679 | #endif | ||
| 2680 | |||
| 2681 | TSAN_INTERCEPT_VER(pthread_cond_init, PTHREAD_ABI_BASE); | ||
| 2682 | TSAN_INTERCEPT_VER(pthread_cond_signal, PTHREAD_ABI_BASE); | ||
| 2683 | TSAN_INTERCEPT_VER(pthread_cond_broadcast, PTHREAD_ABI_BASE); | ||
| 2684 | TSAN_INTERCEPT_VER(pthread_cond_wait, PTHREAD_ABI_BASE); | ||
| 2685 | TSAN_INTERCEPT_VER(pthread_cond_timedwait, PTHREAD_ABI_BASE); | ||
| 2686 | TSAN_INTERCEPT_VER(pthread_cond_destroy, PTHREAD_ABI_BASE); | ||
| 2687 | |||
| 2688 | TSAN_INTERCEPT(pthread_mutex_init); | ||
| 2689 | TSAN_INTERCEPT(pthread_mutex_destroy); | ||
| 2690 | TSAN_INTERCEPT(pthread_mutex_trylock); | ||
| 2691 | TSAN_INTERCEPT(pthread_mutex_timedlock); | ||
| 2692 | |||
| 2693 | TSAN_INTERCEPT(pthread_spin_init); | ||
| 2694 | TSAN_INTERCEPT(pthread_spin_destroy); | ||
| 2695 | TSAN_INTERCEPT(pthread_spin_lock); | ||
| 2696 | TSAN_INTERCEPT(pthread_spin_trylock); | ||
| 2697 | TSAN_INTERCEPT(pthread_spin_unlock); | ||
| 2698 | |||
| 2699 | TSAN_INTERCEPT(pthread_rwlock_init); | ||
| 2700 | TSAN_INTERCEPT(pthread_rwlock_destroy); | ||
| 2701 | TSAN_INTERCEPT(pthread_rwlock_rdlock); | ||
| 2702 | TSAN_INTERCEPT(pthread_rwlock_tryrdlock); | ||
| 2703 | TSAN_INTERCEPT(pthread_rwlock_timedrdlock); | ||
| 2704 | TSAN_INTERCEPT(pthread_rwlock_wrlock); | ||
| 2705 | TSAN_INTERCEPT(pthread_rwlock_trywrlock); | ||
| 2706 | TSAN_INTERCEPT(pthread_rwlock_timedwrlock); | ||
| 2707 | TSAN_INTERCEPT(pthread_rwlock_unlock); | ||
| 2708 | |||
| 2709 | TSAN_INTERCEPT(pthread_barrier_init); | ||
| 2710 | TSAN_INTERCEPT(pthread_barrier_destroy); | ||
| 2711 | TSAN_INTERCEPT(pthread_barrier_wait); | ||
| 2712 | |||
| 2713 | TSAN_INTERCEPT(pthread_once); | ||
| 2714 | |||
| 2715 | TSAN_INTERCEPT(fstat); | ||
| 2716 | TSAN_MAYBE_INTERCEPT___FXSTAT; | ||
| 2717 | TSAN_MAYBE_INTERCEPT_FSTAT64; | ||
| 2718 | TSAN_MAYBE_INTERCEPT___FXSTAT64; | ||
| 2719 | TSAN_INTERCEPT(open); | ||
| 2720 | TSAN_MAYBE_INTERCEPT_OPEN64; | ||
| 2721 | TSAN_INTERCEPT(creat); | ||
| 2722 | TSAN_MAYBE_INTERCEPT_CREAT64; | ||
| 2723 | TSAN_INTERCEPT(dup); | ||
| 2724 | TSAN_INTERCEPT(dup2); | ||
| 2725 | TSAN_INTERCEPT(dup3); | ||
| 2726 | TSAN_MAYBE_INTERCEPT_EVENTFD; | ||
| 2727 | TSAN_MAYBE_INTERCEPT_SIGNALFD; | ||
| 2728 | TSAN_MAYBE_INTERCEPT_INOTIFY_INIT; | ||
| 2729 | TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1; | ||
| 2730 | TSAN_INTERCEPT(socket); | ||
| 2731 | TSAN_INTERCEPT(socketpair); | ||
| 2732 | TSAN_INTERCEPT(connect); | ||
| 2733 | TSAN_INTERCEPT(bind); | ||
| 2734 | TSAN_INTERCEPT(listen); | ||
| 2735 | TSAN_MAYBE_INTERCEPT_EPOLL; | ||
| 2736 | TSAN_INTERCEPT(close); | ||
| 2737 | TSAN_MAYBE_INTERCEPT___CLOSE; | ||
| 2738 | TSAN_MAYBE_INTERCEPT___RES_ICLOSE; | ||
| 2739 | TSAN_INTERCEPT(pipe); | ||
| 2740 | TSAN_INTERCEPT(pipe2); | ||
| 2741 | |||
| 2742 | TSAN_INTERCEPT(unlink); | ||
| 2743 | TSAN_INTERCEPT(tmpfile); | ||
| 2744 | TSAN_MAYBE_INTERCEPT_TMPFILE64; | ||
| 2745 | TSAN_INTERCEPT(abort); | ||
| 2746 | TSAN_INTERCEPT(rmdir); | ||
| 2747 | TSAN_INTERCEPT(closedir); | ||
| 2748 | |||
| 2749 | TSAN_INTERCEPT(sigsuspend); | ||
| 2750 | TSAN_INTERCEPT(sigblock); | ||
| 2751 | TSAN_INTERCEPT(sigsetmask); | ||
| 2752 | TSAN_INTERCEPT(pthread_sigmask); | ||
| 2753 | TSAN_INTERCEPT(raise); | ||
| 2754 | TSAN_INTERCEPT(kill); | ||
| 2755 | TSAN_INTERCEPT(pthread_kill); | ||
| 2756 | TSAN_INTERCEPT(sleep); | ||
| 2757 | TSAN_INTERCEPT(usleep); | ||
| 2758 | TSAN_INTERCEPT(nanosleep); | ||
| 2759 | TSAN_INTERCEPT(pause); | ||
| 2760 | TSAN_INTERCEPT(gettimeofday); | ||
| 2761 | TSAN_INTERCEPT(getaddrinfo); | ||
| 2762 | |||
| 2763 | TSAN_INTERCEPT(fork); | ||
| 2764 | TSAN_INTERCEPT(vfork); | ||
| 2765 | #if !SANITIZER_ANDROID | ||
| 2766 | TSAN_INTERCEPT(dl_iterate_phdr); | ||
| 2767 | #endif | ||
| 2768 | TSAN_MAYBE_INTERCEPT_ON_EXIT; | ||
| 2769 | TSAN_INTERCEPT(__cxa_atexit); | ||
| 2770 | TSAN_INTERCEPT(_exit); | ||
| 2771 | |||
| 2772 | #ifdef NEED_TLS_GET_ADDR | ||
| 2773 | TSAN_INTERCEPT(__tls_get_addr); | ||
| 2774 | #endif | ||
| 2775 | |||
| 2776 | TSAN_MAYBE_INTERCEPT__LWP_EXIT; | ||
| 2777 | TSAN_MAYBE_INTERCEPT_THR_EXIT; | ||
| 2778 | |||
| 2779 | #if !SANITIZER_MAC && !SANITIZER_ANDROID | ||
| 2780 | // Need to setup it, because interceptors check that the function is resolved. | ||
| 2781 | // But atexit is emitted directly into the module, so can't be resolved. | ||
| 2782 | REAL(atexit) = (int(*)(void(*)()))unreachable; | ||
| 2783 | #endif | ||
| 2784 | |||
| 2785 | if (REAL(__cxa_atexit)(&finalize, 0, 0)) { | ||
| 2786 | Printf("ThreadSanitizer: failed to setup atexit callback\n"); | ||
| 2787 | Die(); | ||
| 2788 | } | ||
| 2789 | |||
| 2790 | #if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD | ||
| 2791 | if (pthread_key_create(&interceptor_ctx()->finalize_key, &thread_finalize)) { | ||
| 2792 | Printf("ThreadSanitizer: failed to create thread key\n"); | ||
| 2793 | Die(); | ||
| 2794 | } | ||
| 2795 | #endif | ||
| 2796 | |||
| 2797 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_init); | ||
| 2798 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_signal); | ||
| 2799 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_broadcast); | ||
| 2800 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_wait); | ||
| 2801 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_destroy); | ||
| 2802 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_init); | ||
| 2803 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_destroy); | ||
| 2804 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_trylock); | ||
| 2805 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_init); | ||
| 2806 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_destroy); | ||
| 2807 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_rdlock); | ||
| 2808 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_tryrdlock); | ||
| 2809 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_wrlock); | ||
| 2810 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_trywrlock); | ||
| 2811 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_unlock); | ||
| 2812 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(once); | ||
| 2813 | TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(sigsetmask); | ||
| 2814 | |||
| 2815 | FdInit(); | ||
| 2816 | } | ||
| 2817 | |||
| 2818 | } // namespace __tsan | ||
| 2819 | |||
| 2820 | // Invisible barrier for tests. | ||
| 2821 | // There were several unsuccessful iterations for this functionality: | ||
| 2822 | // 1. Initially it was implemented in user code using | ||
| 2823 | // REAL(pthread_barrier_wait). But pthread_barrier_wait is not supported on | ||
| 2824 | // MacOS. Futexes are linux-specific for this matter. | ||
| 2825 | // 2. Then we switched to atomics+usleep(10). But usleep produced parasitic | ||
| 2826 | // "as-if synchronized via sleep" messages in reports which failed some | ||
| 2827 | // output tests. | ||
| 2828 | // 3. Then we switched to atomics+sched_yield. But this produced tons of tsan- | ||
| 2829 | // visible events, which lead to "failed to restore stack trace" failures. | ||
| 2830 | // Note that no_sanitize_thread attribute does not turn off atomic interception | ||
| 2831 | // so attaching it to the function defined in user code does not help. | ||
| 2832 | // That's why we now have what we have. | ||
| 2833 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE | ||
| 2834 | void __tsan_testonly_barrier_init(u64 *barrier, u32 count) { | ||
| 2835 | if (count >= (1 << 8)) { | ||
| 2836 | Printf("barrier_init: count is too large (%d)\n", count); | ||
| 2837 | Die(); | ||
| 2838 | } | ||
| 2839 | // 8 lsb is thread count, the remaining are count of entered threads. | ||
| 2840 | *barrier = count; | ||
| 2841 | } | ||
| 2842 | |||
| 2843 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE | ||
| 2844 | void __tsan_testonly_barrier_wait(u64 *barrier) { | ||
| 2845 | unsigned old = __atomic_fetch_add(barrier, 1 << 8, __ATOMIC_RELAXED); | ||
| 2846 | unsigned old_epoch = (old >> 8) / (old & 0xff); | ||
| 2847 | for (;;) { | ||
| 2848 | unsigned cur = __atomic_load_n(barrier, __ATOMIC_RELAXED); | ||
| 2849 | unsigned cur_epoch = (cur >> 8) / (cur & 0xff); | ||
| 2850 | if (cur_epoch != old_epoch) | ||
| 2851 | return; | ||
| 2852 | internal_sched_yield(); | ||
| 2853 | } | ||
| 2854 | } | ||
lib/tsan/tsan_interface.cpp created+160| ... | @@ -0,0 +1,160 @@ | ||
| 1 | //===-- tsan_interface.cpp ------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "tsan_interface.h" | ||
| 14 | #include "tsan_interface_ann.h" | ||
| 15 | #include "tsan_rtl.h" | ||
| 16 | #include "sanitizer_common/sanitizer_internal_defs.h" | ||
| 17 | |||
| 18 | #define CALLERPC ((uptr)__builtin_return_address(0)) | ||
| 19 | |||
| 20 | using namespace __tsan; | ||
| 21 | |||
| 22 | typedef u16 uint16_t; | ||
| 23 | typedef u32 uint32_t; | ||
| 24 | typedef u64 uint64_t; | ||
| 25 | |||
| 26 | void __tsan_init() { | ||
| 27 | cur_thread_init(); | ||
| 28 | Initialize(cur_thread()); | ||
| 29 | } | ||
| 30 | |||
| 31 | void __tsan_flush_memory() { | ||
| 32 | FlushShadowMemory(); | ||
| 33 | } | ||
| 34 | |||
| 35 | void __tsan_read16(void *addr) { | ||
| 36 | MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8); | ||
| 37 | MemoryRead(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8); | ||
| 38 | } | ||
| 39 | |||
| 40 | void __tsan_write16(void *addr) { | ||
| 41 | MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8); | ||
| 42 | MemoryWrite(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8); | ||
| 43 | } | ||
| 44 | |||
| 45 | void __tsan_read16_pc(void *addr, void *pc) { | ||
| 46 | MemoryRead(cur_thread(), (uptr)pc, (uptr)addr, kSizeLog8); | ||
| 47 | MemoryRead(cur_thread(), (uptr)pc, (uptr)addr + 8, kSizeLog8); | ||
| 48 | } | ||
| 49 | |||
| 50 | void __tsan_write16_pc(void *addr, void *pc) { | ||
| 51 | MemoryWrite(cur_thread(), (uptr)pc, (uptr)addr, kSizeLog8); | ||
| 52 | MemoryWrite(cur_thread(), (uptr)pc, (uptr)addr + 8, kSizeLog8); | ||
| 53 | } | ||
| 54 | |||
| 55 | // __tsan_unaligned_read/write calls are emitted by compiler. | ||
| 56 | |||
| 57 | void __tsan_unaligned_read2(const void *addr) { | ||
| 58 | UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, false, false); | ||
| 59 | } | ||
| 60 | |||
| 61 | void __tsan_unaligned_read4(const void *addr) { | ||
| 62 | UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 4, false, false); | ||
| 63 | } | ||
| 64 | |||
| 65 | void __tsan_unaligned_read8(const void *addr) { | ||
| 66 | UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 8, false, false); | ||
| 67 | } | ||
| 68 | |||
| 69 | void __tsan_unaligned_read16(const void *addr) { | ||
| 70 | UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 16, false, false); | ||
| 71 | } | ||
| 72 | |||
| 73 | void __tsan_unaligned_write2(void *addr) { | ||
| 74 | UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, true, false); | ||
| 75 | } | ||
| 76 | |||
| 77 | void __tsan_unaligned_write4(void *addr) { | ||
| 78 | UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 4, true, false); | ||
| 79 | } | ||
| 80 | |||
| 81 | void __tsan_unaligned_write8(void *addr) { | ||
| 82 | UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 8, true, false); | ||
| 83 | } | ||
| 84 | |||
| 85 | void __tsan_unaligned_write16(void *addr) { | ||
| 86 | UnalignedMemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 16, true, false); | ||
| 87 | } | ||
| 88 | |||
| 89 | // __sanitizer_unaligned_load/store are for user instrumentation. | ||
| 90 | |||
| 91 | extern "C" { | ||
| 92 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 93 | u16 __sanitizer_unaligned_load16(const uu16 *addr) { | ||
| 94 | __tsan_unaligned_read2(addr); | ||
| 95 | return *addr; | ||
| 96 | } | ||
| 97 | |||
| 98 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 99 | u32 __sanitizer_unaligned_load32(const uu32 *addr) { | ||
| 100 | __tsan_unaligned_read4(addr); | ||
| 101 | return *addr; | ||
| 102 | } | ||
| 103 | |||
| 104 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 105 | u64 __sanitizer_unaligned_load64(const uu64 *addr) { | ||
| 106 | __tsan_unaligned_read8(addr); | ||
| 107 | return *addr; | ||
| 108 | } | ||
| 109 | |||
| 110 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 111 | void __sanitizer_unaligned_store16(uu16 *addr, u16 v) { | ||
| 112 | __tsan_unaligned_write2(addr); | ||
| 113 | *addr = v; | ||
| 114 | } | ||
| 115 | |||
| 116 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 117 | void __sanitizer_unaligned_store32(uu32 *addr, u32 v) { | ||
| 118 | __tsan_unaligned_write4(addr); | ||
| 119 | *addr = v; | ||
| 120 | } | ||
| 121 | |||
| 122 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 123 | void __sanitizer_unaligned_store64(uu64 *addr, u64 v) { | ||
| 124 | __tsan_unaligned_write8(addr); | ||
| 125 | *addr = v; | ||
| 126 | } | ||
| 127 | |||
| 128 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 129 | void *__tsan_get_current_fiber() { | ||
| 130 | return cur_thread(); | ||
| 131 | } | ||
| 132 | |||
| 133 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 134 | void *__tsan_create_fiber(unsigned flags) { | ||
| 135 | return FiberCreate(cur_thread(), CALLERPC, flags); | ||
| 136 | } | ||
| 137 | |||
| 138 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 139 | void __tsan_destroy_fiber(void *fiber) { | ||
| 140 | FiberDestroy(cur_thread(), CALLERPC, static_cast<ThreadState *>(fiber)); | ||
| 141 | } | ||
| 142 | |||
| 143 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 144 | void __tsan_switch_to_fiber(void *fiber, unsigned flags) { | ||
| 145 | FiberSwitch(cur_thread(), CALLERPC, static_cast<ThreadState *>(fiber), flags); | ||
| 146 | } | ||
| 147 | |||
| 148 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 149 | void __tsan_set_fiber_name(void *fiber, const char *name) { | ||
| 150 | ThreadSetName(static_cast<ThreadState *>(fiber), name); | ||
| 151 | } | ||
| 152 | } // extern "C" | ||
| 153 | |||
| 154 | void __tsan_acquire(void *addr) { | ||
| 155 | Acquire(cur_thread(), CALLERPC, (uptr)addr); | ||
| 156 | } | ||
| 157 | |||
| 158 | void __tsan_release(void *addr) { | ||
| 159 | Release(cur_thread(), CALLERPC, (uptr)addr); | ||
| 160 | } | ||
lib/tsan/tsan_interface.h created+422| ... | @@ -0,0 +1,422 @@ | ||
| 1 | //===-- tsan_interface.h ----------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | // The functions declared in this header will be inserted by the instrumentation | ||
| 12 | // module. | ||
| 13 | // This header can be included by the instrumented program or by TSan tests. | ||
| 14 | //===----------------------------------------------------------------------===// | ||
| 15 | #ifndef TSAN_INTERFACE_H | ||
| 16 | #define TSAN_INTERFACE_H | ||
| 17 | |||
| 18 | #include <sanitizer_common/sanitizer_internal_defs.h> | ||
| 19 | using __sanitizer::uptr; | ||
| 20 | using __sanitizer::tid_t; | ||
| 21 | |||
| 22 | // This header should NOT include any other headers. | ||
| 23 | // All functions in this header are extern "C" and start with __tsan_. | ||
| 24 | |||
| 25 | #ifdef __cplusplus | ||
| 26 | extern "C" { | ||
| 27 | #endif | ||
| 28 | |||
| 29 | #if !SANITIZER_GO | ||
| 30 | |||
| 31 | // This function should be called at the very beginning of the process, | ||
| 32 | // before any instrumented code is executed and before any call to malloc. | ||
| 33 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_init(); | ||
| 34 | |||
| 35 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_flush_memory(); | ||
| 36 | |||
| 37 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read1(void *addr); | ||
| 38 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read2(void *addr); | ||
| 39 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read4(void *addr); | ||
| 40 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read8(void *addr); | ||
| 41 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read16(void *addr); | ||
| 42 | |||
| 43 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write1(void *addr); | ||
| 44 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write2(void *addr); | ||
| 45 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write4(void *addr); | ||
| 46 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write8(void *addr); | ||
| 47 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write16(void *addr); | ||
| 48 | |||
| 49 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_read2(const void *addr); | ||
| 50 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_read4(const void *addr); | ||
| 51 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_read8(const void *addr); | ||
| 52 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_read16(const void *addr); | ||
| 53 | |||
| 54 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write2(void *addr); | ||
| 55 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write4(void *addr); | ||
| 56 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write8(void *addr); | ||
| 57 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write16(void *addr); | ||
| 58 | |||
| 59 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read1_pc(void *addr, void *pc); | ||
| 60 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read2_pc(void *addr, void *pc); | ||
| 61 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read4_pc(void *addr, void *pc); | ||
| 62 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read8_pc(void *addr, void *pc); | ||
| 63 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read16_pc(void *addr, void *pc); | ||
| 64 | |||
| 65 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write1_pc(void *addr, void *pc); | ||
| 66 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write2_pc(void *addr, void *pc); | ||
| 67 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write4_pc(void *addr, void *pc); | ||
| 68 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write8_pc(void *addr, void *pc); | ||
| 69 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_write16_pc(void *addr, void *pc); | ||
| 70 | |||
| 71 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_vptr_read(void **vptr_p); | ||
| 72 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 73 | void __tsan_vptr_update(void **vptr_p, void *new_val); | ||
| 74 | |||
| 75 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_func_entry(void *call_pc); | ||
| 76 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_func_exit(); | ||
| 77 | |||
| 78 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_ignore_thread_begin(); | ||
| 79 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_ignore_thread_end(); | ||
| 80 | |||
| 81 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 82 | void *__tsan_external_register_tag(const char *object_type); | ||
| 83 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 84 | void __tsan_external_register_header(void *tag, const char *header); | ||
| 85 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 86 | void __tsan_external_assign_tag(void *addr, void *tag); | ||
| 87 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 88 | void __tsan_external_read(void *addr, void *caller_pc, void *tag); | ||
| 89 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 90 | void __tsan_external_write(void *addr, void *caller_pc, void *tag); | ||
| 91 | |||
| 92 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 93 | void __tsan_read_range(void *addr, unsigned long size); | ||
| 94 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 95 | void __tsan_write_range(void *addr, unsigned long size); | ||
| 96 | |||
| 97 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 98 | void __tsan_read_range_pc(void *addr, unsigned long size, void *pc); // NOLINT | ||
| 99 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 100 | void __tsan_write_range_pc(void *addr, unsigned long size, void *pc); // NOLINT | ||
| 101 | |||
| 102 | // User may provide function that would be called right when TSan detects | ||
| 103 | // an error. The argument 'report' is an opaque pointer that can be used to | ||
| 104 | // gather additional information using other TSan report API functions. | ||
| 105 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 106 | void __tsan_on_report(void *report); | ||
| 107 | |||
| 108 | // If TSan is currently reporting a detected issue on the current thread, | ||
| 109 | // returns an opaque pointer to the current report. Otherwise returns NULL. | ||
| 110 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 111 | void *__tsan_get_current_report(); | ||
| 112 | |||
| 113 | // Returns a report's description (issue type), number of duplicate issues | ||
| 114 | // found, counts of array data (stack traces, memory operations, locations, | ||
| 115 | // mutexes, threads, unique thread IDs) and a stack trace of a sleep() call (if | ||
| 116 | // one was involved in the issue). | ||
| 117 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 118 | int __tsan_get_report_data(void *report, const char **description, int *count, | ||
| 119 | int *stack_count, int *mop_count, int *loc_count, | ||
| 120 | int *mutex_count, int *thread_count, | ||
| 121 | int *unique_tid_count, void **sleep_trace, | ||
| 122 | uptr trace_size); | ||
| 123 | |||
| 124 | /// Retrieves the "tag" from a report (for external-race report types). External | ||
| 125 | /// races can be associated with a tag which give them more meaning. For example | ||
| 126 | /// tag value '1' means "Swift access race". Tag value '0' indicated a plain | ||
| 127 | /// external race. | ||
| 128 | /// | ||
| 129 | /// \param report opaque pointer to the current report (obtained as argument in | ||
| 130 | /// __tsan_on_report, or from __tsan_get_current_report) | ||
| 131 | /// \param [out] tag points to storage that will be filled with the tag value | ||
| 132 | /// | ||
| 133 | /// \returns non-zero value on success, zero on failure | ||
| 134 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 135 | int __tsan_get_report_tag(void *report, uptr *tag); | ||
| 136 | |||
| 137 | // Returns information about stack traces included in the report. | ||
| 138 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 139 | int __tsan_get_report_stack(void *report, uptr idx, void **trace, | ||
| 140 | uptr trace_size); | ||
| 141 | |||
| 142 | // Returns information about memory operations included in the report. | ||
| 143 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 144 | int __tsan_get_report_mop(void *report, uptr idx, int *tid, void **addr, | ||
| 145 | int *size, int *write, int *atomic, void **trace, | ||
| 146 | uptr trace_size); | ||
| 147 | |||
| 148 | // Returns information about locations included in the report. | ||
| 149 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 150 | int __tsan_get_report_loc(void *report, uptr idx, const char **type, | ||
| 151 | void **addr, uptr *start, uptr *size, int *tid, | ||
| 152 | int *fd, int *suppressable, void **trace, | ||
| 153 | uptr trace_size); | ||
| 154 | |||
| 155 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 156 | int __tsan_get_report_loc_object_type(void *report, uptr idx, | ||
| 157 | const char **object_type); | ||
| 158 | |||
| 159 | // Returns information about mutexes included in the report. | ||
| 160 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 161 | int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr, | ||
| 162 | int *destroyed, void **trace, uptr trace_size); | ||
| 163 | |||
| 164 | // Returns information about threads included in the report. | ||
| 165 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 166 | int __tsan_get_report_thread(void *report, uptr idx, int *tid, tid_t *os_id, | ||
| 167 | int *running, const char **name, int *parent_tid, | ||
| 168 | void **trace, uptr trace_size); | ||
| 169 | |||
| 170 | // Returns information about unique thread IDs included in the report. | ||
| 171 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 172 | int __tsan_get_report_unique_tid(void *report, uptr idx, int *tid); | ||
| 173 | |||
| 174 | // Returns the type of the pointer (heap, stack, global, ...) and if possible | ||
| 175 | // also the starting address (e.g. of a heap allocation) and size. | ||
| 176 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 177 | const char *__tsan_locate_address(uptr addr, char *name, uptr name_size, | ||
| 178 | uptr *region_address, uptr *region_size); | ||
| 179 | |||
| 180 | // Returns the allocation stack for a heap pointer. | ||
| 181 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 182 | int __tsan_get_alloc_stack(uptr addr, uptr *trace, uptr size, int *thread_id, | ||
| 183 | tid_t *os_id); | ||
| 184 | |||
| 185 | #endif // SANITIZER_GO | ||
| 186 | |||
| 187 | #ifdef __cplusplus | ||
| 188 | } // extern "C" | ||
| 189 | #endif | ||
| 190 | |||
| 191 | namespace __tsan { | ||
| 192 | |||
| 193 | // These should match declarations from public tsan_interface_atomic.h header. | ||
| 194 | typedef unsigned char a8; | ||
| 195 | typedef unsigned short a16; | ||
| 196 | typedef unsigned int a32; | ||
| 197 | typedef unsigned long long a64; | ||
| 198 | #if !SANITIZER_GO && (defined(__SIZEOF_INT128__) \ | ||
| 199 | || (__clang_major__ * 100 + __clang_minor__ >= 302)) && !defined(__mips64) | ||
| 200 | __extension__ typedef __int128 a128; | ||
| 201 | # define __TSAN_HAS_INT128 1 | ||
| 202 | #else | ||
| 203 | # define __TSAN_HAS_INT128 0 | ||
| 204 | #endif | ||
| 205 | |||
| 206 | // Part of ABI, do not change. | ||
| 207 | // https://github.com/llvm/llvm-project/blob/master/libcxx/include/atomic | ||
| 208 | typedef enum { | ||
| 209 | mo_relaxed, | ||
| 210 | mo_consume, | ||
| 211 | mo_acquire, | ||
| 212 | mo_release, | ||
| 213 | mo_acq_rel, | ||
| 214 | mo_seq_cst | ||
| 215 | } morder; | ||
| 216 | |||
| 217 | struct ThreadState; | ||
| 218 | |||
| 219 | extern "C" { | ||
| 220 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 221 | a8 __tsan_atomic8_load(const volatile a8 *a, morder mo); | ||
| 222 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 223 | a16 __tsan_atomic16_load(const volatile a16 *a, morder mo); | ||
| 224 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 225 | a32 __tsan_atomic32_load(const volatile a32 *a, morder mo); | ||
| 226 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 227 | a64 __tsan_atomic64_load(const volatile a64 *a, morder mo); | ||
| 228 | #if __TSAN_HAS_INT128 | ||
| 229 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 230 | a128 __tsan_atomic128_load(const volatile a128 *a, morder mo); | ||
| 231 | #endif | ||
| 232 | |||
| 233 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 234 | void __tsan_atomic8_store(volatile a8 *a, a8 v, morder mo); | ||
| 235 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 236 | void __tsan_atomic16_store(volatile a16 *a, a16 v, morder mo); | ||
| 237 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 238 | void __tsan_atomic32_store(volatile a32 *a, a32 v, morder mo); | ||
| 239 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 240 | void __tsan_atomic64_store(volatile a64 *a, a64 v, morder mo); | ||
| 241 | #if __TSAN_HAS_INT128 | ||
| 242 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 243 | void __tsan_atomic128_store(volatile a128 *a, a128 v, morder mo); | ||
| 244 | #endif | ||
| 245 | |||
| 246 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 247 | a8 __tsan_atomic8_exchange(volatile a8 *a, a8 v, morder mo); | ||
| 248 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 249 | a16 __tsan_atomic16_exchange(volatile a16 *a, a16 v, morder mo); | ||
| 250 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 251 | a32 __tsan_atomic32_exchange(volatile a32 *a, a32 v, morder mo); | ||
| 252 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 253 | a64 __tsan_atomic64_exchange(volatile a64 *a, a64 v, morder mo); | ||
| 254 | #if __TSAN_HAS_INT128 | ||
| 255 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 256 | a128 __tsan_atomic128_exchange(volatile a128 *a, a128 v, morder mo); | ||
| 257 | #endif | ||
| 258 | |||
| 259 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 260 | a8 __tsan_atomic8_fetch_add(volatile a8 *a, a8 v, morder mo); | ||
| 261 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 262 | a16 __tsan_atomic16_fetch_add(volatile a16 *a, a16 v, morder mo); | ||
| 263 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 264 | a32 __tsan_atomic32_fetch_add(volatile a32 *a, a32 v, morder mo); | ||
| 265 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 266 | a64 __tsan_atomic64_fetch_add(volatile a64 *a, a64 v, morder mo); | ||
| 267 | #if __TSAN_HAS_INT128 | ||
| 268 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 269 | a128 __tsan_atomic128_fetch_add(volatile a128 *a, a128 v, morder mo); | ||
| 270 | #endif | ||
| 271 | |||
| 272 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 273 | a8 __tsan_atomic8_fetch_sub(volatile a8 *a, a8 v, morder mo); | ||
| 274 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 275 | a16 __tsan_atomic16_fetch_sub(volatile a16 *a, a16 v, morder mo); | ||
| 276 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 277 | a32 __tsan_atomic32_fetch_sub(volatile a32 *a, a32 v, morder mo); | ||
| 278 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 279 | a64 __tsan_atomic64_fetch_sub(volatile a64 *a, a64 v, morder mo); | ||
| 280 | #if __TSAN_HAS_INT128 | ||
| 281 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 282 | a128 __tsan_atomic128_fetch_sub(volatile a128 *a, a128 v, morder mo); | ||
| 283 | #endif | ||
| 284 | |||
| 285 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 286 | a8 __tsan_atomic8_fetch_and(volatile a8 *a, a8 v, morder mo); | ||
| 287 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 288 | a16 __tsan_atomic16_fetch_and(volatile a16 *a, a16 v, morder mo); | ||
| 289 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 290 | a32 __tsan_atomic32_fetch_and(volatile a32 *a, a32 v, morder mo); | ||
| 291 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 292 | a64 __tsan_atomic64_fetch_and(volatile a64 *a, a64 v, morder mo); | ||
| 293 | #if __TSAN_HAS_INT128 | ||
| 294 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 295 | a128 __tsan_atomic128_fetch_and(volatile a128 *a, a128 v, morder mo); | ||
| 296 | #endif | ||
| 297 | |||
| 298 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 299 | a8 __tsan_atomic8_fetch_or(volatile a8 *a, a8 v, morder mo); | ||
| 300 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 301 | a16 __tsan_atomic16_fetch_or(volatile a16 *a, a16 v, morder mo); | ||
| 302 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 303 | a32 __tsan_atomic32_fetch_or(volatile a32 *a, a32 v, morder mo); | ||
| 304 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 305 | a64 __tsan_atomic64_fetch_or(volatile a64 *a, a64 v, morder mo); | ||
| 306 | #if __TSAN_HAS_INT128 | ||
| 307 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 308 | a128 __tsan_atomic128_fetch_or(volatile a128 *a, a128 v, morder mo); | ||
| 309 | #endif | ||
| 310 | |||
| 311 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 312 | a8 __tsan_atomic8_fetch_xor(volatile a8 *a, a8 v, morder mo); | ||
| 313 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 314 | a16 __tsan_atomic16_fetch_xor(volatile a16 *a, a16 v, morder mo); | ||
| 315 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 316 | a32 __tsan_atomic32_fetch_xor(volatile a32 *a, a32 v, morder mo); | ||
| 317 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 318 | a64 __tsan_atomic64_fetch_xor(volatile a64 *a, a64 v, morder mo); | ||
| 319 | #if __TSAN_HAS_INT128 | ||
| 320 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 321 | a128 __tsan_atomic128_fetch_xor(volatile a128 *a, a128 v, morder mo); | ||
| 322 | #endif | ||
| 323 | |||
| 324 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 325 | a8 __tsan_atomic8_fetch_nand(volatile a8 *a, a8 v, morder mo); | ||
| 326 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 327 | a16 __tsan_atomic16_fetch_nand(volatile a16 *a, a16 v, morder mo); | ||
| 328 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 329 | a32 __tsan_atomic32_fetch_nand(volatile a32 *a, a32 v, morder mo); | ||
| 330 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 331 | a64 __tsan_atomic64_fetch_nand(volatile a64 *a, a64 v, morder mo); | ||
| 332 | #if __TSAN_HAS_INT128 | ||
| 333 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 334 | a128 __tsan_atomic128_fetch_nand(volatile a128 *a, a128 v, morder mo); | ||
| 335 | #endif | ||
| 336 | |||
| 337 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 338 | int __tsan_atomic8_compare_exchange_strong(volatile a8 *a, a8 *c, a8 v, | ||
| 339 | morder mo, morder fmo); | ||
| 340 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 341 | int __tsan_atomic16_compare_exchange_strong(volatile a16 *a, a16 *c, a16 v, | ||
| 342 | morder mo, morder fmo); | ||
| 343 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 344 | int __tsan_atomic32_compare_exchange_strong(volatile a32 *a, a32 *c, a32 v, | ||
| 345 | morder mo, morder fmo); | ||
| 346 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 347 | int __tsan_atomic64_compare_exchange_strong(volatile a64 *a, a64 *c, a64 v, | ||
| 348 | morder mo, morder fmo); | ||
| 349 | #if __TSAN_HAS_INT128 | ||
| 350 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 351 | int __tsan_atomic128_compare_exchange_strong(volatile a128 *a, a128 *c, a128 v, | ||
| 352 | morder mo, morder fmo); | ||
| 353 | #endif | ||
| 354 | |||
| 355 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 356 | int __tsan_atomic8_compare_exchange_weak(volatile a8 *a, a8 *c, a8 v, morder mo, | ||
| 357 | morder fmo); | ||
| 358 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 359 | int __tsan_atomic16_compare_exchange_weak(volatile a16 *a, a16 *c, a16 v, | ||
| 360 | morder mo, morder fmo); | ||
| 361 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 362 | int __tsan_atomic32_compare_exchange_weak(volatile a32 *a, a32 *c, a32 v, | ||
| 363 | morder mo, morder fmo); | ||
| 364 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 365 | int __tsan_atomic64_compare_exchange_weak(volatile a64 *a, a64 *c, a64 v, | ||
| 366 | morder mo, morder fmo); | ||
| 367 | #if __TSAN_HAS_INT128 | ||
| 368 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 369 | int __tsan_atomic128_compare_exchange_weak(volatile a128 *a, a128 *c, a128 v, | ||
| 370 | morder mo, morder fmo); | ||
| 371 | #endif | ||
| 372 | |||
| 373 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 374 | a8 __tsan_atomic8_compare_exchange_val(volatile a8 *a, a8 c, a8 v, morder mo, | ||
| 375 | morder fmo); | ||
| 376 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 377 | a16 __tsan_atomic16_compare_exchange_val(volatile a16 *a, a16 c, a16 v, | ||
| 378 | morder mo, morder fmo); | ||
| 379 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 380 | a32 __tsan_atomic32_compare_exchange_val(volatile a32 *a, a32 c, a32 v, | ||
| 381 | morder mo, morder fmo); | ||
| 382 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 383 | a64 __tsan_atomic64_compare_exchange_val(volatile a64 *a, a64 c, a64 v, | ||
| 384 | morder mo, morder fmo); | ||
| 385 | #if __TSAN_HAS_INT128 | ||
| 386 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 387 | a128 __tsan_atomic128_compare_exchange_val(volatile a128 *a, a128 c, a128 v, | ||
| 388 | morder mo, morder fmo); | ||
| 389 | #endif | ||
| 390 | |||
| 391 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 392 | void __tsan_atomic_thread_fence(morder mo); | ||
| 393 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 394 | void __tsan_atomic_signal_fence(morder mo); | ||
| 395 | |||
| 396 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 397 | void __tsan_go_atomic32_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a); | ||
| 398 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 399 | void __tsan_go_atomic64_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a); | ||
| 400 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 401 | void __tsan_go_atomic32_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a); | ||
| 402 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 403 | void __tsan_go_atomic64_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a); | ||
| 404 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 405 | void __tsan_go_atomic32_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a); | ||
| 406 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 407 | void __tsan_go_atomic64_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a); | ||
| 408 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 409 | void __tsan_go_atomic32_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a); | ||
| 410 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 411 | void __tsan_go_atomic64_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a); | ||
| 412 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 413 | void __tsan_go_atomic32_compare_exchange(ThreadState *thr, uptr cpc, uptr pc, | ||
| 414 | u8 *a); | ||
| 415 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 416 | void __tsan_go_atomic64_compare_exchange(ThreadState *thr, uptr cpc, uptr pc, | ||
| 417 | u8 *a); | ||
| 418 | } // extern "C" | ||
| 419 | |||
| 420 | } // namespace __tsan | ||
| 421 | |||
| 422 | #endif // TSAN_INTERFACE_H | ||
lib/tsan/tsan_interface_ann.cpp created+552| ... | @@ -0,0 +1,552 @@ | ||
| 1 | //===-- tsan_interface_ann.cpp --------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #include "sanitizer_common/sanitizer_libc.h" | ||
| 13 | #include "sanitizer_common/sanitizer_internal_defs.h" | ||
| 14 | #include "sanitizer_common/sanitizer_placement_new.h" | ||
| 15 | #include "sanitizer_common/sanitizer_stacktrace.h" | ||
| 16 | #include "sanitizer_common/sanitizer_vector.h" | ||
| 17 | #include "tsan_interface_ann.h" | ||
| 18 | #include "tsan_mutex.h" | ||
| 19 | #include "tsan_report.h" | ||
| 20 | #include "tsan_rtl.h" | ||
| 21 | #include "tsan_mman.h" | ||
| 22 | #include "tsan_flags.h" | ||
| 23 | #include "tsan_platform.h" | ||
| 24 | |||
| 25 | #define CALLERPC ((uptr)__builtin_return_address(0)) | ||
| 26 | |||
| 27 | using namespace __tsan; | ||
| 28 | |||
| 29 | namespace __tsan { | ||
| 30 | |||
| 31 | class ScopedAnnotation { | ||
| 32 | public: | ||
| 33 | ScopedAnnotation(ThreadState *thr, const char *aname, uptr pc) | ||
| 34 | : thr_(thr) { | ||
| 35 | FuncEntry(thr_, pc); | ||
| 36 | DPrintf("#%d: annotation %s()\n", thr_->tid, aname); | ||
| 37 | } | ||
| 38 | |||
| 39 | ~ScopedAnnotation() { | ||
| 40 | FuncExit(thr_); | ||
| 41 | CheckNoLocks(thr_); | ||
| 42 | } | ||
| 43 | private: | ||
| 44 | ThreadState *const thr_; | ||
| 45 | }; | ||
| 46 | |||
| 47 | #define SCOPED_ANNOTATION_RET(typ, ret) \ | ||
| 48 | if (!flags()->enable_annotations) \ | ||
| 49 | return ret; \ | ||
| 50 | ThreadState *thr = cur_thread(); \ | ||
| 51 | const uptr caller_pc = (uptr)__builtin_return_address(0); \ | ||
| 52 | StatInc(thr, StatAnnotation); \ | ||
| 53 | StatInc(thr, Stat##typ); \ | ||
| 54 | ScopedAnnotation sa(thr, __func__, caller_pc); \ | ||
| 55 | const uptr pc = StackTrace::GetCurrentPc(); \ | ||
| 56 | (void)pc; \ | ||
| 57 | /**/ | ||
| 58 | |||
| 59 | #define SCOPED_ANNOTATION(typ) SCOPED_ANNOTATION_RET(typ, ) | ||
| 60 | |||
| 61 | static const int kMaxDescLen = 128; | ||
| 62 | |||
| 63 | struct ExpectRace { | ||
| 64 | ExpectRace *next; | ||
| 65 | ExpectRace *prev; | ||
| 66 | atomic_uintptr_t hitcount; | ||
| 67 | atomic_uintptr_t addcount; | ||
| 68 | uptr addr; | ||
| 69 | uptr size; | ||
| 70 | char *file; | ||
| 71 | int line; | ||
| 72 | char desc[kMaxDescLen]; | ||
| 73 | }; | ||
| 74 | |||
| 75 | struct DynamicAnnContext { | ||
| 76 | Mutex mtx; | ||
| 77 | ExpectRace expect; | ||
| 78 | ExpectRace benign; | ||
| 79 | |||
| 80 | DynamicAnnContext() | ||
| 81 | : mtx(MutexTypeAnnotations, StatMtxAnnotations) { | ||
| 82 | } | ||
| 83 | }; | ||
| 84 | |||
| 85 | static DynamicAnnContext *dyn_ann_ctx; | ||
| 86 | static char dyn_ann_ctx_placeholder[sizeof(DynamicAnnContext)] ALIGNED(64); | ||
| 87 | |||
| 88 | static void AddExpectRace(ExpectRace *list, | ||
| 89 | char *f, int l, uptr addr, uptr size, char *desc) { | ||
| 90 | ExpectRace *race = list->next; | ||
| 91 | for (; race != list; race = race->next) { | ||
| 92 | if (race->addr == addr && race->size == size) { | ||
| 93 | atomic_store_relaxed(&race->addcount, | ||
| 94 | atomic_load_relaxed(&race->addcount) + 1); | ||
| 95 | return; | ||
| 96 | } | ||
| 97 | } | ||
| 98 | race = (ExpectRace*)internal_alloc(MBlockExpectRace, sizeof(ExpectRace)); | ||
| 99 | race->addr = addr; | ||
| 100 | race->size = size; | ||
| 101 | race->file = f; | ||
| 102 | race->line = l; | ||
| 103 | race->desc[0] = 0; | ||
| 104 | atomic_store_relaxed(&race->hitcount, 0); | ||
| 105 | atomic_store_relaxed(&race->addcount, 1); | ||
| 106 | if (desc) { | ||
| 107 | int i = 0; | ||
| 108 | for (; i < kMaxDescLen - 1 && desc[i]; i++) | ||
| 109 | race->desc[i] = desc[i]; | ||
| 110 | race->desc[i] = 0; | ||
| 111 | } | ||
| 112 | race->prev = list; | ||
| 113 | race->next = list->next; | ||
| 114 | race->next->prev = race; | ||
| 115 | list->next = race; | ||
| 116 | } | ||
| 117 | |||
| 118 | static ExpectRace *FindRace(ExpectRace *list, uptr addr, uptr size) { | ||
| 119 | for (ExpectRace *race = list->next; race != list; race = race->next) { | ||
| 120 | uptr maxbegin = max(race->addr, addr); | ||
| 121 | uptr minend = min(race->addr + race->size, addr + size); | ||
| 122 | if (maxbegin < minend) | ||
| 123 | return race; | ||
| 124 | } | ||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | |||
| 128 | static bool CheckContains(ExpectRace *list, uptr addr, uptr size) { | ||
| 129 | ExpectRace *race = FindRace(list, addr, size); | ||
| 130 | if (race == 0) | ||
| 131 | return false; | ||
| 132 | DPrintf("Hit expected/benign race: %s addr=%zx:%d %s:%d\n", | ||
| 133 | race->desc, race->addr, (int)race->size, race->file, race->line); | ||
| 134 | atomic_fetch_add(&race->hitcount, 1, memory_order_relaxed); | ||
| 135 | return true; | ||
| 136 | } | ||
| 137 | |||
| 138 | static void InitList(ExpectRace *list) { | ||
| 139 | list->next = list; | ||
| 140 | list->prev = list; | ||
| 141 | } | ||
| 142 | |||
| 143 | void InitializeDynamicAnnotations() { | ||
| 144 | dyn_ann_ctx = new(dyn_ann_ctx_placeholder) DynamicAnnContext; | ||
| 145 | InitList(&dyn_ann_ctx->expect); | ||
| 146 | InitList(&dyn_ann_ctx->benign); | ||
| 147 | } | ||
| 148 | |||
| 149 | bool IsExpectedReport(uptr addr, uptr size) { | ||
| 150 | ReadLock lock(&dyn_ann_ctx->mtx); | ||
| 151 | if (CheckContains(&dyn_ann_ctx->expect, addr, size)) | ||
| 152 | return true; | ||
| 153 | if (CheckContains(&dyn_ann_ctx->benign, addr, size)) | ||
| 154 | return true; | ||
| 155 | return false; | ||
| 156 | } | ||
| 157 | |||
| 158 | static void CollectMatchedBenignRaces(Vector<ExpectRace> *matched, | ||
| 159 | int *unique_count, int *hit_count, atomic_uintptr_t ExpectRace::*counter) { | ||
| 160 | ExpectRace *list = &dyn_ann_ctx->benign; | ||
| 161 | for (ExpectRace *race = list->next; race != list; race = race->next) { | ||
| 162 | (*unique_count)++; | ||
| 163 | const uptr cnt = atomic_load_relaxed(&(race->*counter)); | ||
| 164 | if (cnt == 0) | ||
| 165 | continue; | ||
| 166 | *hit_count += cnt; | ||
| 167 | uptr i = 0; | ||
| 168 | for (; i < matched->Size(); i++) { | ||
| 169 | ExpectRace *race0 = &(*matched)[i]; | ||
| 170 | if (race->line == race0->line | ||
| 171 | && internal_strcmp(race->file, race0->file) == 0 | ||
| 172 | && internal_strcmp(race->desc, race0->desc) == 0) { | ||
| 173 | atomic_fetch_add(&(race0->*counter), cnt, memory_order_relaxed); | ||
| 174 | break; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | if (i == matched->Size()) | ||
| 178 | matched->PushBack(*race); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 182 | void PrintMatchedBenignRaces() { | ||
| 183 | Lock lock(&dyn_ann_ctx->mtx); | ||
| 184 | int unique_count = 0; | ||
| 185 | int hit_count = 0; | ||
| 186 | int add_count = 0; | ||
| 187 | Vector<ExpectRace> hit_matched; | ||
| 188 | CollectMatchedBenignRaces(&hit_matched, &unique_count, &hit_count, | ||
| 189 | &ExpectRace::hitcount); | ||
| 190 | Vector<ExpectRace> add_matched; | ||
| 191 | CollectMatchedBenignRaces(&add_matched, &unique_count, &add_count, | ||
| 192 | &ExpectRace::addcount); | ||
| 193 | if (hit_matched.Size()) { | ||
| 194 | Printf("ThreadSanitizer: Matched %d \"benign\" races (pid=%d):\n", | ||
| 195 | hit_count, (int)internal_getpid()); | ||
| 196 | for (uptr i = 0; i < hit_matched.Size(); i++) { | ||
| 197 | Printf("%d %s:%d %s\n", | ||
| 198 | atomic_load_relaxed(&hit_matched[i].hitcount), | ||
| 199 | hit_matched[i].file, hit_matched[i].line, hit_matched[i].desc); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | if (hit_matched.Size()) { | ||
| 203 | Printf("ThreadSanitizer: Annotated %d \"benign\" races, %d unique" | ||
| 204 | " (pid=%d):\n", | ||
| 205 | add_count, unique_count, (int)internal_getpid()); | ||
| 206 | for (uptr i = 0; i < add_matched.Size(); i++) { | ||
| 207 | Printf("%d %s:%d %s\n", | ||
| 208 | atomic_load_relaxed(&add_matched[i].addcount), | ||
| 209 | add_matched[i].file, add_matched[i].line, add_matched[i].desc); | ||
| 210 | } | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | static void ReportMissedExpectedRace(ExpectRace *race) { | ||
| 215 | Printf("==================\n"); | ||
| 216 | Printf("WARNING: ThreadSanitizer: missed expected data race\n"); | ||
| 217 | Printf(" %s addr=%zx %s:%d\n", | ||
| 218 | race->desc, race->addr, race->file, race->line); | ||
| 219 | Printf("==================\n"); | ||
| 220 | } | ||
| 221 | } // namespace __tsan | ||
| 222 | |||
| 223 | using namespace __tsan; | ||
| 224 | |||
| 225 | extern "C" { | ||
| 226 | void INTERFACE_ATTRIBUTE AnnotateHappensBefore(char *f, int l, uptr addr) { | ||
| 227 | SCOPED_ANNOTATION(AnnotateHappensBefore); | ||
| 228 | Release(thr, pc, addr); | ||
| 229 | } | ||
| 230 | |||
| 231 | void INTERFACE_ATTRIBUTE AnnotateHappensAfter(char *f, int l, uptr addr) { | ||
| 232 | SCOPED_ANNOTATION(AnnotateHappensAfter); | ||
| 233 | Acquire(thr, pc, addr); | ||
| 234 | } | ||
| 235 | |||
| 236 | void INTERFACE_ATTRIBUTE AnnotateCondVarSignal(char *f, int l, uptr cv) { | ||
| 237 | SCOPED_ANNOTATION(AnnotateCondVarSignal); | ||
| 238 | } | ||
| 239 | |||
| 240 | void INTERFACE_ATTRIBUTE AnnotateCondVarSignalAll(char *f, int l, uptr cv) { | ||
| 241 | SCOPED_ANNOTATION(AnnotateCondVarSignalAll); | ||
| 242 | } | ||
| 243 | |||
| 244 | void INTERFACE_ATTRIBUTE AnnotateMutexIsNotPHB(char *f, int l, uptr mu) { | ||
| 245 | SCOPED_ANNOTATION(AnnotateMutexIsNotPHB); | ||
| 246 | } | ||
| 247 | |||
| 248 | void INTERFACE_ATTRIBUTE AnnotateCondVarWait(char *f, int l, uptr cv, | ||
| 249 | uptr lock) { | ||
| 250 | SCOPED_ANNOTATION(AnnotateCondVarWait); | ||
| 251 | } | ||
| 252 | |||
| 253 | void INTERFACE_ATTRIBUTE AnnotateRWLockCreate(char *f, int l, uptr m) { | ||
| 254 | SCOPED_ANNOTATION(AnnotateRWLockCreate); | ||
| 255 | MutexCreate(thr, pc, m, MutexFlagWriteReentrant); | ||
| 256 | } | ||
| 257 | |||
| 258 | void INTERFACE_ATTRIBUTE AnnotateRWLockCreateStatic(char *f, int l, uptr m) { | ||
| 259 | SCOPED_ANNOTATION(AnnotateRWLockCreateStatic); | ||
| 260 | MutexCreate(thr, pc, m, MutexFlagWriteReentrant | MutexFlagLinkerInit); | ||
| 261 | } | ||
| 262 | |||
| 263 | void INTERFACE_ATTRIBUTE AnnotateRWLockDestroy(char *f, int l, uptr m) { | ||
| 264 | SCOPED_ANNOTATION(AnnotateRWLockDestroy); | ||
| 265 | MutexDestroy(thr, pc, m); | ||
| 266 | } | ||
| 267 | |||
| 268 | void INTERFACE_ATTRIBUTE AnnotateRWLockAcquired(char *f, int l, uptr m, | ||
| 269 | uptr is_w) { | ||
| 270 | SCOPED_ANNOTATION(AnnotateRWLockAcquired); | ||
| 271 | if (is_w) | ||
| 272 | MutexPostLock(thr, pc, m, MutexFlagDoPreLockOnPostLock); | ||
| 273 | else | ||
| 274 | MutexPostReadLock(thr, pc, m, MutexFlagDoPreLockOnPostLock); | ||
| 275 | } | ||
| 276 | |||
| 277 | void INTERFACE_ATTRIBUTE AnnotateRWLockReleased(char *f, int l, uptr m, | ||
| 278 | uptr is_w) { | ||
| 279 | SCOPED_ANNOTATION(AnnotateRWLockReleased); | ||
| 280 | if (is_w) | ||
| 281 | MutexUnlock(thr, pc, m); | ||
| 282 | else | ||
| 283 | MutexReadUnlock(thr, pc, m); | ||
| 284 | } | ||
| 285 | |||
| 286 | void INTERFACE_ATTRIBUTE AnnotateTraceMemory(char *f, int l, uptr mem) { | ||
| 287 | SCOPED_ANNOTATION(AnnotateTraceMemory); | ||
| 288 | } | ||
| 289 | |||
| 290 | void INTERFACE_ATTRIBUTE AnnotateFlushState(char *f, int l) { | ||
| 291 | SCOPED_ANNOTATION(AnnotateFlushState); | ||
| 292 | } | ||
| 293 | |||
| 294 | void INTERFACE_ATTRIBUTE AnnotateNewMemory(char *f, int l, uptr mem, | ||
| 295 | uptr size) { | ||
| 296 | SCOPED_ANNOTATION(AnnotateNewMemory); | ||
| 297 | } | ||
| 298 | |||
| 299 | void INTERFACE_ATTRIBUTE AnnotateNoOp(char *f, int l, uptr mem) { | ||
| 300 | SCOPED_ANNOTATION(AnnotateNoOp); | ||
| 301 | } | ||
| 302 | |||
| 303 | void INTERFACE_ATTRIBUTE AnnotateFlushExpectedRaces(char *f, int l) { | ||
| 304 | SCOPED_ANNOTATION(AnnotateFlushExpectedRaces); | ||
| 305 | Lock lock(&dyn_ann_ctx->mtx); | ||
| 306 | while (dyn_ann_ctx->expect.next != &dyn_ann_ctx->expect) { | ||
| 307 | ExpectRace *race = dyn_ann_ctx->expect.next; | ||
| 308 | if (atomic_load_relaxed(&race->hitcount) == 0) { | ||
| 309 | ctx->nmissed_expected++; | ||
| 310 | ReportMissedExpectedRace(race); | ||
| 311 | } | ||
| 312 | race->prev->next = race->next; | ||
| 313 | race->next->prev = race->prev; | ||
| 314 | internal_free(race); | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 318 | void INTERFACE_ATTRIBUTE AnnotateEnableRaceDetection( | ||
| 319 | char *f, int l, int enable) { | ||
| 320 | SCOPED_ANNOTATION(AnnotateEnableRaceDetection); | ||
| 321 | // FIXME: Reconsider this functionality later. It may be irrelevant. | ||
| 322 | } | ||
| 323 | |||
| 324 | void INTERFACE_ATTRIBUTE AnnotateMutexIsUsedAsCondVar( | ||
| 325 | char *f, int l, uptr mu) { | ||
| 326 | SCOPED_ANNOTATION(AnnotateMutexIsUsedAsCondVar); | ||
| 327 | } | ||
| 328 | |||
| 329 | void INTERFACE_ATTRIBUTE AnnotatePCQGet( | ||
| 330 | char *f, int l, uptr pcq) { | ||
| 331 | SCOPED_ANNOTATION(AnnotatePCQGet); | ||
| 332 | } | ||
| 333 | |||
| 334 | void INTERFACE_ATTRIBUTE AnnotatePCQPut( | ||
| 335 | char *f, int l, uptr pcq) { | ||
| 336 | SCOPED_ANNOTATION(AnnotatePCQPut); | ||
| 337 | } | ||
| 338 | |||
| 339 | void INTERFACE_ATTRIBUTE AnnotatePCQDestroy( | ||
| 340 | char *f, int l, uptr pcq) { | ||
| 341 | SCOPED_ANNOTATION(AnnotatePCQDestroy); | ||
| 342 | } | ||
| 343 | |||
| 344 | void INTERFACE_ATTRIBUTE AnnotatePCQCreate( | ||
| 345 | char *f, int l, uptr pcq) { | ||
| 346 | SCOPED_ANNOTATION(AnnotatePCQCreate); | ||
| 347 | } | ||
| 348 | |||
| 349 | void INTERFACE_ATTRIBUTE AnnotateExpectRace( | ||
| 350 | char *f, int l, uptr mem, char *desc) { | ||
| 351 | SCOPED_ANNOTATION(AnnotateExpectRace); | ||
| 352 | Lock lock(&dyn_ann_ctx->mtx); | ||
| 353 | AddExpectRace(&dyn_ann_ctx->expect, | ||
| 354 | f, l, mem, 1, desc); | ||
| 355 | DPrintf("Add expected race: %s addr=%zx %s:%d\n", desc, mem, f, l); | ||
| 356 | } | ||
| 357 | |||
| 358 | static void BenignRaceImpl( | ||
| 359 | char *f, int l, uptr mem, uptr size, char *desc) { | ||
| 360 | Lock lock(&dyn_ann_ctx->mtx); | ||
| 361 | AddExpectRace(&dyn_ann_ctx->benign, | ||
| 362 | f, l, mem, size, desc); | ||
| 363 | DPrintf("Add benign race: %s addr=%zx %s:%d\n", desc, mem, f, l); | ||
| 364 | } | ||
| 365 | |||
| 366 | // FIXME: Turn it off later. WTF is benign race?1?? Go talk to Hans Boehm. | ||
| 367 | void INTERFACE_ATTRIBUTE AnnotateBenignRaceSized( | ||
| 368 | char *f, int l, uptr mem, uptr size, char *desc) { | ||
| 369 | SCOPED_ANNOTATION(AnnotateBenignRaceSized); | ||
| 370 | BenignRaceImpl(f, l, mem, size, desc); | ||
| 371 | } | ||
| 372 | |||
| 373 | void INTERFACE_ATTRIBUTE AnnotateBenignRace( | ||
| 374 | char *f, int l, uptr mem, char *desc) { | ||
| 375 | SCOPED_ANNOTATION(AnnotateBenignRace); | ||
| 376 | BenignRaceImpl(f, l, mem, 1, desc); | ||
| 377 | } | ||
| 378 | |||
| 379 | void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsBegin(char *f, int l) { | ||
| 380 | SCOPED_ANNOTATION(AnnotateIgnoreReadsBegin); | ||
| 381 | ThreadIgnoreBegin(thr, pc); | ||
| 382 | } | ||
| 383 | |||
| 384 | void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsEnd(char *f, int l) { | ||
| 385 | SCOPED_ANNOTATION(AnnotateIgnoreReadsEnd); | ||
| 386 | ThreadIgnoreEnd(thr, pc); | ||
| 387 | } | ||
| 388 | |||
| 389 | void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesBegin(char *f, int l) { | ||
| 390 | SCOPED_ANNOTATION(AnnotateIgnoreWritesBegin); | ||
| 391 | ThreadIgnoreBegin(thr, pc); | ||
| 392 | } | ||
| 393 | |||
| 394 | void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesEnd(char *f, int l) { | ||
| 395 | SCOPED_ANNOTATION(AnnotateIgnoreWritesEnd); | ||
| 396 | ThreadIgnoreEnd(thr, pc); | ||
| 397 | } | ||
| 398 | |||
| 399 | void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncBegin(char *f, int l) { | ||
| 400 | SCOPED_ANNOTATION(AnnotateIgnoreSyncBegin); | ||
| 401 | ThreadIgnoreSyncBegin(thr, pc); | ||
| 402 | } | ||
| 403 | |||
| 404 | void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncEnd(char *f, int l) { | ||
| 405 | SCOPED_ANNOTATION(AnnotateIgnoreSyncEnd); | ||
| 406 | ThreadIgnoreSyncEnd(thr, pc); | ||
| 407 | } | ||
| 408 | |||
| 409 | void INTERFACE_ATTRIBUTE AnnotatePublishMemoryRange( | ||
| 410 | char *f, int l, uptr addr, uptr size) { | ||
| 411 | SCOPED_ANNOTATION(AnnotatePublishMemoryRange); | ||
| 412 | } | ||
| 413 | |||
| 414 | void INTERFACE_ATTRIBUTE AnnotateUnpublishMemoryRange( | ||
| 415 | char *f, int l, uptr addr, uptr size) { | ||
| 416 | SCOPED_ANNOTATION(AnnotateUnpublishMemoryRange); | ||
| 417 | } | ||
| 418 | |||
| 419 | void INTERFACE_ATTRIBUTE AnnotateThreadName( | ||
| 420 | char *f, int l, char *name) { | ||
| 421 | SCOPED_ANNOTATION(AnnotateThreadName); | ||
| 422 | ThreadSetName(thr, name); | ||
| 423 | } | ||
| 424 | |||
| 425 | // We deliberately omit the implementation of WTFAnnotateHappensBefore() and | ||
| 426 | // WTFAnnotateHappensAfter(). Those are being used by Webkit to annotate | ||
| 427 | // atomic operations, which should be handled by ThreadSanitizer correctly. | ||
| 428 | void INTERFACE_ATTRIBUTE WTFAnnotateHappensBefore(char *f, int l, uptr addr) { | ||
| 429 | SCOPED_ANNOTATION(AnnotateHappensBefore); | ||
| 430 | } | ||
| 431 | |||
| 432 | void INTERFACE_ATTRIBUTE WTFAnnotateHappensAfter(char *f, int l, uptr addr) { | ||
| 433 | SCOPED_ANNOTATION(AnnotateHappensAfter); | ||
| 434 | } | ||
| 435 | |||
| 436 | void INTERFACE_ATTRIBUTE WTFAnnotateBenignRaceSized( | ||
| 437 | char *f, int l, uptr mem, uptr sz, char *desc) { | ||
| 438 | SCOPED_ANNOTATION(AnnotateBenignRaceSized); | ||
| 439 | BenignRaceImpl(f, l, mem, sz, desc); | ||
| 440 | } | ||
| 441 | |||
| 442 | int INTERFACE_ATTRIBUTE RunningOnValgrind() { | ||
| 443 | return flags()->running_on_valgrind; | ||
| 444 | } | ||
| 445 | |||
| 446 | double __attribute__((weak)) INTERFACE_ATTRIBUTE ValgrindSlowdown(void) { | ||
| 447 | return 10.0; | ||
| 448 | } | ||
| 449 | |||
| 450 | const char INTERFACE_ATTRIBUTE* ThreadSanitizerQuery(const char *query) { | ||
| 451 | if (internal_strcmp(query, "pure_happens_before") == 0) | ||
| 452 | return "1"; | ||
| 453 | else | ||
| 454 | return "0"; | ||
| 455 | } | ||
| 456 | |||
| 457 | void INTERFACE_ATTRIBUTE | ||
| 458 | AnnotateMemoryIsInitialized(char *f, int l, uptr mem, uptr sz) {} | ||
| 459 | void INTERFACE_ATTRIBUTE | ||
| 460 | AnnotateMemoryIsUninitialized(char *f, int l, uptr mem, uptr sz) {} | ||
| 461 | |||
| 462 | // Note: the parameter is called flagz, because flags is already taken | ||
| 463 | // by the global function that returns flags. | ||
| 464 | INTERFACE_ATTRIBUTE | ||
| 465 | void __tsan_mutex_create(void *m, unsigned flagz) { | ||
| 466 | SCOPED_ANNOTATION(__tsan_mutex_create); | ||
| 467 | MutexCreate(thr, pc, (uptr)m, flagz & MutexCreationFlagMask); | ||
| 468 | } | ||
| 469 | |||
| 470 | INTERFACE_ATTRIBUTE | ||
| 471 | void __tsan_mutex_destroy(void *m, unsigned flagz) { | ||
| 472 | SCOPED_ANNOTATION(__tsan_mutex_destroy); | ||
| 473 | MutexDestroy(thr, pc, (uptr)m, flagz); | ||
| 474 | } | ||
| 475 | |||
| 476 | INTERFACE_ATTRIBUTE | ||
| 477 | void __tsan_mutex_pre_lock(void *m, unsigned flagz) { | ||
| 478 | SCOPED_ANNOTATION(__tsan_mutex_pre_lock); | ||
| 479 | if (!(flagz & MutexFlagTryLock)) { | ||
| 480 | if (flagz & MutexFlagReadLock) | ||
| 481 | MutexPreReadLock(thr, pc, (uptr)m); | ||
| 482 | else | ||
| 483 | MutexPreLock(thr, pc, (uptr)m); | ||
| 484 | } | ||
| 485 | ThreadIgnoreBegin(thr, pc, /*save_stack=*/false); | ||
| 486 | ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false); | ||
| 487 | } | ||
| 488 | |||
| 489 | INTERFACE_ATTRIBUTE | ||
| 490 | void __tsan_mutex_post_lock(void *m, unsigned flagz, int rec) { | ||
| 491 | SCOPED_ANNOTATION(__tsan_mutex_post_lock); | ||
| 492 | ThreadIgnoreSyncEnd(thr, pc); | ||
| 493 | ThreadIgnoreEnd(thr, pc); | ||
| 494 | if (!(flagz & MutexFlagTryLockFailed)) { | ||
| 495 | if (flagz & MutexFlagReadLock) | ||
| 496 | MutexPostReadLock(thr, pc, (uptr)m, flagz); | ||
| 497 | else | ||
| 498 | MutexPostLock(thr, pc, (uptr)m, flagz, rec); | ||
| 499 | } | ||
| 500 | } | ||
| 501 | |||
| 502 | INTERFACE_ATTRIBUTE | ||
| 503 | int __tsan_mutex_pre_unlock(void *m, unsigned flagz) { | ||
| 504 | SCOPED_ANNOTATION_RET(__tsan_mutex_pre_unlock, 0); | ||
| 505 | int ret = 0; | ||
| 506 | if (flagz & MutexFlagReadLock) { | ||
| 507 | CHECK(!(flagz & MutexFlagRecursiveUnlock)); | ||
| 508 | MutexReadUnlock(thr, pc, (uptr)m); | ||
| 509 | } else { | ||
| 510 | ret = MutexUnlock(thr, pc, (uptr)m, flagz); | ||
| 511 | } | ||
| 512 | ThreadIgnoreBegin(thr, pc, /*save_stack=*/false); | ||
| 513 | ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false); | ||
| 514 | return ret; | ||
| 515 | } | ||
| 516 | |||
| 517 | INTERFACE_ATTRIBUTE | ||
| 518 | void __tsan_mutex_post_unlock(void *m, unsigned flagz) { | ||
| 519 | SCOPED_ANNOTATION(__tsan_mutex_post_unlock); | ||
| 520 | ThreadIgnoreSyncEnd(thr, pc); | ||
| 521 | ThreadIgnoreEnd(thr, pc); | ||
| 522 | } | ||
| 523 | |||
| 524 | INTERFACE_ATTRIBUTE | ||
| 525 | void __tsan_mutex_pre_signal(void *addr, unsigned flagz) { | ||
| 526 | SCOPED_ANNOTATION(__tsan_mutex_pre_signal); | ||
| 527 | ThreadIgnoreBegin(thr, pc, /*save_stack=*/false); | ||
| 528 | ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false); | ||
| 529 | } | ||
| 530 | |||
| 531 | INTERFACE_ATTRIBUTE | ||
| 532 | void __tsan_mutex_post_signal(void *addr, unsigned flagz) { | ||
| 533 | SCOPED_ANNOTATION(__tsan_mutex_post_signal); | ||
| 534 | ThreadIgnoreSyncEnd(thr, pc); | ||
| 535 | ThreadIgnoreEnd(thr, pc); | ||
| 536 | } | ||
| 537 | |||
| 538 | INTERFACE_ATTRIBUTE | ||
| 539 | void __tsan_mutex_pre_divert(void *addr, unsigned flagz) { | ||
| 540 | SCOPED_ANNOTATION(__tsan_mutex_pre_divert); | ||
| 541 | // Exit from ignore region started in __tsan_mutex_pre_lock/unlock/signal. | ||
| 542 | ThreadIgnoreSyncEnd(thr, pc); | ||
| 543 | ThreadIgnoreEnd(thr, pc); | ||
| 544 | } | ||
| 545 | |||
| 546 | INTERFACE_ATTRIBUTE | ||
| 547 | void __tsan_mutex_post_divert(void *addr, unsigned flagz) { | ||
| 548 | SCOPED_ANNOTATION(__tsan_mutex_post_divert); | ||
| 549 | ThreadIgnoreBegin(thr, pc, /*save_stack=*/false); | ||
| 550 | ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false); | ||
| 551 | } | ||
| 552 | } // extern "C" | ||
lib/tsan/tsan_interface_ann.h created+32| ... | @@ -0,0 +1,32 @@ | ||
| 1 | //===-- tsan_interface_ann.h ------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | // Interface for dynamic annotations. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | #ifndef TSAN_INTERFACE_ANN_H | ||
| 14 | #define TSAN_INTERFACE_ANN_H | ||
| 15 | |||
| 16 | #include <sanitizer_common/sanitizer_internal_defs.h> | ||
| 17 | |||
| 18 | // This header should NOT include any other headers. | ||
| 19 | // All functions in this header are extern "C" and start with __tsan_. | ||
| 20 | |||
| 21 | #ifdef __cplusplus | ||
| 22 | extern "C" { | ||
| 23 | #endif | ||
| 24 | |||
| 25 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_acquire(void *addr); | ||
| 26 | SANITIZER_INTERFACE_ATTRIBUTE void __tsan_release(void *addr); | ||
| 27 | |||
| 28 | #ifdef __cplusplus | ||
| 29 | } // extern "C" | ||
| 30 | #endif | ||
| 31 | |||
| 32 | #endif // TSAN_INTERFACE_ANN_H | ||
lib/tsan/tsan_interface_atomic.cpp created+955| ... | @@ -0,0 +1,955 @@ | ||
| 1 | //===-- tsan_interface_atomic.cpp -----------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | // ThreadSanitizer atomic operations are based on C++11/C1x standards. | ||
| 14 | // For background see C++11 standard. A slightly older, publicly | ||
| 15 | // available draft of the standard (not entirely up-to-date, but close enough | ||
| 16 | // for casual browsing) is available here: | ||
| 17 | // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf | ||
| 18 | // The following page contains more background information: | ||
| 19 | // http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/ | ||
| 20 | |||
| 21 | #include "sanitizer_common/sanitizer_placement_new.h" | ||
| 22 | #include "sanitizer_common/sanitizer_stacktrace.h" | ||
| 23 | #include "sanitizer_common/sanitizer_mutex.h" | ||
| 24 | #include "tsan_flags.h" | ||
| 25 | #include "tsan_interface.h" | ||
| 26 | #include "tsan_rtl.h" | ||
| 27 | |||
| 28 | using namespace __tsan; | ||
| 29 | |||
| 30 | #if !SANITIZER_GO && __TSAN_HAS_INT128 | ||
| 31 | // Protects emulation of 128-bit atomic operations. | ||
| 32 | static StaticSpinMutex mutex128; | ||
| 33 | #endif | ||
| 34 | |||
| 35 | static bool IsLoadOrder(morder mo) { | ||
| 36 | return mo == mo_relaxed || mo == mo_consume | ||
| 37 | || mo == mo_acquire || mo == mo_seq_cst; | ||
| 38 | } | ||
| 39 | |||
| 40 | static bool IsStoreOrder(morder mo) { | ||
| 41 | return mo == mo_relaxed || mo == mo_release || mo == mo_seq_cst; | ||
| 42 | } | ||
| 43 | |||
| 44 | static bool IsReleaseOrder(morder mo) { | ||
| 45 | return mo == mo_release || mo == mo_acq_rel || mo == mo_seq_cst; | ||
| 46 | } | ||
| 47 | |||
| 48 | static bool IsAcquireOrder(morder mo) { | ||
| 49 | return mo == mo_consume || mo == mo_acquire | ||
| 50 | || mo == mo_acq_rel || mo == mo_seq_cst; | ||
| 51 | } | ||
| 52 | |||
| 53 | static bool IsAcqRelOrder(morder mo) { | ||
| 54 | return mo == mo_acq_rel || mo == mo_seq_cst; | ||
| 55 | } | ||
| 56 | |||
| 57 | template<typename T> T func_xchg(volatile T *v, T op) { | ||
| 58 | T res = __sync_lock_test_and_set(v, op); | ||
| 59 | // __sync_lock_test_and_set does not contain full barrier. | ||
| 60 | __sync_synchronize(); | ||
| 61 | return res; | ||
| 62 | } | ||
| 63 | |||
| 64 | template<typename T> T func_add(volatile T *v, T op) { | ||
| 65 | return __sync_fetch_and_add(v, op); | ||
| 66 | } | ||
| 67 | |||
| 68 | template<typename T> T func_sub(volatile T *v, T op) { | ||
| 69 | return __sync_fetch_and_sub(v, op); | ||
| 70 | } | ||
| 71 | |||
| 72 | template<typename T> T func_and(volatile T *v, T op) { | ||
| 73 | return __sync_fetch_and_and(v, op); | ||
| 74 | } | ||
| 75 | |||
| 76 | template<typename T> T func_or(volatile T *v, T op) { | ||
| 77 | return __sync_fetch_and_or(v, op); | ||
| 78 | } | ||
| 79 | |||
| 80 | template<typename T> T func_xor(volatile T *v, T op) { | ||
| 81 | return __sync_fetch_and_xor(v, op); | ||
| 82 | } | ||
| 83 | |||
| 84 | template<typename T> T func_nand(volatile T *v, T op) { | ||
| 85 | // clang does not support __sync_fetch_and_nand. | ||
| 86 | T cmp = *v; | ||
| 87 | for (;;) { | ||
| 88 | T newv = ~(cmp & op); | ||
| 89 | T cur = __sync_val_compare_and_swap(v, cmp, newv); | ||
| 90 | if (cmp == cur) | ||
| 91 | return cmp; | ||
| 92 | cmp = cur; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | template<typename T> T func_cas(volatile T *v, T cmp, T xch) { | ||
| 97 | return __sync_val_compare_and_swap(v, cmp, xch); | ||
| 98 | } | ||
| 99 | |||
| 100 | // clang does not support 128-bit atomic ops. | ||
| 101 | // Atomic ops are executed under tsan internal mutex, | ||
| 102 | // here we assume that the atomic variables are not accessed | ||
| 103 | // from non-instrumented code. | ||
| 104 | #if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) && !SANITIZER_GO \ | ||
| 105 | && __TSAN_HAS_INT128 | ||
| 106 | a128 func_xchg(volatile a128 *v, a128 op) { | ||
| 107 | SpinMutexLock lock(&mutex128); | ||
| 108 | a128 cmp = *v; | ||
| 109 | *v = op; | ||
| 110 | return cmp; | ||
| 111 | } | ||
| 112 | |||
| 113 | a128 func_add(volatile a128 *v, a128 op) { | ||
| 114 | SpinMutexLock lock(&mutex128); | ||
| 115 | a128 cmp = *v; | ||
| 116 | *v = cmp + op; | ||
| 117 | return cmp; | ||
| 118 | } | ||
| 119 | |||
| 120 | a128 func_sub(volatile a128 *v, a128 op) { | ||
| 121 | SpinMutexLock lock(&mutex128); | ||
| 122 | a128 cmp = *v; | ||
| 123 | *v = cmp - op; | ||
| 124 | return cmp; | ||
| 125 | } | ||
| 126 | |||
| 127 | a128 func_and(volatile a128 *v, a128 op) { | ||
| 128 | SpinMutexLock lock(&mutex128); | ||
| 129 | a128 cmp = *v; | ||
| 130 | *v = cmp & op; | ||
| 131 | return cmp; | ||
| 132 | } | ||
| 133 | |||
| 134 | a128 func_or(volatile a128 *v, a128 op) { | ||
| 135 | SpinMutexLock lock(&mutex128); | ||
| 136 | a128 cmp = *v; | ||
| 137 | *v = cmp | op; | ||
| 138 | return cmp; | ||
| 139 | } | ||
| 140 | |||
| 141 | a128 func_xor(volatile a128 *v, a128 op) { | ||
| 142 | SpinMutexLock lock(&mutex128); | ||
| 143 | a128 cmp = *v; | ||
| 144 | *v = cmp ^ op; | ||
| 145 | return cmp; | ||
| 146 | } | ||
| 147 | |||
| 148 | a128 func_nand(volatile a128 *v, a128 op) { | ||
| 149 | SpinMutexLock lock(&mutex128); | ||
| 150 | a128 cmp = *v; | ||
| 151 | *v = ~(cmp & op); | ||
| 152 | return cmp; | ||
| 153 | } | ||
| 154 | |||
| 155 | a128 func_cas(volatile a128 *v, a128 cmp, a128 xch) { | ||
| 156 | SpinMutexLock lock(&mutex128); | ||
| 157 | a128 cur = *v; | ||
| 158 | if (cur == cmp) | ||
| 159 | *v = xch; | ||
| 160 | return cur; | ||
| 161 | } | ||
| 162 | #endif | ||
| 163 | |||
| 164 | template<typename T> | ||
| 165 | static int SizeLog() { | ||
| 166 | if (sizeof(T) <= 1) | ||
| 167 | return kSizeLog1; | ||
| 168 | else if (sizeof(T) <= 2) | ||
| 169 | return kSizeLog2; | ||
| 170 | else if (sizeof(T) <= 4) | ||
| 171 | return kSizeLog4; | ||
| 172 | else | ||
| 173 | return kSizeLog8; | ||
| 174 | // For 16-byte atomics we also use 8-byte memory access, | ||
| 175 | // this leads to false negatives only in very obscure cases. | ||
| 176 | } | ||
| 177 | |||
| 178 | #if !SANITIZER_GO | ||
| 179 | static atomic_uint8_t *to_atomic(const volatile a8 *a) { | ||
| 180 | return reinterpret_cast<atomic_uint8_t *>(const_cast<a8 *>(a)); | ||
| 181 | } | ||
| 182 | |||
| 183 | static atomic_uint16_t *to_atomic(const volatile a16 *a) { | ||
| 184 | return reinterpret_cast<atomic_uint16_t *>(const_cast<a16 *>(a)); | ||
| 185 | } | ||
| 186 | #endif | ||
| 187 | |||
| 188 | static atomic_uint32_t *to_atomic(const volatile a32 *a) { | ||
| 189 | return reinterpret_cast<atomic_uint32_t *>(const_cast<a32 *>(a)); | ||
| 190 | } | ||
| 191 | |||
| 192 | static atomic_uint64_t *to_atomic(const volatile a64 *a) { | ||
| 193 | return reinterpret_cast<atomic_uint64_t *>(const_cast<a64 *>(a)); | ||
| 194 | } | ||
| 195 | |||
| 196 | static memory_order to_mo(morder mo) { | ||
| 197 | switch (mo) { | ||
| 198 | case mo_relaxed: return memory_order_relaxed; | ||
| 199 | case mo_consume: return memory_order_consume; | ||
| 200 | case mo_acquire: return memory_order_acquire; | ||
| 201 | case mo_release: return memory_order_release; | ||
| 202 | case mo_acq_rel: return memory_order_acq_rel; | ||
| 203 | case mo_seq_cst: return memory_order_seq_cst; | ||
| 204 | } | ||
| 205 | CHECK(0); | ||
| 206 | return memory_order_seq_cst; | ||
| 207 | } | ||
| 208 | |||
| 209 | template<typename T> | ||
| 210 | static T NoTsanAtomicLoad(const volatile T *a, morder mo) { | ||
| 211 | return atomic_load(to_atomic(a), to_mo(mo)); | ||
| 212 | } | ||
| 213 | |||
| 214 | #if __TSAN_HAS_INT128 && !SANITIZER_GO | ||
| 215 | static a128 NoTsanAtomicLoad(const volatile a128 *a, morder mo) { | ||
| 216 | SpinMutexLock lock(&mutex128); | ||
| 217 | return *a; | ||
| 218 | } | ||
| 219 | #endif | ||
| 220 | |||
| 221 | template<typename T> | ||
| 222 | static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a, morder mo) { | ||
| 223 | CHECK(IsLoadOrder(mo)); | ||
| 224 | // This fast-path is critical for performance. | ||
| 225 | // Assume the access is atomic. | ||
| 226 | if (!IsAcquireOrder(mo)) { | ||
| 227 | MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>()); | ||
| 228 | return NoTsanAtomicLoad(a, mo); | ||
| 229 | } | ||
| 230 | // Don't create sync object if it does not exist yet. For example, an atomic | ||
| 231 | // pointer is initialized to nullptr and then periodically acquire-loaded. | ||
| 232 | T v = NoTsanAtomicLoad(a, mo); | ||
| 233 | SyncVar *s = ctx->metamap.GetIfExistsAndLock((uptr)a, false); | ||
| 234 | if (s) { | ||
| 235 | AcquireImpl(thr, pc, &s->clock); | ||
| 236 | // Re-read under sync mutex because we need a consistent snapshot | ||
| 237 | // of the value and the clock we acquire. | ||
| 238 | v = NoTsanAtomicLoad(a, mo); | ||
| 239 | s->mtx.ReadUnlock(); | ||
| 240 | } | ||
| 241 | MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>()); | ||
| 242 | return v; | ||
| 243 | } | ||
| 244 | |||
| 245 | template<typename T> | ||
| 246 | static void NoTsanAtomicStore(volatile T *a, T v, morder mo) { | ||
| 247 | atomic_store(to_atomic(a), v, to_mo(mo)); | ||
| 248 | } | ||
| 249 | |||
| 250 | #if __TSAN_HAS_INT128 && !SANITIZER_GO | ||
| 251 | static void NoTsanAtomicStore(volatile a128 *a, a128 v, morder mo) { | ||
| 252 | SpinMutexLock lock(&mutex128); | ||
| 253 | *a = v; | ||
| 254 | } | ||
| 255 | #endif | ||
| 256 | |||
| 257 | template<typename T> | ||
| 258 | static void AtomicStore(ThreadState *thr, uptr pc, volatile T *a, T v, | ||
| 259 | morder mo) { | ||
| 260 | CHECK(IsStoreOrder(mo)); | ||
| 261 | MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>()); | ||
| 262 | // This fast-path is critical for performance. | ||
| 263 | // Assume the access is atomic. | ||
| 264 | // Strictly saying even relaxed store cuts off release sequence, | ||
| 265 | // so must reset the clock. | ||
| 266 | if (!IsReleaseOrder(mo)) { | ||
| 267 | NoTsanAtomicStore(a, v, mo); | ||
| 268 | return; | ||
| 269 | } | ||
| 270 | __sync_synchronize(); | ||
| 271 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, true); | ||
| 272 | thr->fast_state.IncrementEpoch(); | ||
| 273 | // Can't increment epoch w/o writing to the trace as well. | ||
| 274 | TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); | ||
| 275 | ReleaseStoreImpl(thr, pc, &s->clock); | ||
| 276 | NoTsanAtomicStore(a, v, mo); | ||
| 277 | s->mtx.Unlock(); | ||
| 278 | } | ||
| 279 | |||
| 280 | template<typename T, T (*F)(volatile T *v, T op)> | ||
| 281 | static T AtomicRMW(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) { | ||
| 282 | MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>()); | ||
| 283 | SyncVar *s = 0; | ||
| 284 | if (mo != mo_relaxed) { | ||
| 285 | s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, true); | ||
| 286 | thr->fast_state.IncrementEpoch(); | ||
| 287 | // Can't increment epoch w/o writing to the trace as well. | ||
| 288 | TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); | ||
| 289 | if (IsAcqRelOrder(mo)) | ||
| 290 | AcquireReleaseImpl(thr, pc, &s->clock); | ||
| 291 | else if (IsReleaseOrder(mo)) | ||
| 292 | ReleaseImpl(thr, pc, &s->clock); | ||
| 293 | else if (IsAcquireOrder(mo)) | ||
| 294 | AcquireImpl(thr, pc, &s->clock); | ||
| 295 | } | ||
| 296 | v = F(a, v); | ||
| 297 | if (s) | ||
| 298 | s->mtx.Unlock(); | ||
| 299 | return v; | ||
| 300 | } | ||
| 301 | |||
| 302 | template<typename T> | ||
| 303 | static T NoTsanAtomicExchange(volatile T *a, T v, morder mo) { | ||
| 304 | return func_xchg(a, v); | ||
| 305 | } | ||
| 306 | |||
| 307 | template<typename T> | ||
| 308 | static T NoTsanAtomicFetchAdd(volatile T *a, T v, morder mo) { | ||
| 309 | return func_add(a, v); | ||
| 310 | } | ||
| 311 | |||
| 312 | template<typename T> | ||
| 313 | static T NoTsanAtomicFetchSub(volatile T *a, T v, morder mo) { | ||
| 314 | return func_sub(a, v); | ||
| 315 | } | ||
| 316 | |||
| 317 | template<typename T> | ||
| 318 | static T NoTsanAtomicFetchAnd(volatile T *a, T v, morder mo) { | ||
| 319 | return func_and(a, v); | ||
| 320 | } | ||
| 321 | |||
| 322 | template<typename T> | ||
| 323 | static T NoTsanAtomicFetchOr(volatile T *a, T v, morder mo) { | ||
| 324 | return func_or(a, v); | ||
| 325 | } | ||
| 326 | |||
| 327 | template<typename T> | ||
| 328 | static T NoTsanAtomicFetchXor(volatile T *a, T v, morder mo) { | ||
| 329 | return func_xor(a, v); | ||
| 330 | } | ||
| 331 | |||
| 332 | template<typename T> | ||
| 333 | static T NoTsanAtomicFetchNand(volatile T *a, T v, morder mo) { | ||
| 334 | return func_nand(a, v); | ||
| 335 | } | ||
| 336 | |||
| 337 | template<typename T> | ||
| 338 | static T AtomicExchange(ThreadState *thr, uptr pc, volatile T *a, T v, | ||
| 339 | morder mo) { | ||
| 340 | return AtomicRMW<T, func_xchg>(thr, pc, a, v, mo); | ||
| 341 | } | ||
| 342 | |||
| 343 | template<typename T> | ||
| 344 | static T AtomicFetchAdd(ThreadState *thr, uptr pc, volatile T *a, T v, | ||
| 345 | morder mo) { | ||
| 346 | return AtomicRMW<T, func_add>(thr, pc, a, v, mo); | ||
| 347 | } | ||
| 348 | |||
| 349 | template<typename T> | ||
| 350 | static T AtomicFetchSub(ThreadState *thr, uptr pc, volatile T *a, T v, | ||
| 351 | morder mo) { | ||
| 352 | return AtomicRMW<T, func_sub>(thr, pc, a, v, mo); | ||
| 353 | } | ||
| 354 | |||
| 355 | template<typename T> | ||
| 356 | static T AtomicFetchAnd(ThreadState *thr, uptr pc, volatile T *a, T v, | ||
| 357 | morder mo) { | ||
| 358 | return AtomicRMW<T, func_and>(thr, pc, a, v, mo); | ||
| 359 | } | ||
| 360 | |||
| 361 | template<typename T> | ||
| 362 | static T AtomicFetchOr(ThreadState *thr, uptr pc, volatile T *a, T v, | ||
| 363 | morder mo) { | ||
| 364 | return AtomicRMW<T, func_or>(thr, pc, a, v, mo); | ||
| 365 | } | ||
| 366 | |||
| 367 | template<typename T> | ||
| 368 | static T AtomicFetchXor(ThreadState *thr, uptr pc, volatile T *a, T v, | ||
| 369 | morder mo) { | ||
| 370 | return AtomicRMW<T, func_xor>(thr, pc, a, v, mo); | ||
| 371 | } | ||
| 372 | |||
| 373 | template<typename T> | ||
| 374 | static T AtomicFetchNand(ThreadState *thr, uptr pc, volatile T *a, T v, | ||
| 375 | morder mo) { | ||
| 376 | return AtomicRMW<T, func_nand>(thr, pc, a, v, mo); | ||
| 377 | } | ||
| 378 | |||
| 379 | template<typename T> | ||
| 380 | static bool NoTsanAtomicCAS(volatile T *a, T *c, T v, morder mo, morder fmo) { | ||
| 381 | return atomic_compare_exchange_strong(to_atomic(a), c, v, to_mo(mo)); | ||
| 382 | } | ||
| 383 | |||
| 384 | #if __TSAN_HAS_INT128 | ||
| 385 | static bool NoTsanAtomicCAS(volatile a128 *a, a128 *c, a128 v, | ||
| 386 | morder mo, morder fmo) { | ||
| 387 | a128 old = *c; | ||
| 388 | a128 cur = func_cas(a, old, v); | ||
| 389 | if (cur == old) | ||
| 390 | return true; | ||
| 391 | *c = cur; | ||
| 392 | return false; | ||
| 393 | } | ||
| 394 | #endif | ||
| 395 | |||
| 396 | template<typename T> | ||
| 397 | static T NoTsanAtomicCAS(volatile T *a, T c, T v, morder mo, morder fmo) { | ||
| 398 | NoTsanAtomicCAS(a, &c, v, mo, fmo); | ||
| 399 | return c; | ||
| 400 | } | ||
| 401 | |||
| 402 | template<typename T> | ||
| 403 | static bool AtomicCAS(ThreadState *thr, uptr pc, | ||
| 404 | volatile T *a, T *c, T v, morder mo, morder fmo) { | ||
| 405 | (void)fmo; // Unused because llvm does not pass it yet. | ||
| 406 | MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>()); | ||
| 407 | SyncVar *s = 0; | ||
| 408 | bool write_lock = mo != mo_acquire && mo != mo_consume; | ||
| 409 | if (mo != mo_relaxed) { | ||
| 410 | s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, write_lock); | ||
| 411 | thr->fast_state.IncrementEpoch(); | ||
| 412 | // Can't increment epoch w/o writing to the trace as well. | ||
| 413 | TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); | ||
| 414 | if (IsAcqRelOrder(mo)) | ||
| 415 | AcquireReleaseImpl(thr, pc, &s->clock); | ||
| 416 | else if (IsReleaseOrder(mo)) | ||
| 417 | ReleaseImpl(thr, pc, &s->clock); | ||
| 418 | else if (IsAcquireOrder(mo)) | ||
| 419 | AcquireImpl(thr, pc, &s->clock); | ||
| 420 | } | ||
| 421 | T cc = *c; | ||
| 422 | T pr = func_cas(a, cc, v); | ||
| 423 | if (s) { | ||
| 424 | if (write_lock) | ||
| 425 | s->mtx.Unlock(); | ||
| 426 | else | ||
| 427 | s->mtx.ReadUnlock(); | ||
| 428 | } | ||
| 429 | if (pr == cc) | ||
| 430 | return true; | ||
| 431 | *c = pr; | ||
| 432 | return false; | ||
| 433 | } | ||
| 434 | |||
| 435 | template<typename T> | ||
| 436 | static T AtomicCAS(ThreadState *thr, uptr pc, | ||
| 437 | volatile T *a, T c, T v, morder mo, morder fmo) { | ||
| 438 | AtomicCAS(thr, pc, a, &c, v, mo, fmo); | ||
| 439 | return c; | ||
| 440 | } | ||
| 441 | |||
| 442 | #if !SANITIZER_GO | ||
| 443 | static void NoTsanAtomicFence(morder mo) { | ||
| 444 | __sync_synchronize(); | ||
| 445 | } | ||
| 446 | |||
| 447 | static void AtomicFence(ThreadState *thr, uptr pc, morder mo) { | ||
| 448 | // FIXME(dvyukov): not implemented. | ||
| 449 | __sync_synchronize(); | ||
| 450 | } | ||
| 451 | #endif | ||
| 452 | |||
| 453 | // Interface functions follow. | ||
| 454 | #if !SANITIZER_GO | ||
| 455 | |||
| 456 | // C/C++ | ||
| 457 | |||
| 458 | static morder convert_morder(morder mo) { | ||
| 459 | if (flags()->force_seq_cst_atomics) | ||
| 460 | return (morder)mo_seq_cst; | ||
| 461 | |||
| 462 | // Filter out additional memory order flags: | ||
| 463 | // MEMMODEL_SYNC = 1 << 15 | ||
| 464 | // __ATOMIC_HLE_ACQUIRE = 1 << 16 | ||
| 465 | // __ATOMIC_HLE_RELEASE = 1 << 17 | ||
| 466 | // | ||
| 467 | // HLE is an optimization, and we pretend that elision always fails. | ||
| 468 | // MEMMODEL_SYNC is used when lowering __sync_ atomics, | ||
| 469 | // since we use __sync_ atomics for actual atomic operations, | ||
| 470 | // we can safely ignore it as well. It also subtly affects semantics, | ||
| 471 | // but we don't model the difference. | ||
| 472 | return (morder)(mo & 0x7fff); | ||
| 473 | } | ||
| 474 | |||
| 475 | #define SCOPED_ATOMIC(func, ...) \ | ||
| 476 | ThreadState *const thr = cur_thread(); \ | ||
| 477 | if (UNLIKELY(thr->ignore_sync || thr->ignore_interceptors)) { \ | ||
| 478 | ProcessPendingSignals(thr); \ | ||
| 479 | return NoTsanAtomic##func(__VA_ARGS__); \ | ||
| 480 | } \ | ||
| 481 | const uptr callpc = (uptr)__builtin_return_address(0); \ | ||
| 482 | uptr pc = StackTrace::GetCurrentPc(); \ | ||
| 483 | mo = convert_morder(mo); \ | ||
| 484 | AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \ | ||
| 485 | ScopedAtomic sa(thr, callpc, a, mo, __func__); \ | ||
| 486 | return Atomic##func(thr, pc, __VA_ARGS__); \ | ||
| 487 | /**/ | ||
| 488 | |||
| 489 | class ScopedAtomic { | ||
| 490 | public: | ||
| 491 | ScopedAtomic(ThreadState *thr, uptr pc, const volatile void *a, | ||
| 492 | morder mo, const char *func) | ||
| 493 | : thr_(thr) { | ||
| 494 | FuncEntry(thr_, pc); | ||
| 495 | DPrintf("#%d: %s(%p, %d)\n", thr_->tid, func, a, mo); | ||
| 496 | } | ||
| 497 | ~ScopedAtomic() { | ||
| 498 | ProcessPendingSignals(thr_); | ||
| 499 | FuncExit(thr_); | ||
| 500 | } | ||
| 501 | private: | ||
| 502 | ThreadState *thr_; | ||
| 503 | }; | ||
| 504 | |||
| 505 | static void AtomicStatInc(ThreadState *thr, uptr size, morder mo, StatType t) { | ||
| 506 | StatInc(thr, StatAtomic); | ||
| 507 | StatInc(thr, t); | ||
| 508 | StatInc(thr, size == 1 ? StatAtomic1 | ||
| 509 | : size == 2 ? StatAtomic2 | ||
| 510 | : size == 4 ? StatAtomic4 | ||
| 511 | : size == 8 ? StatAtomic8 | ||
| 512 | : StatAtomic16); | ||
| 513 | StatInc(thr, mo == mo_relaxed ? StatAtomicRelaxed | ||
| 514 | : mo == mo_consume ? StatAtomicConsume | ||
| 515 | : mo == mo_acquire ? StatAtomicAcquire | ||
| 516 | : mo == mo_release ? StatAtomicRelease | ||
| 517 | : mo == mo_acq_rel ? StatAtomicAcq_Rel | ||
| 518 | : StatAtomicSeq_Cst); | ||
| 519 | } | ||
| 520 | |||
| 521 | extern "C" { | ||
| 522 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 523 | a8 __tsan_atomic8_load(const volatile a8 *a, morder mo) { | ||
| 524 | SCOPED_ATOMIC(Load, a, mo); | ||
| 525 | } | ||
| 526 | |||
| 527 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 528 | a16 __tsan_atomic16_load(const volatile a16 *a, morder mo) { | ||
| 529 | SCOPED_ATOMIC(Load, a, mo); | ||
| 530 | } | ||
| 531 | |||
| 532 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 533 | a32 __tsan_atomic32_load(const volatile a32 *a, morder mo) { | ||
| 534 | SCOPED_ATOMIC(Load, a, mo); | ||
| 535 | } | ||
| 536 | |||
| 537 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 538 | a64 __tsan_atomic64_load(const volatile a64 *a, morder mo) { | ||
| 539 | SCOPED_ATOMIC(Load, a, mo); | ||
| 540 | } | ||
| 541 | |||
| 542 | #if __TSAN_HAS_INT128 | ||
| 543 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 544 | a128 __tsan_atomic128_load(const volatile a128 *a, morder mo) { | ||
| 545 | SCOPED_ATOMIC(Load, a, mo); | ||
| 546 | } | ||
| 547 | #endif | ||
| 548 | |||
| 549 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 550 | void __tsan_atomic8_store(volatile a8 *a, a8 v, morder mo) { | ||
| 551 | SCOPED_ATOMIC(Store, a, v, mo); | ||
| 552 | } | ||
| 553 | |||
| 554 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 555 | void __tsan_atomic16_store(volatile a16 *a, a16 v, morder mo) { | ||
| 556 | SCOPED_ATOMIC(Store, a, v, mo); | ||
| 557 | } | ||
| 558 | |||
| 559 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 560 | void __tsan_atomic32_store(volatile a32 *a, a32 v, morder mo) { | ||
| 561 | SCOPED_ATOMIC(Store, a, v, mo); | ||
| 562 | } | ||
| 563 | |||
| 564 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 565 | void __tsan_atomic64_store(volatile a64 *a, a64 v, morder mo) { | ||
| 566 | SCOPED_ATOMIC(Store, a, v, mo); | ||
| 567 | } | ||
| 568 | |||
| 569 | #if __TSAN_HAS_INT128 | ||
| 570 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 571 | void __tsan_atomic128_store(volatile a128 *a, a128 v, morder mo) { | ||
| 572 | SCOPED_ATOMIC(Store, a, v, mo); | ||
| 573 | } | ||
| 574 | #endif | ||
| 575 | |||
| 576 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 577 | a8 __tsan_atomic8_exchange(volatile a8 *a, a8 v, morder mo) { | ||
| 578 | SCOPED_ATOMIC(Exchange, a, v, mo); | ||
| 579 | } | ||
| 580 | |||
| 581 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 582 | a16 __tsan_atomic16_exchange(volatile a16 *a, a16 v, morder mo) { | ||
| 583 | SCOPED_ATOMIC(Exchange, a, v, mo); | ||
| 584 | } | ||
| 585 | |||
| 586 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 587 | a32 __tsan_atomic32_exchange(volatile a32 *a, a32 v, morder mo) { | ||
| 588 | SCOPED_ATOMIC(Exchange, a, v, mo); | ||
| 589 | } | ||
| 590 | |||
| 591 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 592 | a64 __tsan_atomic64_exchange(volatile a64 *a, a64 v, morder mo) { | ||
| 593 | SCOPED_ATOMIC(Exchange, a, v, mo); | ||
| 594 | } | ||
| 595 | |||
| 596 | #if __TSAN_HAS_INT128 | ||
| 597 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 598 | a128 __tsan_atomic128_exchange(volatile a128 *a, a128 v, morder mo) { | ||
| 599 | SCOPED_ATOMIC(Exchange, a, v, mo); | ||
| 600 | } | ||
| 601 | #endif | ||
| 602 | |||
| 603 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 604 | a8 __tsan_atomic8_fetch_add(volatile a8 *a, a8 v, morder mo) { | ||
| 605 | SCOPED_ATOMIC(FetchAdd, a, v, mo); | ||
| 606 | } | ||
| 607 | |||
| 608 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 609 | a16 __tsan_atomic16_fetch_add(volatile a16 *a, a16 v, morder mo) { | ||
| 610 | SCOPED_ATOMIC(FetchAdd, a, v, mo); | ||
| 611 | } | ||
| 612 | |||
| 613 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 614 | a32 __tsan_atomic32_fetch_add(volatile a32 *a, a32 v, morder mo) { | ||
| 615 | SCOPED_ATOMIC(FetchAdd, a, v, mo); | ||
| 616 | } | ||
| 617 | |||
| 618 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 619 | a64 __tsan_atomic64_fetch_add(volatile a64 *a, a64 v, morder mo) { | ||
| 620 | SCOPED_ATOMIC(FetchAdd, a, v, mo); | ||
| 621 | } | ||
| 622 | |||
| 623 | #if __TSAN_HAS_INT128 | ||
| 624 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 625 | a128 __tsan_atomic128_fetch_add(volatile a128 *a, a128 v, morder mo) { | ||
| 626 | SCOPED_ATOMIC(FetchAdd, a, v, mo); | ||
| 627 | } | ||
| 628 | #endif | ||
| 629 | |||
| 630 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 631 | a8 __tsan_atomic8_fetch_sub(volatile a8 *a, a8 v, morder mo) { | ||
| 632 | SCOPED_ATOMIC(FetchSub, a, v, mo); | ||
| 633 | } | ||
| 634 | |||
| 635 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 636 | a16 __tsan_atomic16_fetch_sub(volatile a16 *a, a16 v, morder mo) { | ||
| 637 | SCOPED_ATOMIC(FetchSub, a, v, mo); | ||
| 638 | } | ||
| 639 | |||
| 640 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 641 | a32 __tsan_atomic32_fetch_sub(volatile a32 *a, a32 v, morder mo) { | ||
| 642 | SCOPED_ATOMIC(FetchSub, a, v, mo); | ||
| 643 | } | ||
| 644 | |||
| 645 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 646 | a64 __tsan_atomic64_fetch_sub(volatile a64 *a, a64 v, morder mo) { | ||
| 647 | SCOPED_ATOMIC(FetchSub, a, v, mo); | ||
| 648 | } | ||
| 649 | |||
| 650 | #if __TSAN_HAS_INT128 | ||
| 651 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 652 | a128 __tsan_atomic128_fetch_sub(volatile a128 *a, a128 v, morder mo) { | ||
| 653 | SCOPED_ATOMIC(FetchSub, a, v, mo); | ||
| 654 | } | ||
| 655 | #endif | ||
| 656 | |||
| 657 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 658 | a8 __tsan_atomic8_fetch_and(volatile a8 *a, a8 v, morder mo) { | ||
| 659 | SCOPED_ATOMIC(FetchAnd, a, v, mo); | ||
| 660 | } | ||
| 661 | |||
| 662 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 663 | a16 __tsan_atomic16_fetch_and(volatile a16 *a, a16 v, morder mo) { | ||
| 664 | SCOPED_ATOMIC(FetchAnd, a, v, mo); | ||
| 665 | } | ||
| 666 | |||
| 667 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 668 | a32 __tsan_atomic32_fetch_and(volatile a32 *a, a32 v, morder mo) { | ||
| 669 | SCOPED_ATOMIC(FetchAnd, a, v, mo); | ||
| 670 | } | ||
| 671 | |||
| 672 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 673 | a64 __tsan_atomic64_fetch_and(volatile a64 *a, a64 v, morder mo) { | ||
| 674 | SCOPED_ATOMIC(FetchAnd, a, v, mo); | ||
| 675 | } | ||
| 676 | |||
| 677 | #if __TSAN_HAS_INT128 | ||
| 678 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 679 | a128 __tsan_atomic128_fetch_and(volatile a128 *a, a128 v, morder mo) { | ||
| 680 | SCOPED_ATOMIC(FetchAnd, a, v, mo); | ||
| 681 | } | ||
| 682 | #endif | ||
| 683 | |||
| 684 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 685 | a8 __tsan_atomic8_fetch_or(volatile a8 *a, a8 v, morder mo) { | ||
| 686 | SCOPED_ATOMIC(FetchOr, a, v, mo); | ||
| 687 | } | ||
| 688 | |||
| 689 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 690 | a16 __tsan_atomic16_fetch_or(volatile a16 *a, a16 v, morder mo) { | ||
| 691 | SCOPED_ATOMIC(FetchOr, a, v, mo); | ||
| 692 | } | ||
| 693 | |||
| 694 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 695 | a32 __tsan_atomic32_fetch_or(volatile a32 *a, a32 v, morder mo) { | ||
| 696 | SCOPED_ATOMIC(FetchOr, a, v, mo); | ||
| 697 | } | ||
| 698 | |||
| 699 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 700 | a64 __tsan_atomic64_fetch_or(volatile a64 *a, a64 v, morder mo) { | ||
| 701 | SCOPED_ATOMIC(FetchOr, a, v, mo); | ||
| 702 | } | ||
| 703 | |||
| 704 | #if __TSAN_HAS_INT128 | ||
| 705 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 706 | a128 __tsan_atomic128_fetch_or(volatile a128 *a, a128 v, morder mo) { | ||
| 707 | SCOPED_ATOMIC(FetchOr, a, v, mo); | ||
| 708 | } | ||
| 709 | #endif | ||
| 710 | |||
| 711 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 712 | a8 __tsan_atomic8_fetch_xor(volatile a8 *a, a8 v, morder mo) { | ||
| 713 | SCOPED_ATOMIC(FetchXor, a, v, mo); | ||
| 714 | } | ||
| 715 | |||
| 716 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 717 | a16 __tsan_atomic16_fetch_xor(volatile a16 *a, a16 v, morder mo) { | ||
| 718 | SCOPED_ATOMIC(FetchXor, a, v, mo); | ||
| 719 | } | ||
| 720 | |||
| 721 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 722 | a32 __tsan_atomic32_fetch_xor(volatile a32 *a, a32 v, morder mo) { | ||
| 723 | SCOPED_ATOMIC(FetchXor, a, v, mo); | ||
| 724 | } | ||
| 725 | |||
| 726 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 727 | a64 __tsan_atomic64_fetch_xor(volatile a64 *a, a64 v, morder mo) { | ||
| 728 | SCOPED_ATOMIC(FetchXor, a, v, mo); | ||
| 729 | } | ||
| 730 | |||
| 731 | #if __TSAN_HAS_INT128 | ||
| 732 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 733 | a128 __tsan_atomic128_fetch_xor(volatile a128 *a, a128 v, morder mo) { | ||
| 734 | SCOPED_ATOMIC(FetchXor, a, v, mo); | ||
| 735 | } | ||
| 736 | #endif | ||
| 737 | |||
| 738 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 739 | a8 __tsan_atomic8_fetch_nand(volatile a8 *a, a8 v, morder mo) { | ||
| 740 | SCOPED_ATOMIC(FetchNand, a, v, mo); | ||
| 741 | } | ||
| 742 | |||
| 743 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 744 | a16 __tsan_atomic16_fetch_nand(volatile a16 *a, a16 v, morder mo) { | ||
| 745 | SCOPED_ATOMIC(FetchNand, a, v, mo); | ||
| 746 | } | ||
| 747 | |||
| 748 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 749 | a32 __tsan_atomic32_fetch_nand(volatile a32 *a, a32 v, morder mo) { | ||
| 750 | SCOPED_ATOMIC(FetchNand, a, v, mo); | ||
| 751 | } | ||
| 752 | |||
| 753 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 754 | a64 __tsan_atomic64_fetch_nand(volatile a64 *a, a64 v, morder mo) { | ||
| 755 | SCOPED_ATOMIC(FetchNand, a, v, mo); | ||
| 756 | } | ||
| 757 | |||
| 758 | #if __TSAN_HAS_INT128 | ||
| 759 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 760 | a128 __tsan_atomic128_fetch_nand(volatile a128 *a, a128 v, morder mo) { | ||
| 761 | SCOPED_ATOMIC(FetchNand, a, v, mo); | ||
| 762 | } | ||
| 763 | #endif | ||
| 764 | |||
| 765 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 766 | int __tsan_atomic8_compare_exchange_strong(volatile a8 *a, a8 *c, a8 v, | ||
| 767 | morder mo, morder fmo) { | ||
| 768 | SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); | ||
| 769 | } | ||
| 770 | |||
| 771 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 772 | int __tsan_atomic16_compare_exchange_strong(volatile a16 *a, a16 *c, a16 v, | ||
| 773 | morder mo, morder fmo) { | ||
| 774 | SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); | ||
| 775 | } | ||
| 776 | |||
| 777 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 778 | int __tsan_atomic32_compare_exchange_strong(volatile a32 *a, a32 *c, a32 v, | ||
| 779 | morder mo, morder fmo) { | ||
| 780 | SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); | ||
| 781 | } | ||
| 782 | |||
| 783 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 784 | int __tsan_atomic64_compare_exchange_strong(volatile a64 *a, a64 *c, a64 v, | ||
| 785 | morder mo, morder fmo) { | ||
| 786 | SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); | ||
| 787 | } | ||
| 788 | |||
| 789 | #if __TSAN_HAS_INT128 | ||
| 790 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 791 | int __tsan_atomic128_compare_exchange_strong(volatile a128 *a, a128 *c, a128 v, | ||
| 792 | morder mo, morder fmo) { | ||
| 793 | SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); | ||
| 794 | } | ||
| 795 | #endif | ||
| 796 | |||
| 797 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 798 | int __tsan_atomic8_compare_exchange_weak(volatile a8 *a, a8 *c, a8 v, | ||
| 799 | morder mo, morder fmo) { | ||
| 800 | SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); | ||
| 801 | } | ||
| 802 | |||
| 803 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 804 | int __tsan_atomic16_compare_exchange_weak(volatile a16 *a, a16 *c, a16 v, | ||
| 805 | morder mo, morder fmo) { | ||
| 806 | SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); | ||
| 807 | } | ||
| 808 | |||
| 809 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 810 | int __tsan_atomic32_compare_exchange_weak(volatile a32 *a, a32 *c, a32 v, | ||
| 811 | morder mo, morder fmo) { | ||
| 812 | SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); | ||
| 813 | } | ||
| 814 | |||
| 815 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 816 | int __tsan_atomic64_compare_exchange_weak(volatile a64 *a, a64 *c, a64 v, | ||
| 817 | morder mo, morder fmo) { | ||
| 818 | SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); | ||
| 819 | } | ||
| 820 | |||
| 821 | #if __TSAN_HAS_INT128 | ||
| 822 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 823 | int __tsan_atomic128_compare_exchange_weak(volatile a128 *a, a128 *c, a128 v, | ||
| 824 | morder mo, morder fmo) { | ||
| 825 | SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); | ||
| 826 | } | ||
| 827 | #endif | ||
| 828 | |||
| 829 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 830 | a8 __tsan_atomic8_compare_exchange_val(volatile a8 *a, a8 c, a8 v, | ||
| 831 | morder mo, morder fmo) { | ||
| 832 | SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); | ||
| 833 | } | ||
| 834 | |||
| 835 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 836 | a16 __tsan_atomic16_compare_exchange_val(volatile a16 *a, a16 c, a16 v, | ||
| 837 | morder mo, morder fmo) { | ||
| 838 | SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); | ||
| 839 | } | ||
| 840 | |||
| 841 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 842 | a32 __tsan_atomic32_compare_exchange_val(volatile a32 *a, a32 c, a32 v, | ||
| 843 | morder mo, morder fmo) { | ||
| 844 | SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); | ||
| 845 | } | ||
| 846 | |||
| 847 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 848 | a64 __tsan_atomic64_compare_exchange_val(volatile a64 *a, a64 c, a64 v, | ||
| 849 | morder mo, morder fmo) { | ||
| 850 | SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); | ||
| 851 | } | ||
| 852 | |||
| 853 | #if __TSAN_HAS_INT128 | ||
| 854 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 855 | a128 __tsan_atomic128_compare_exchange_val(volatile a128 *a, a128 c, a128 v, | ||
| 856 | morder mo, morder fmo) { | ||
| 857 | SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); | ||
| 858 | } | ||
| 859 | #endif | ||
| 860 | |||
| 861 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 862 | void __tsan_atomic_thread_fence(morder mo) { | ||
| 863 | char* a = 0; | ||
| 864 | SCOPED_ATOMIC(Fence, mo); | ||
| 865 | } | ||
| 866 | |||
| 867 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 868 | void __tsan_atomic_signal_fence(morder mo) { | ||
| 869 | } | ||
| 870 | } // extern "C" | ||
| 871 | |||
| 872 | #else // #if !SANITIZER_GO | ||
| 873 | |||
| 874 | // Go | ||
| 875 | |||
| 876 | #define ATOMIC(func, ...) \ | ||
| 877 | if (thr->ignore_sync) { \ | ||
| 878 | NoTsanAtomic##func(__VA_ARGS__); \ | ||
| 879 | } else { \ | ||
| 880 | FuncEntry(thr, cpc); \ | ||
| 881 | Atomic##func(thr, pc, __VA_ARGS__); \ | ||
| 882 | FuncExit(thr); \ | ||
| 883 | } \ | ||
| 884 | /**/ | ||
| 885 | |||
| 886 | #define ATOMIC_RET(func, ret, ...) \ | ||
| 887 | if (thr->ignore_sync) { \ | ||
| 888 | (ret) = NoTsanAtomic##func(__VA_ARGS__); \ | ||
| 889 | } else { \ | ||
| 890 | FuncEntry(thr, cpc); \ | ||
| 891 | (ret) = Atomic##func(thr, pc, __VA_ARGS__); \ | ||
| 892 | FuncExit(thr); \ | ||
| 893 | } \ | ||
| 894 | /**/ | ||
| 895 | |||
| 896 | extern "C" { | ||
| 897 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 898 | void __tsan_go_atomic32_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { | ||
| 899 | ATOMIC_RET(Load, *(a32*)(a+8), *(a32**)a, mo_acquire); | ||
| 900 | } | ||
| 901 | |||
| 902 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 903 | void __tsan_go_atomic64_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { | ||
| 904 | ATOMIC_RET(Load, *(a64*)(a+8), *(a64**)a, mo_acquire); | ||
| 905 | } | ||
| 906 | |||
| 907 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 908 | void __tsan_go_atomic32_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { | ||
| 909 | ATOMIC(Store, *(a32**)a, *(a32*)(a+8), mo_release); | ||
| 910 | } | ||
| 911 | |||
| 912 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 913 | void __tsan_go_atomic64_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { | ||
| 914 | ATOMIC(Store, *(a64**)a, *(a64*)(a+8), mo_release); | ||
| 915 | } | ||
| 916 | |||
| 917 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 918 | void __tsan_go_atomic32_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { | ||
| 919 | ATOMIC_RET(FetchAdd, *(a32*)(a+16), *(a32**)a, *(a32*)(a+8), mo_acq_rel); | ||
| 920 | } | ||
| 921 | |||
| 922 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 923 | void __tsan_go_atomic64_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { | ||
| 924 | ATOMIC_RET(FetchAdd, *(a64*)(a+16), *(a64**)a, *(a64*)(a+8), mo_acq_rel); | ||
| 925 | } | ||
| 926 | |||
| 927 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 928 | void __tsan_go_atomic32_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { | ||
| 929 | ATOMIC_RET(Exchange, *(a32*)(a+16), *(a32**)a, *(a32*)(a+8), mo_acq_rel); | ||
| 930 | } | ||
| 931 | |||
| 932 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 933 | void __tsan_go_atomic64_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { | ||
| 934 | ATOMIC_RET(Exchange, *(a64*)(a+16), *(a64**)a, *(a64*)(a+8), mo_acq_rel); | ||
| 935 | } | ||
| 936 | |||
| 937 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 938 | void __tsan_go_atomic32_compare_exchange( | ||
| 939 | ThreadState *thr, uptr cpc, uptr pc, u8 *a) { | ||
| 940 | a32 cur = 0; | ||
| 941 | a32 cmp = *(a32*)(a+8); | ||
| 942 | ATOMIC_RET(CAS, cur, *(a32**)a, cmp, *(a32*)(a+12), mo_acq_rel, mo_acquire); | ||
| 943 | *(bool*)(a+16) = (cur == cmp); | ||
| 944 | } | ||
| 945 | |||
| 946 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 947 | void __tsan_go_atomic64_compare_exchange( | ||
| 948 | ThreadState *thr, uptr cpc, uptr pc, u8 *a) { | ||
| 949 | a64 cur = 0; | ||
| 950 | a64 cmp = *(a64*)(a+8); | ||
| 951 | ATOMIC_RET(CAS, cur, *(a64**)a, cmp, *(a64*)(a+16), mo_acq_rel, mo_acquire); | ||
| 952 | *(bool*)(a+24) = (cur == cmp); | ||
| 953 | } | ||
| 954 | } // extern "C" | ||
| 955 | #endif // #if !SANITIZER_GO | ||
lib/tsan/tsan_interface_inl.h created+132| ... | @@ -0,0 +1,132 @@ | ||
| 1 | //===-- tsan_interface_inl.h ------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "tsan_interface.h" | ||
| 14 | #include "tsan_rtl.h" | ||
| 15 | |||
| 16 | #define CALLERPC ((uptr)__builtin_return_address(0)) | ||
| 17 | |||
| 18 | using namespace __tsan; | ||
| 19 | |||
| 20 | void __tsan_read1(void *addr) { | ||
| 21 | MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog1); | ||
| 22 | } | ||
| 23 | |||
| 24 | void __tsan_read2(void *addr) { | ||
| 25 | MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog2); | ||
| 26 | } | ||
| 27 | |||
| 28 | void __tsan_read4(void *addr) { | ||
| 29 | MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog4); | ||
| 30 | } | ||
| 31 | |||
| 32 | void __tsan_read8(void *addr) { | ||
| 33 | MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8); | ||
| 34 | } | ||
| 35 | |||
| 36 | void __tsan_write1(void *addr) { | ||
| 37 | MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog1); | ||
| 38 | } | ||
| 39 | |||
| 40 | void __tsan_write2(void *addr) { | ||
| 41 | MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog2); | ||
| 42 | } | ||
| 43 | |||
| 44 | void __tsan_write4(void *addr) { | ||
| 45 | MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog4); | ||
| 46 | } | ||
| 47 | |||
| 48 | void __tsan_write8(void *addr) { | ||
| 49 | MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8); | ||
| 50 | } | ||
| 51 | |||
| 52 | void __tsan_read1_pc(void *addr, void *pc) { | ||
| 53 | MemoryRead(cur_thread(), (uptr)pc, (uptr)addr, kSizeLog1); | ||
| 54 | } | ||
| 55 | |||
| 56 | void __tsan_read2_pc(void *addr, void *pc) { | ||
| 57 | MemoryRead(cur_thread(), (uptr)pc, (uptr)addr, kSizeLog2); | ||
| 58 | } | ||
| 59 | |||
| 60 | void __tsan_read4_pc(void *addr, void *pc) { | ||
| 61 | MemoryRead(cur_thread(), (uptr)pc, (uptr)addr, kSizeLog4); | ||
| 62 | } | ||
| 63 | |||
| 64 | void __tsan_read8_pc(void *addr, void *pc) { | ||
| 65 | MemoryRead(cur_thread(), (uptr)pc, (uptr)addr, kSizeLog8); | ||
| 66 | } | ||
| 67 | |||
| 68 | void __tsan_write1_pc(void *addr, void *pc) { | ||
| 69 | MemoryWrite(cur_thread(), (uptr)pc, (uptr)addr, kSizeLog1); | ||
| 70 | } | ||
| 71 | |||
| 72 | void __tsan_write2_pc(void *addr, void *pc) { | ||
| 73 | MemoryWrite(cur_thread(), (uptr)pc, (uptr)addr, kSizeLog2); | ||
| 74 | } | ||
| 75 | |||
| 76 | void __tsan_write4_pc(void *addr, void *pc) { | ||
| 77 | MemoryWrite(cur_thread(), (uptr)pc, (uptr)addr, kSizeLog4); | ||
| 78 | } | ||
| 79 | |||
| 80 | void __tsan_write8_pc(void *addr, void *pc) { | ||
| 81 | MemoryWrite(cur_thread(), (uptr)pc, (uptr)addr, kSizeLog8); | ||
| 82 | } | ||
| 83 | |||
| 84 | void __tsan_vptr_update(void **vptr_p, void *new_val) { | ||
| 85 | CHECK_EQ(sizeof(vptr_p), 8); | ||
| 86 | if (*vptr_p != new_val) { | ||
| 87 | ThreadState *thr = cur_thread(); | ||
| 88 | thr->is_vptr_access = true; | ||
| 89 | MemoryWrite(thr, CALLERPC, (uptr)vptr_p, kSizeLog8); | ||
| 90 | thr->is_vptr_access = false; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | void __tsan_vptr_read(void **vptr_p) { | ||
| 95 | CHECK_EQ(sizeof(vptr_p), 8); | ||
| 96 | ThreadState *thr = cur_thread(); | ||
| 97 | thr->is_vptr_access = true; | ||
| 98 | MemoryRead(thr, CALLERPC, (uptr)vptr_p, kSizeLog8); | ||
| 99 | thr->is_vptr_access = false; | ||
| 100 | } | ||
| 101 | |||
| 102 | void __tsan_func_entry(void *pc) { | ||
| 103 | FuncEntry(cur_thread(), (uptr)pc); | ||
| 104 | } | ||
| 105 | |||
| 106 | void __tsan_func_exit() { | ||
| 107 | FuncExit(cur_thread()); | ||
| 108 | } | ||
| 109 | |||
| 110 | void __tsan_ignore_thread_begin() { | ||
| 111 | ThreadIgnoreBegin(cur_thread(), CALLERPC); | ||
| 112 | } | ||
| 113 | |||
| 114 | void __tsan_ignore_thread_end() { | ||
| 115 | ThreadIgnoreEnd(cur_thread(), CALLERPC); | ||
| 116 | } | ||
| 117 | |||
| 118 | void __tsan_read_range(void *addr, uptr size) { | ||
| 119 | MemoryAccessRange(cur_thread(), CALLERPC, (uptr)addr, size, false); | ||
| 120 | } | ||
| 121 | |||
| 122 | void __tsan_write_range(void *addr, uptr size) { | ||
| 123 | MemoryAccessRange(cur_thread(), CALLERPC, (uptr)addr, size, true); | ||
| 124 | } | ||
| 125 | |||
| 126 | void __tsan_read_range_pc(void *addr, uptr size, void *pc) { | ||
| 127 | MemoryAccessRange(cur_thread(), (uptr)pc, (uptr)addr, size, false); | ||
| 128 | } | ||
| 129 | |||
| 130 | void __tsan_write_range_pc(void *addr, uptr size, void *pc) { | ||
| 131 | MemoryAccessRange(cur_thread(), (uptr)pc, (uptr)addr, size, true); | ||
| 132 | } | ||
lib/tsan/tsan_interface_java.cpp created+267| ... | @@ -0,0 +1,267 @@ | ||
| 1 | //===-- tsan_interface_java.cpp -------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "tsan_interface_java.h" | ||
| 14 | #include "tsan_rtl.h" | ||
| 15 | #include "tsan_mutex.h" | ||
| 16 | #include "sanitizer_common/sanitizer_internal_defs.h" | ||
| 17 | #include "sanitizer_common/sanitizer_common.h" | ||
| 18 | #include "sanitizer_common/sanitizer_placement_new.h" | ||
| 19 | #include "sanitizer_common/sanitizer_stacktrace.h" | ||
| 20 | #include "sanitizer_common/sanitizer_procmaps.h" | ||
| 21 | |||
| 22 | using namespace __tsan; | ||
| 23 | |||
| 24 | const jptr kHeapAlignment = 8; | ||
| 25 | |||
| 26 | namespace __tsan { | ||
| 27 | |||
| 28 | struct JavaContext { | ||
| 29 | const uptr heap_begin; | ||
| 30 | const uptr heap_size; | ||
| 31 | |||
| 32 | JavaContext(jptr heap_begin, jptr heap_size) | ||
| 33 | : heap_begin(heap_begin) | ||
| 34 | , heap_size(heap_size) { | ||
| 35 | } | ||
| 36 | }; | ||
| 37 | |||
| 38 | class ScopedJavaFunc { | ||
| 39 | public: | ||
| 40 | ScopedJavaFunc(ThreadState *thr, uptr pc) | ||
| 41 | : thr_(thr) { | ||
| 42 | Initialize(thr_); | ||
| 43 | FuncEntry(thr, pc); | ||
| 44 | } | ||
| 45 | |||
| 46 | ~ScopedJavaFunc() { | ||
| 47 | FuncExit(thr_); | ||
| 48 | // FIXME(dvyukov): process pending signals. | ||
| 49 | } | ||
| 50 | |||
| 51 | private: | ||
| 52 | ThreadState *thr_; | ||
| 53 | }; | ||
| 54 | |||
| 55 | static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1]; | ||
| 56 | static JavaContext *jctx; | ||
| 57 | |||
| 58 | } // namespace __tsan | ||
| 59 | |||
| 60 | #define SCOPED_JAVA_FUNC(func) \ | ||
| 61 | ThreadState *thr = cur_thread(); \ | ||
| 62 | const uptr caller_pc = GET_CALLER_PC(); \ | ||
| 63 | const uptr pc = StackTrace::GetCurrentPc(); \ | ||
| 64 | (void)pc; \ | ||
| 65 | ScopedJavaFunc scoped(thr, caller_pc); \ | ||
| 66 | /**/ | ||
| 67 | |||
| 68 | void __tsan_java_init(jptr heap_begin, jptr heap_size) { | ||
| 69 | SCOPED_JAVA_FUNC(__tsan_java_init); | ||
| 70 | DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size); | ||
| 71 | CHECK_EQ(jctx, 0); | ||
| 72 | CHECK_GT(heap_begin, 0); | ||
| 73 | CHECK_GT(heap_size, 0); | ||
| 74 | CHECK_EQ(heap_begin % kHeapAlignment, 0); | ||
| 75 | CHECK_EQ(heap_size % kHeapAlignment, 0); | ||
| 76 | CHECK_LT(heap_begin, heap_begin + heap_size); | ||
| 77 | jctx = new(jctx_buf) JavaContext(heap_begin, heap_size); | ||
| 78 | } | ||
| 79 | |||
| 80 | int __tsan_java_fini() { | ||
| 81 | SCOPED_JAVA_FUNC(__tsan_java_fini); | ||
| 82 | DPrintf("#%d: java_fini()\n", thr->tid); | ||
| 83 | CHECK_NE(jctx, 0); | ||
| 84 | // FIXME(dvyukov): this does not call atexit() callbacks. | ||
| 85 | int status = Finalize(thr); | ||
| 86 | DPrintf("#%d: java_fini() = %d\n", thr->tid, status); | ||
| 87 | return status; | ||
| 88 | } | ||
| 89 | |||
| 90 | void __tsan_java_alloc(jptr ptr, jptr size) { | ||
| 91 | SCOPED_JAVA_FUNC(__tsan_java_alloc); | ||
| 92 | DPrintf("#%d: java_alloc(%p, %p)\n", thr->tid, ptr, size); | ||
| 93 | CHECK_NE(jctx, 0); | ||
| 94 | CHECK_NE(size, 0); | ||
| 95 | CHECK_EQ(ptr % kHeapAlignment, 0); | ||
| 96 | CHECK_EQ(size % kHeapAlignment, 0); | ||
| 97 | CHECK_GE(ptr, jctx->heap_begin); | ||
| 98 | CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size); | ||
| 99 | |||
| 100 | OnUserAlloc(thr, pc, ptr, size, false); | ||
| 101 | } | ||
| 102 | |||
| 103 | void __tsan_java_free(jptr ptr, jptr size) { | ||
| 104 | SCOPED_JAVA_FUNC(__tsan_java_free); | ||
| 105 | DPrintf("#%d: java_free(%p, %p)\n", thr->tid, ptr, size); | ||
| 106 | CHECK_NE(jctx, 0); | ||
| 107 | CHECK_NE(size, 0); | ||
| 108 | CHECK_EQ(ptr % kHeapAlignment, 0); | ||
| 109 | CHECK_EQ(size % kHeapAlignment, 0); | ||
| 110 | CHECK_GE(ptr, jctx->heap_begin); | ||
| 111 | CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size); | ||
| 112 | |||
| 113 | ctx->metamap.FreeRange(thr->proc(), ptr, size); | ||
| 114 | } | ||
| 115 | |||
| 116 | void __tsan_java_move(jptr src, jptr dst, jptr size) { | ||
| 117 | SCOPED_JAVA_FUNC(__tsan_java_move); | ||
| 118 | DPrintf("#%d: java_move(%p, %p, %p)\n", thr->tid, src, dst, size); | ||
| 119 | CHECK_NE(jctx, 0); | ||
| 120 | CHECK_NE(size, 0); | ||
| 121 | CHECK_EQ(src % kHeapAlignment, 0); | ||
| 122 | CHECK_EQ(dst % kHeapAlignment, 0); | ||
| 123 | CHECK_EQ(size % kHeapAlignment, 0); | ||
| 124 | CHECK_GE(src, jctx->heap_begin); | ||
| 125 | CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size); | ||
| 126 | CHECK_GE(dst, jctx->heap_begin); | ||
| 127 | CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size); | ||
| 128 | CHECK_NE(dst, src); | ||
| 129 | CHECK_NE(size, 0); | ||
| 130 | |||
| 131 | // Assuming it's not running concurrently with threads that do | ||
| 132 | // memory accesses and mutex operations (stop-the-world phase). | ||
| 133 | ctx->metamap.MoveMemory(src, dst, size); | ||
| 134 | |||
| 135 | // Move shadow. | ||
| 136 | u64 *s = (u64*)MemToShadow(src); | ||
| 137 | u64 *d = (u64*)MemToShadow(dst); | ||
| 138 | u64 *send = (u64*)MemToShadow(src + size); | ||
| 139 | uptr inc = 1; | ||
| 140 | if (dst > src) { | ||
| 141 | s = (u64*)MemToShadow(src + size) - 1; | ||
| 142 | d = (u64*)MemToShadow(dst + size) - 1; | ||
| 143 | send = (u64*)MemToShadow(src) - 1; | ||
| 144 | inc = -1; | ||
| 145 | } | ||
| 146 | for (; s != send; s += inc, d += inc) { | ||
| 147 | *d = *s; | ||
| 148 | *s = 0; | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | jptr __tsan_java_find(jptr *from_ptr, jptr to) { | ||
| 153 | SCOPED_JAVA_FUNC(__tsan_java_find); | ||
| 154 | DPrintf("#%d: java_find(&%p, %p)\n", *from_ptr, to); | ||
| 155 | CHECK_EQ((*from_ptr) % kHeapAlignment, 0); | ||
| 156 | CHECK_EQ(to % kHeapAlignment, 0); | ||
| 157 | CHECK_GE(*from_ptr, jctx->heap_begin); | ||
| 158 | CHECK_LE(to, jctx->heap_begin + jctx->heap_size); | ||
| 159 | for (uptr from = *from_ptr; from < to; from += kHeapAlignment) { | ||
| 160 | MBlock *b = ctx->metamap.GetBlock(from); | ||
| 161 | if (b) { | ||
| 162 | *from_ptr = from; | ||
| 163 | return b->siz; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | return 0; | ||
| 167 | } | ||
| 168 | |||
| 169 | void __tsan_java_finalize() { | ||
| 170 | SCOPED_JAVA_FUNC(__tsan_java_finalize); | ||
| 171 | DPrintf("#%d: java_mutex_finalize()\n", thr->tid); | ||
| 172 | AcquireGlobal(thr, 0); | ||
| 173 | } | ||
| 174 | |||
| 175 | void __tsan_java_mutex_lock(jptr addr) { | ||
| 176 | SCOPED_JAVA_FUNC(__tsan_java_mutex_lock); | ||
| 177 | DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr); | ||
| 178 | CHECK_NE(jctx, 0); | ||
| 179 | CHECK_GE(addr, jctx->heap_begin); | ||
| 180 | CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); | ||
| 181 | |||
| 182 | MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant | | ||
| 183 | MutexFlagDoPreLockOnPostLock); | ||
| 184 | } | ||
| 185 | |||
| 186 | void __tsan_java_mutex_unlock(jptr addr) { | ||
| 187 | SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock); | ||
| 188 | DPrintf("#%d: java_mutex_unlock(%p)\n", thr->tid, addr); | ||
| 189 | CHECK_NE(jctx, 0); | ||
| 190 | CHECK_GE(addr, jctx->heap_begin); | ||
| 191 | CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); | ||
| 192 | |||
| 193 | MutexUnlock(thr, pc, addr); | ||
| 194 | } | ||
| 195 | |||
| 196 | void __tsan_java_mutex_read_lock(jptr addr) { | ||
| 197 | SCOPED_JAVA_FUNC(__tsan_java_mutex_read_lock); | ||
| 198 | DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr); | ||
| 199 | CHECK_NE(jctx, 0); | ||
| 200 | CHECK_GE(addr, jctx->heap_begin); | ||
| 201 | CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); | ||
| 202 | |||
| 203 | MutexPostReadLock(thr, pc, addr, MutexFlagLinkerInit | | ||
| 204 | MutexFlagWriteReentrant | MutexFlagDoPreLockOnPostLock); | ||
| 205 | } | ||
| 206 | |||
| 207 | void __tsan_java_mutex_read_unlock(jptr addr) { | ||
| 208 | SCOPED_JAVA_FUNC(__tsan_java_mutex_read_unlock); | ||
| 209 | DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr); | ||
| 210 | CHECK_NE(jctx, 0); | ||
| 211 | CHECK_GE(addr, jctx->heap_begin); | ||
| 212 | CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); | ||
| 213 | |||
| 214 | MutexReadUnlock(thr, pc, addr); | ||
| 215 | } | ||
| 216 | |||
| 217 | void __tsan_java_mutex_lock_rec(jptr addr, int rec) { | ||
| 218 | SCOPED_JAVA_FUNC(__tsan_java_mutex_lock_rec); | ||
| 219 | DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec); | ||
| 220 | CHECK_NE(jctx, 0); | ||
| 221 | CHECK_GE(addr, jctx->heap_begin); | ||
| 222 | CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); | ||
| 223 | CHECK_GT(rec, 0); | ||
| 224 | |||
| 225 | MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant | | ||
| 226 | MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock, rec); | ||
| 227 | } | ||
| 228 | |||
| 229 | int __tsan_java_mutex_unlock_rec(jptr addr) { | ||
| 230 | SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock_rec); | ||
| 231 | DPrintf("#%d: java_mutex_unlock_rec(%p)\n", thr->tid, addr); | ||
| 232 | CHECK_NE(jctx, 0); | ||
| 233 | CHECK_GE(addr, jctx->heap_begin); | ||
| 234 | CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); | ||
| 235 | |||
| 236 | return MutexUnlock(thr, pc, addr, MutexFlagRecursiveUnlock); | ||
| 237 | } | ||
| 238 | |||
| 239 | void __tsan_java_acquire(jptr addr) { | ||
| 240 | SCOPED_JAVA_FUNC(__tsan_java_acquire); | ||
| 241 | DPrintf("#%d: java_acquire(%p)\n", thr->tid, addr); | ||
| 242 | CHECK_NE(jctx, 0); | ||
| 243 | CHECK_GE(addr, jctx->heap_begin); | ||
| 244 | CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); | ||
| 245 | |||
| 246 | Acquire(thr, caller_pc, addr); | ||
| 247 | } | ||
| 248 | |||
| 249 | void __tsan_java_release(jptr addr) { | ||
| 250 | SCOPED_JAVA_FUNC(__tsan_java_release); | ||
| 251 | DPrintf("#%d: java_release(%p)\n", thr->tid, addr); | ||
| 252 | CHECK_NE(jctx, 0); | ||
| 253 | CHECK_GE(addr, jctx->heap_begin); | ||
| 254 | CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); | ||
| 255 | |||
| 256 | Release(thr, caller_pc, addr); | ||
| 257 | } | ||
| 258 | |||
| 259 | void __tsan_java_release_store(jptr addr) { | ||
| 260 | SCOPED_JAVA_FUNC(__tsan_java_release); | ||
| 261 | DPrintf("#%d: java_release_store(%p)\n", thr->tid, addr); | ||
| 262 | CHECK_NE(jctx, 0); | ||
| 263 | CHECK_GE(addr, jctx->heap_begin); | ||
| 264 | CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); | ||
| 265 | |||
| 266 | ReleaseStore(thr, caller_pc, addr); | ||
| 267 | } | ||
lib/tsan/tsan_interface_java.h created+99| ... | @@ -0,0 +1,99 @@ | ||
| 1 | //===-- tsan_interface_java.h -----------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | // Interface for verification of Java or mixed Java/C++ programs. | ||
| 12 | // The interface is intended to be used from within a JVM and notify TSan | ||
| 13 | // about such events like Java locks and GC memory compaction. | ||
| 14 | // | ||
| 15 | // For plain memory accesses and function entry/exit a JVM is intended to use | ||
| 16 | // C++ interfaces: __tsan_readN/writeN and __tsan_func_enter/exit. | ||
| 17 | // | ||
| 18 | // For volatile memory accesses and atomic operations JVM is intended to use | ||
| 19 | // standard atomics API: __tsan_atomicN_load/store/etc. | ||
| 20 | // | ||
| 21 | // For usage examples see lit_tests/java_*.cpp | ||
| 22 | //===----------------------------------------------------------------------===// | ||
| 23 | #ifndef TSAN_INTERFACE_JAVA_H | ||
| 24 | #define TSAN_INTERFACE_JAVA_H | ||
| 25 | |||
| 26 | #ifndef INTERFACE_ATTRIBUTE | ||
| 27 | # define INTERFACE_ATTRIBUTE __attribute__((visibility("default"))) | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #ifdef __cplusplus | ||
| 31 | extern "C" { | ||
| 32 | #endif | ||
| 33 | |||
| 34 | typedef unsigned long jptr; | ||
| 35 | |||
| 36 | // Must be called before any other callback from Java. | ||
| 37 | void __tsan_java_init(jptr heap_begin, jptr heap_size) INTERFACE_ATTRIBUTE; | ||
| 38 | // Must be called when the application exits. | ||
| 39 | // Not necessary the last callback (concurrently running threads are OK). | ||
| 40 | // Returns exit status or 0 if tsan does not want to override it. | ||
| 41 | int __tsan_java_fini() INTERFACE_ATTRIBUTE; | ||
| 42 | |||
| 43 | // Callback for memory allocations. | ||
| 44 | // May be omitted for allocations that are not subject to data races | ||
| 45 | // nor contain synchronization objects (e.g. String). | ||
| 46 | void __tsan_java_alloc(jptr ptr, jptr size) INTERFACE_ATTRIBUTE; | ||
| 47 | // Callback for memory free. | ||
| 48 | // Can be aggregated for several objects (preferably). | ||
| 49 | void __tsan_java_free(jptr ptr, jptr size) INTERFACE_ATTRIBUTE; | ||
| 50 | // Callback for memory move by GC. | ||
| 51 | // Can be aggregated for several objects (preferably). | ||
| 52 | // The ranges can overlap. | ||
| 53 | void __tsan_java_move(jptr src, jptr dst, jptr size) INTERFACE_ATTRIBUTE; | ||
| 54 | // This function must be called on the finalizer thread | ||
| 55 | // before executing a batch of finalizers. | ||
| 56 | // It ensures necessary synchronization between | ||
| 57 | // java object creation and finalization. | ||
| 58 | void __tsan_java_finalize() INTERFACE_ATTRIBUTE; | ||
| 59 | // Finds the first allocated memory block in the [*from_ptr, to) range, saves | ||
| 60 | // its address in *from_ptr and returns its size. Returns 0 if there are no | ||
| 61 | // allocated memory blocks in the range. | ||
| 62 | jptr __tsan_java_find(jptr *from_ptr, jptr to) INTERFACE_ATTRIBUTE; | ||
| 63 | |||
| 64 | // Mutex lock. | ||
| 65 | // Addr is any unique address associated with the mutex. | ||
| 66 | // Can be called on recursive reentry. | ||
| 67 | void __tsan_java_mutex_lock(jptr addr) INTERFACE_ATTRIBUTE; | ||
| 68 | // Mutex unlock. | ||
| 69 | void __tsan_java_mutex_unlock(jptr addr) INTERFACE_ATTRIBUTE; | ||
| 70 | // Mutex read lock. | ||
| 71 | void __tsan_java_mutex_read_lock(jptr addr) INTERFACE_ATTRIBUTE; | ||
| 72 | // Mutex read unlock. | ||
| 73 | void __tsan_java_mutex_read_unlock(jptr addr) INTERFACE_ATTRIBUTE; | ||
| 74 | // Recursive mutex lock, intended for handling of Object.wait(). | ||
| 75 | // The 'rec' value must be obtained from the previous | ||
| 76 | // __tsan_java_mutex_unlock_rec(). | ||
| 77 | void __tsan_java_mutex_lock_rec(jptr addr, int rec) INTERFACE_ATTRIBUTE; | ||
| 78 | // Recursive mutex unlock, intended for handling of Object.wait(). | ||
| 79 | // The return value says how many times this thread called lock() | ||
| 80 | // w/o a pairing unlock() (i.e. how many recursive levels it unlocked). | ||
| 81 | // It must be passed back to __tsan_java_mutex_lock_rec() to restore | ||
| 82 | // the same recursion level. | ||
| 83 | int __tsan_java_mutex_unlock_rec(jptr addr) INTERFACE_ATTRIBUTE; | ||
| 84 | |||
| 85 | // Raw acquire/release primitives. | ||
| 86 | // Can be used to establish happens-before edges on volatile/final fields, | ||
| 87 | // in atomic operations, etc. release_store is the same as release, but it | ||
| 88 | // breaks release sequence on addr (see C++ standard 1.10/7 for details). | ||
| 89 | void __tsan_java_acquire(jptr addr) INTERFACE_ATTRIBUTE; | ||
| 90 | void __tsan_java_release(jptr addr) INTERFACE_ATTRIBUTE; | ||
| 91 | void __tsan_java_release_store(jptr addr) INTERFACE_ATTRIBUTE; | ||
| 92 | |||
| 93 | #ifdef __cplusplus | ||
| 94 | } // extern "C" | ||
| 95 | #endif | ||
| 96 | |||
| 97 | #undef INTERFACE_ATTRIBUTE | ||
| 98 | |||
| 99 | #endif // #ifndef TSAN_INTERFACE_JAVA_H | ||
lib/tsan/tsan_malloc_mac.cpp created+71| ... | @@ -0,0 +1,71 @@ | ||
| 1 | //===-- tsan_malloc_mac.cpp -----------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | // Mac-specific malloc interception. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_common/sanitizer_platform.h" | ||
| 15 | #if SANITIZER_MAC | ||
| 16 | |||
| 17 | #include "sanitizer_common/sanitizer_errno.h" | ||
| 18 | #include "tsan_interceptors.h" | ||
| 19 | #include "tsan_stack_trace.h" | ||
| 20 | |||
| 21 | using namespace __tsan; | ||
| 22 | #define COMMON_MALLOC_ZONE_NAME "tsan" | ||
| 23 | #define COMMON_MALLOC_ENTER() | ||
| 24 | #define COMMON_MALLOC_SANITIZER_INITIALIZED (cur_thread()->is_inited) | ||
| 25 | #define COMMON_MALLOC_FORCE_LOCK() | ||
| 26 | #define COMMON_MALLOC_FORCE_UNLOCK() | ||
| 27 | #define COMMON_MALLOC_MEMALIGN(alignment, size) \ | ||
| 28 | void *p = \ | ||
| 29 | user_memalign(cur_thread(), StackTrace::GetCurrentPc(), alignment, size) | ||
| 30 | #define COMMON_MALLOC_MALLOC(size) \ | ||
| 31 | if (in_symbolizer()) return InternalAlloc(size); \ | ||
| 32 | SCOPED_INTERCEPTOR_RAW(malloc, size); \ | ||
| 33 | void *p = user_alloc(thr, pc, size) | ||
| 34 | #define COMMON_MALLOC_REALLOC(ptr, size) \ | ||
| 35 | if (in_symbolizer()) return InternalRealloc(ptr, size); \ | ||
| 36 | SCOPED_INTERCEPTOR_RAW(realloc, ptr, size); \ | ||
| 37 | void *p = user_realloc(thr, pc, ptr, size) | ||
| 38 | #define COMMON_MALLOC_CALLOC(count, size) \ | ||
| 39 | if (in_symbolizer()) return InternalCalloc(count, size); \ | ||
| 40 | SCOPED_INTERCEPTOR_RAW(calloc, size, count); \ | ||
| 41 | void *p = user_calloc(thr, pc, size, count) | ||
| 42 | #define COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size) \ | ||
| 43 | if (in_symbolizer()) { \ | ||
| 44 | void *p = InternalAlloc(size, nullptr, alignment); \ | ||
| 45 | if (!p) return errno_ENOMEM; \ | ||
| 46 | *memptr = p; \ | ||
| 47 | return 0; \ | ||
| 48 | } \ | ||
| 49 | SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, alignment, size); \ | ||
| 50 | int res = user_posix_memalign(thr, pc, memptr, alignment, size); | ||
| 51 | #define COMMON_MALLOC_VALLOC(size) \ | ||
| 52 | if (in_symbolizer()) \ | ||
| 53 | return InternalAlloc(size, nullptr, GetPageSizeCached()); \ | ||
| 54 | SCOPED_INTERCEPTOR_RAW(valloc, size); \ | ||
| 55 | void *p = user_valloc(thr, pc, size) | ||
| 56 | #define COMMON_MALLOC_FREE(ptr) \ | ||
| 57 | if (in_symbolizer()) return InternalFree(ptr); \ | ||
| 58 | SCOPED_INTERCEPTOR_RAW(free, ptr); \ | ||
| 59 | user_free(thr, pc, ptr) | ||
| 60 | #define COMMON_MALLOC_SIZE(ptr) uptr size = user_alloc_usable_size(ptr); | ||
| 61 | #define COMMON_MALLOC_FILL_STATS(zone, stats) | ||
| 62 | #define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \ | ||
| 63 | (void)zone_name; \ | ||
| 64 | Report("mz_realloc(%p) -- attempting to realloc unallocated memory.\n", ptr); | ||
| 65 | #define COMMON_MALLOC_NAMESPACE __tsan | ||
| 66 | #define COMMON_MALLOC_HAS_ZONE_ENUMERATOR 0 | ||
| 67 | #define COMMON_MALLOC_HAS_EXTRA_INTROSPECTION_INIT 0 | ||
| 68 | |||
| 69 | #include "sanitizer_common/sanitizer_malloc_mac.inc" | ||
| 70 | |||
| 71 | #endif | ||
lib/tsan/tsan_md5.cpp created+250| ... | @@ -0,0 +1,250 @@ | ||
| 1 | //===-- tsan_md5.cpp ------------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #include "tsan_defs.h" | ||
| 13 | |||
| 14 | namespace __tsan { | ||
| 15 | |||
| 16 | #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) | ||
| 17 | #define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) | ||
| 18 | #define H(x, y, z) ((x) ^ (y) ^ (z)) | ||
| 19 | #define I(x, y, z) ((y) ^ ((x) | ~(z))) | ||
| 20 | |||
| 21 | #define STEP(f, a, b, c, d, x, t, s) \ | ||
| 22 | (a) += f((b), (c), (d)) + (x) + (t); \ | ||
| 23 | (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ | ||
| 24 | (a) += (b); | ||
| 25 | |||
| 26 | #define SET(n) \ | ||
| 27 | (*(const MD5_u32plus *)&ptr[(n) * 4]) | ||
| 28 | #define GET(n) \ | ||
| 29 | SET(n) | ||
| 30 | |||
| 31 | typedef unsigned int MD5_u32plus; | ||
| 32 | typedef unsigned long ulong_t; | ||
| 33 | |||
| 34 | typedef struct { | ||
| 35 | MD5_u32plus lo, hi; | ||
| 36 | MD5_u32plus a, b, c, d; | ||
| 37 | unsigned char buffer[64]; | ||
| 38 | MD5_u32plus block[16]; | ||
| 39 | } MD5_CTX; | ||
| 40 | |||
| 41 | static const void *body(MD5_CTX *ctx, const void *data, ulong_t size) { | ||
| 42 | const unsigned char *ptr = (const unsigned char *)data; | ||
| 43 | MD5_u32plus a, b, c, d; | ||
| 44 | MD5_u32plus saved_a, saved_b, saved_c, saved_d; | ||
| 45 | |||
| 46 | a = ctx->a; | ||
| 47 | b = ctx->b; | ||
| 48 | c = ctx->c; | ||
| 49 | d = ctx->d; | ||
| 50 | |||
| 51 | do { | ||
| 52 | saved_a = a; | ||
| 53 | saved_b = b; | ||
| 54 | saved_c = c; | ||
| 55 | saved_d = d; | ||
| 56 | |||
| 57 | STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) | ||
| 58 | STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) | ||
| 59 | STEP(F, c, d, a, b, SET(2), 0x242070db, 17) | ||
| 60 | STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) | ||
| 61 | STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) | ||
| 62 | STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) | ||
| 63 | STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) | ||
| 64 | STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) | ||
| 65 | STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) | ||
| 66 | STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) | ||
| 67 | STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) | ||
| 68 | STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) | ||
| 69 | STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) | ||
| 70 | STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) | ||
| 71 | STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) | ||
| 72 | STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) | ||
| 73 | |||
| 74 | STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) | ||
| 75 | STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) | ||
| 76 | STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) | ||
| 77 | STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) | ||
| 78 | STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) | ||
| 79 | STEP(G, d, a, b, c, GET(10), 0x02441453, 9) | ||
| 80 | STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) | ||
| 81 | STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) | ||
| 82 | STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) | ||
| 83 | STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) | ||
| 84 | STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) | ||
| 85 | STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) | ||
| 86 | STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) | ||
| 87 | STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) | ||
| 88 | STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) | ||
| 89 | STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) | ||
| 90 | |||
| 91 | STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) | ||
| 92 | STEP(H, d, a, b, c, GET(8), 0x8771f681, 11) | ||
| 93 | STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) | ||
| 94 | STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23) | ||
| 95 | STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) | ||
| 96 | STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11) | ||
| 97 | STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) | ||
| 98 | STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23) | ||
| 99 | STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) | ||
| 100 | STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11) | ||
| 101 | STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) | ||
| 102 | STEP(H, b, c, d, a, GET(6), 0x04881d05, 23) | ||
| 103 | STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) | ||
| 104 | STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11) | ||
| 105 | STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) | ||
| 106 | STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23) | ||
| 107 | |||
| 108 | STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) | ||
| 109 | STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) | ||
| 110 | STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) | ||
| 111 | STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) | ||
| 112 | STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) | ||
| 113 | STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) | ||
| 114 | STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) | ||
| 115 | STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) | ||
| 116 | STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) | ||
| 117 | STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) | ||
| 118 | STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) | ||
| 119 | STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) | ||
| 120 | STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) | ||
| 121 | STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) | ||
| 122 | STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) | ||
| 123 | STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) | ||
| 124 | |||
| 125 | a += saved_a; | ||
| 126 | b += saved_b; | ||
| 127 | c += saved_c; | ||
| 128 | d += saved_d; | ||
| 129 | |||
| 130 | ptr += 64; | ||
| 131 | } while (size -= 64); | ||
| 132 | |||
| 133 | ctx->a = a; | ||
| 134 | ctx->b = b; | ||
| 135 | ctx->c = c; | ||
| 136 | ctx->d = d; | ||
| 137 | |||
| 138 | return ptr; | ||
| 139 | } | ||
| 140 | |||
| 141 | #undef F | ||
| 142 | #undef G | ||
| 143 | #undef H | ||
| 144 | #undef I | ||
| 145 | #undef STEP | ||
| 146 | #undef SET | ||
| 147 | #undef GET | ||
| 148 | |||
| 149 | void MD5_Init(MD5_CTX *ctx) { | ||
| 150 | ctx->a = 0x67452301; | ||
| 151 | ctx->b = 0xefcdab89; | ||
| 152 | ctx->c = 0x98badcfe; | ||
| 153 | ctx->d = 0x10325476; | ||
| 154 | |||
| 155 | ctx->lo = 0; | ||
| 156 | ctx->hi = 0; | ||
| 157 | } | ||
| 158 | |||
| 159 | void MD5_Update(MD5_CTX *ctx, const void *data, ulong_t size) { | ||
| 160 | MD5_u32plus saved_lo; | ||
| 161 | ulong_t used, free; | ||
| 162 | |||
| 163 | saved_lo = ctx->lo; | ||
| 164 | if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) | ||
| 165 | ctx->hi++; | ||
| 166 | ctx->hi += size >> 29; | ||
| 167 | |||
| 168 | used = saved_lo & 0x3f; | ||
| 169 | |||
| 170 | if (used) { | ||
| 171 | free = 64 - used; | ||
| 172 | |||
| 173 | if (size < free) { | ||
| 174 | internal_memcpy(&ctx->buffer[used], data, size); | ||
| 175 | return; | ||
| 176 | } | ||
| 177 | |||
| 178 | internal_memcpy(&ctx->buffer[used], data, free); | ||
| 179 | data = (const unsigned char *)data + free; | ||
| 180 | size -= free; | ||
| 181 | body(ctx, ctx->buffer, 64); | ||
| 182 | } | ||
| 183 | |||
| 184 | if (size >= 64) { | ||
| 185 | data = body(ctx, data, size & ~(ulong_t)0x3f); | ||
| 186 | size &= 0x3f; | ||
| 187 | } | ||
| 188 | |||
| 189 | internal_memcpy(ctx->buffer, data, size); | ||
| 190 | } | ||
| 191 | |||
| 192 | void MD5_Final(unsigned char *result, MD5_CTX *ctx) { | ||
| 193 | ulong_t used, free; | ||
| 194 | |||
| 195 | used = ctx->lo & 0x3f; | ||
| 196 | |||
| 197 | ctx->buffer[used++] = 0x80; | ||
| 198 | |||
| 199 | free = 64 - used; | ||
| 200 | |||
| 201 | if (free < 8) { | ||
| 202 | internal_memset(&ctx->buffer[used], 0, free); | ||
| 203 | body(ctx, ctx->buffer, 64); | ||
| 204 | used = 0; | ||
| 205 | free = 64; | ||
| 206 | } | ||
| 207 | |||
| 208 | internal_memset(&ctx->buffer[used], 0, free - 8); | ||
| 209 | |||
| 210 | ctx->lo <<= 3; | ||
| 211 | ctx->buffer[56] = ctx->lo; | ||
| 212 | ctx->buffer[57] = ctx->lo >> 8; | ||
| 213 | ctx->buffer[58] = ctx->lo >> 16; | ||
| 214 | ctx->buffer[59] = ctx->lo >> 24; | ||
| 215 | ctx->buffer[60] = ctx->hi; | ||
| 216 | ctx->buffer[61] = ctx->hi >> 8; | ||
| 217 | ctx->buffer[62] = ctx->hi >> 16; | ||
| 218 | ctx->buffer[63] = ctx->hi >> 24; | ||
| 219 | |||
| 220 | body(ctx, ctx->buffer, 64); | ||
| 221 | |||
| 222 | result[0] = ctx->a; | ||
| 223 | result[1] = ctx->a >> 8; | ||
| 224 | result[2] = ctx->a >> 16; | ||
| 225 | result[3] = ctx->a >> 24; | ||
| 226 | result[4] = ctx->b; | ||
| 227 | result[5] = ctx->b >> 8; | ||
| 228 | result[6] = ctx->b >> 16; | ||
| 229 | result[7] = ctx->b >> 24; | ||
| 230 | result[8] = ctx->c; | ||
| 231 | result[9] = ctx->c >> 8; | ||
| 232 | result[10] = ctx->c >> 16; | ||
| 233 | result[11] = ctx->c >> 24; | ||
| 234 | result[12] = ctx->d; | ||
| 235 | result[13] = ctx->d >> 8; | ||
| 236 | result[14] = ctx->d >> 16; | ||
| 237 | result[15] = ctx->d >> 24; | ||
| 238 | |||
| 239 | internal_memset(ctx, 0, sizeof(*ctx)); | ||
| 240 | } | ||
| 241 | |||
| 242 | MD5Hash md5_hash(const void *data, uptr size) { | ||
| 243 | MD5Hash res; | ||
| 244 | MD5_CTX ctx; | ||
| 245 | MD5_Init(&ctx); | ||
| 246 | MD5_Update(&ctx, data, size); | ||
| 247 | MD5_Final((unsigned char*)&res.hash[0], &ctx); | ||
| 248 | return res; | ||
| 249 | } | ||
| 250 | } // namespace __tsan | ||
lib/tsan/tsan_mman.cpp created+405| ... | @@ -0,0 +1,405 @@ | ||
| 1 | //===-- tsan_mman.cpp -----------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #include "sanitizer_common/sanitizer_allocator_checks.h" | ||
| 13 | #include "sanitizer_common/sanitizer_allocator_interface.h" | ||
| 14 | #include "sanitizer_common/sanitizer_allocator_report.h" | ||
| 15 | #include "sanitizer_common/sanitizer_common.h" | ||
| 16 | #include "sanitizer_common/sanitizer_errno.h" | ||
| 17 | #include "sanitizer_common/sanitizer_placement_new.h" | ||
| 18 | #include "tsan_mman.h" | ||
| 19 | #include "tsan_rtl.h" | ||
| 20 | #include "tsan_report.h" | ||
| 21 | #include "tsan_flags.h" | ||
| 22 | |||
| 23 | // May be overriden by front-end. | ||
| 24 | SANITIZER_WEAK_DEFAULT_IMPL | ||
| 25 | void __sanitizer_malloc_hook(void *ptr, uptr size) { | ||
| 26 | (void)ptr; | ||
| 27 | (void)size; | ||
| 28 | } | ||
| 29 | |||
| 30 | SANITIZER_WEAK_DEFAULT_IMPL | ||
| 31 | void __sanitizer_free_hook(void *ptr) { | ||
| 32 | (void)ptr; | ||
| 33 | } | ||
| 34 | |||
| 35 | namespace __tsan { | ||
| 36 | |||
| 37 | struct MapUnmapCallback { | ||
| 38 | void OnMap(uptr p, uptr size) const { } | ||
| 39 | void OnUnmap(uptr p, uptr size) const { | ||
| 40 | // We are about to unmap a chunk of user memory. | ||
| 41 | // Mark the corresponding shadow memory as not needed. | ||
| 42 | DontNeedShadowFor(p, size); | ||
| 43 | // Mark the corresponding meta shadow memory as not needed. | ||
| 44 | // Note the block does not contain any meta info at this point | ||
| 45 | // (this happens after free). | ||
| 46 | const uptr kMetaRatio = kMetaShadowCell / kMetaShadowSize; | ||
| 47 | const uptr kPageSize = GetPageSizeCached() * kMetaRatio; | ||
| 48 | // Block came from LargeMmapAllocator, so must be large. | ||
| 49 | // We rely on this in the calculations below. | ||
| 50 | CHECK_GE(size, 2 * kPageSize); | ||
| 51 | uptr diff = RoundUp(p, kPageSize) - p; | ||
| 52 | if (diff != 0) { | ||
| 53 | p += diff; | ||
| 54 | size -= diff; | ||
| 55 | } | ||
| 56 | diff = p + size - RoundDown(p + size, kPageSize); | ||
| 57 | if (diff != 0) | ||
| 58 | size -= diff; | ||
| 59 | uptr p_meta = (uptr)MemToMeta(p); | ||
| 60 | ReleaseMemoryPagesToOS(p_meta, p_meta + size / kMetaRatio); | ||
| 61 | } | ||
| 62 | }; | ||
| 63 | |||
| 64 | static char allocator_placeholder[sizeof(Allocator)] ALIGNED(64); | ||
| 65 | Allocator *allocator() { | ||
| 66 | return reinterpret_cast<Allocator*>(&allocator_placeholder); | ||
| 67 | } | ||
| 68 | |||
| 69 | struct GlobalProc { | ||
| 70 | Mutex mtx; | ||
| 71 | Processor *proc; | ||
| 72 | |||
| 73 | GlobalProc() | ||
| 74 | : mtx(MutexTypeGlobalProc, StatMtxGlobalProc) | ||
| 75 | , proc(ProcCreate()) { | ||
| 76 | } | ||
| 77 | }; | ||
| 78 | |||
| 79 | static char global_proc_placeholder[sizeof(GlobalProc)] ALIGNED(64); | ||
| 80 | GlobalProc *global_proc() { | ||
| 81 | return reinterpret_cast<GlobalProc*>(&global_proc_placeholder); | ||
| 82 | } | ||
| 83 | |||
| 84 | ScopedGlobalProcessor::ScopedGlobalProcessor() { | ||
| 85 | GlobalProc *gp = global_proc(); | ||
| 86 | ThreadState *thr = cur_thread(); | ||
| 87 | if (thr->proc()) | ||
| 88 | return; | ||
| 89 | // If we don't have a proc, use the global one. | ||
| 90 | // There are currently only two known case where this path is triggered: | ||
| 91 | // __interceptor_free | ||
| 92 | // __nptl_deallocate_tsd | ||
| 93 | // start_thread | ||
| 94 | // clone | ||
| 95 | // and: | ||
| 96 | // ResetRange | ||
| 97 | // __interceptor_munmap | ||
| 98 | // __deallocate_stack | ||
| 99 | // start_thread | ||
| 100 | // clone | ||
| 101 | // Ideally, we destroy thread state (and unwire proc) when a thread actually | ||
| 102 | // exits (i.e. when we join/wait it). Then we would not need the global proc | ||
| 103 | gp->mtx.Lock(); | ||
| 104 | ProcWire(gp->proc, thr); | ||
| 105 | } | ||
| 106 | |||
| 107 | ScopedGlobalProcessor::~ScopedGlobalProcessor() { | ||
| 108 | GlobalProc *gp = global_proc(); | ||
| 109 | ThreadState *thr = cur_thread(); | ||
| 110 | if (thr->proc() != gp->proc) | ||
| 111 | return; | ||
| 112 | ProcUnwire(gp->proc, thr); | ||
| 113 | gp->mtx.Unlock(); | ||
| 114 | } | ||
| 115 | |||
| 116 | static constexpr uptr kMaxAllowedMallocSize = 1ull << 40; | ||
| 117 | static uptr max_user_defined_malloc_size; | ||
| 118 | |||
| 119 | void InitializeAllocator() { | ||
| 120 | SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); | ||
| 121 | allocator()->Init(common_flags()->allocator_release_to_os_interval_ms); | ||
| 122 | max_user_defined_malloc_size = common_flags()->max_allocation_size_mb | ||
| 123 | ? common_flags()->max_allocation_size_mb | ||
| 124 | << 20 | ||
| 125 | : kMaxAllowedMallocSize; | ||
| 126 | } | ||
| 127 | |||
| 128 | void InitializeAllocatorLate() { | ||
| 129 | new(global_proc()) GlobalProc(); | ||
| 130 | } | ||
| 131 | |||
| 132 | void AllocatorProcStart(Processor *proc) { | ||
| 133 | allocator()->InitCache(&proc->alloc_cache); | ||
| 134 | internal_allocator()->InitCache(&proc->internal_alloc_cache); | ||
| 135 | } | ||
| 136 | |||
| 137 | void AllocatorProcFinish(Processor *proc) { | ||
| 138 | allocator()->DestroyCache(&proc->alloc_cache); | ||
| 139 | internal_allocator()->DestroyCache(&proc->internal_alloc_cache); | ||
| 140 | } | ||
| 141 | |||
| 142 | void AllocatorPrintStats() { | ||
| 143 | allocator()->PrintStats(); | ||
| 144 | } | ||
| 145 | |||
| 146 | static void SignalUnsafeCall(ThreadState *thr, uptr pc) { | ||
| 147 | if (atomic_load_relaxed(&thr->in_signal_handler) == 0 || | ||
| 148 | !flags()->report_signal_unsafe) | ||
| 149 | return; | ||
| 150 | VarSizeStackTrace stack; | ||
| 151 | ObtainCurrentStack(thr, pc, &stack); | ||
| 152 | if (IsFiredSuppression(ctx, ReportTypeSignalUnsafe, stack)) | ||
| 153 | return; | ||
| 154 | ThreadRegistryLock l(ctx->thread_registry); | ||
| 155 | ScopedReport rep(ReportTypeSignalUnsafe); | ||
| 156 | rep.AddStack(stack, true); | ||
| 157 | OutputReport(thr, rep); | ||
| 158 | } | ||
| 159 | |||
| 160 | |||
| 161 | void *user_alloc_internal(ThreadState *thr, uptr pc, uptr sz, uptr align, | ||
| 162 | bool signal) { | ||
| 163 | if (sz >= kMaxAllowedMallocSize || align >= kMaxAllowedMallocSize || | ||
| 164 | sz > max_user_defined_malloc_size) { | ||
| 165 | if (AllocatorMayReturnNull()) | ||
| 166 | return nullptr; | ||
| 167 | uptr malloc_limit = | ||
| 168 | Min(kMaxAllowedMallocSize, max_user_defined_malloc_size); | ||
| 169 | GET_STACK_TRACE_FATAL(thr, pc); | ||
| 170 | ReportAllocationSizeTooBig(sz, malloc_limit, &stack); | ||
| 171 | } | ||
| 172 | void *p = allocator()->Allocate(&thr->proc()->alloc_cache, sz, align); | ||
| 173 | if (UNLIKELY(!p)) { | ||
| 174 | SetAllocatorOutOfMemory(); | ||
| 175 | if (AllocatorMayReturnNull()) | ||
| 176 | return nullptr; | ||
| 177 | GET_STACK_TRACE_FATAL(thr, pc); | ||
| 178 | ReportOutOfMemory(sz, &stack); | ||
| 179 | } | ||
| 180 | if (ctx && ctx->initialized) | ||
| 181 | OnUserAlloc(thr, pc, (uptr)p, sz, true); | ||
| 182 | if (signal) | ||
| 183 | SignalUnsafeCall(thr, pc); | ||
| 184 | return p; | ||
| 185 | } | ||
| 186 | |||
| 187 | void user_free(ThreadState *thr, uptr pc, void *p, bool signal) { | ||
| 188 | ScopedGlobalProcessor sgp; | ||
| 189 | if (ctx && ctx->initialized) | ||
| 190 | OnUserFree(thr, pc, (uptr)p, true); | ||
| 191 | allocator()->Deallocate(&thr->proc()->alloc_cache, p); | ||
| 192 | if (signal) | ||
| 193 | SignalUnsafeCall(thr, pc); | ||
| 194 | } | ||
| 195 | |||
| 196 | void *user_alloc(ThreadState *thr, uptr pc, uptr sz) { | ||
| 197 | return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, kDefaultAlignment)); | ||
| 198 | } | ||
| 199 | |||
| 200 | void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) { | ||
| 201 | if (UNLIKELY(CheckForCallocOverflow(size, n))) { | ||
| 202 | if (AllocatorMayReturnNull()) | ||
| 203 | return SetErrnoOnNull(nullptr); | ||
| 204 | GET_STACK_TRACE_FATAL(thr, pc); | ||
| 205 | ReportCallocOverflow(n, size, &stack); | ||
| 206 | } | ||
| 207 | void *p = user_alloc_internal(thr, pc, n * size); | ||
| 208 | if (p) | ||
| 209 | internal_memset(p, 0, n * size); | ||
| 210 | return SetErrnoOnNull(p); | ||
| 211 | } | ||
| 212 | |||
| 213 | void *user_reallocarray(ThreadState *thr, uptr pc, void *p, uptr size, uptr n) { | ||
| 214 | if (UNLIKELY(CheckForCallocOverflow(size, n))) { | ||
| 215 | if (AllocatorMayReturnNull()) | ||
| 216 | return SetErrnoOnNull(nullptr); | ||
| 217 | GET_STACK_TRACE_FATAL(thr, pc); | ||
| 218 | ReportReallocArrayOverflow(size, n, &stack); | ||
| 219 | } | ||
| 220 | return user_realloc(thr, pc, p, size * n); | ||
| 221 | } | ||
| 222 | |||
| 223 | void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write) { | ||
| 224 | DPrintf("#%d: alloc(%zu) = %p\n", thr->tid, sz, p); | ||
| 225 | ctx->metamap.AllocBlock(thr, pc, p, sz); | ||
| 226 | if (write && thr->ignore_reads_and_writes == 0) | ||
| 227 | MemoryRangeImitateWrite(thr, pc, (uptr)p, sz); | ||
| 228 | else | ||
| 229 | MemoryResetRange(thr, pc, (uptr)p, sz); | ||
| 230 | } | ||
| 231 | |||
| 232 | void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write) { | ||
| 233 | CHECK_NE(p, (void*)0); | ||
| 234 | uptr sz = ctx->metamap.FreeBlock(thr->proc(), p); | ||
| 235 | DPrintf("#%d: free(%p, %zu)\n", thr->tid, p, sz); | ||
| 236 | if (write && thr->ignore_reads_and_writes == 0) | ||
| 237 | MemoryRangeFreed(thr, pc, (uptr)p, sz); | ||
| 238 | } | ||
| 239 | |||
| 240 | void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) { | ||
| 241 | // FIXME: Handle "shrinking" more efficiently, | ||
| 242 | // it seems that some software actually does this. | ||
| 243 | if (!p) | ||
| 244 | return SetErrnoOnNull(user_alloc_internal(thr, pc, sz)); | ||
| 245 | if (!sz) { | ||
| 246 | user_free(thr, pc, p); | ||
| 247 | return nullptr; | ||
| 248 | } | ||
| 249 | void *new_p = user_alloc_internal(thr, pc, sz); | ||
| 250 | if (new_p) { | ||
| 251 | uptr old_sz = user_alloc_usable_size(p); | ||
| 252 | internal_memcpy(new_p, p, min(old_sz, sz)); | ||
| 253 | user_free(thr, pc, p); | ||
| 254 | } | ||
| 255 | return SetErrnoOnNull(new_p); | ||
| 256 | } | ||
| 257 | |||
| 258 | void *user_memalign(ThreadState *thr, uptr pc, uptr align, uptr sz) { | ||
| 259 | if (UNLIKELY(!IsPowerOfTwo(align))) { | ||
| 260 | errno = errno_EINVAL; | ||
| 261 | if (AllocatorMayReturnNull()) | ||
| 262 | return nullptr; | ||
| 263 | GET_STACK_TRACE_FATAL(thr, pc); | ||
| 264 | ReportInvalidAllocationAlignment(align, &stack); | ||
| 265 | } | ||
| 266 | return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align)); | ||
| 267 | } | ||
| 268 | |||
| 269 | int user_posix_memalign(ThreadState *thr, uptr pc, void **memptr, uptr align, | ||
| 270 | uptr sz) { | ||
| 271 | if (UNLIKELY(!CheckPosixMemalignAlignment(align))) { | ||
| 272 | if (AllocatorMayReturnNull()) | ||
| 273 | return errno_EINVAL; | ||
| 274 | GET_STACK_TRACE_FATAL(thr, pc); | ||
| 275 | ReportInvalidPosixMemalignAlignment(align, &stack); | ||
| 276 | } | ||
| 277 | void *ptr = user_alloc_internal(thr, pc, sz, align); | ||
| 278 | if (UNLIKELY(!ptr)) | ||
| 279 | // OOM error is already taken care of by user_alloc_internal. | ||
| 280 | return errno_ENOMEM; | ||
| 281 | CHECK(IsAligned((uptr)ptr, align)); | ||
| 282 | *memptr = ptr; | ||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | |||
| 286 | void *user_aligned_alloc(ThreadState *thr, uptr pc, uptr align, uptr sz) { | ||
| 287 | if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(align, sz))) { | ||
| 288 | errno = errno_EINVAL; | ||
| 289 | if (AllocatorMayReturnNull()) | ||
| 290 | return nullptr; | ||
| 291 | GET_STACK_TRACE_FATAL(thr, pc); | ||
| 292 | ReportInvalidAlignedAllocAlignment(sz, align, &stack); | ||
| 293 | } | ||
| 294 | return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align)); | ||
| 295 | } | ||
| 296 | |||
| 297 | void *user_valloc(ThreadState *thr, uptr pc, uptr sz) { | ||
| 298 | return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, GetPageSizeCached())); | ||
| 299 | } | ||
| 300 | |||
| 301 | void *user_pvalloc(ThreadState *thr, uptr pc, uptr sz) { | ||
| 302 | uptr PageSize = GetPageSizeCached(); | ||
| 303 | if (UNLIKELY(CheckForPvallocOverflow(sz, PageSize))) { | ||
| 304 | errno = errno_ENOMEM; | ||
| 305 | if (AllocatorMayReturnNull()) | ||
| 306 | return nullptr; | ||
| 307 | GET_STACK_TRACE_FATAL(thr, pc); | ||
| 308 | ReportPvallocOverflow(sz, &stack); | ||
| 309 | } | ||
| 310 | // pvalloc(0) should allocate one page. | ||
| 311 | sz = sz ? RoundUpTo(sz, PageSize) : PageSize; | ||
| 312 | return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, PageSize)); | ||
| 313 | } | ||
| 314 | |||
| 315 | uptr user_alloc_usable_size(const void *p) { | ||
| 316 | if (p == 0) | ||
| 317 | return 0; | ||
| 318 | MBlock *b = ctx->metamap.GetBlock((uptr)p); | ||
| 319 | if (!b) | ||
| 320 | return 0; // Not a valid pointer. | ||
| 321 | if (b->siz == 0) | ||
| 322 | return 1; // Zero-sized allocations are actually 1 byte. | ||
| 323 | return b->siz; | ||
| 324 | } | ||
| 325 | |||
| 326 | void invoke_malloc_hook(void *ptr, uptr size) { | ||
| 327 | ThreadState *thr = cur_thread(); | ||
| 328 | if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors) | ||
| 329 | return; | ||
| 330 | __sanitizer_malloc_hook(ptr, size); | ||
| 331 | RunMallocHooks(ptr, size); | ||
| 332 | } | ||
| 333 | |||
| 334 | void invoke_free_hook(void *ptr) { | ||
| 335 | ThreadState *thr = cur_thread(); | ||
| 336 | if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors) | ||
| 337 | return; | ||
| 338 | __sanitizer_free_hook(ptr); | ||
| 339 | RunFreeHooks(ptr); | ||
| 340 | } | ||
| 341 | |||
| 342 | void *internal_alloc(MBlockType typ, uptr sz) { | ||
| 343 | ThreadState *thr = cur_thread(); | ||
| 344 | if (thr->nomalloc) { | ||
| 345 | thr->nomalloc = 0; // CHECK calls internal_malloc(). | ||
| 346 | CHECK(0); | ||
| 347 | } | ||
| 348 | return InternalAlloc(sz, &thr->proc()->internal_alloc_cache); | ||
| 349 | } | ||
| 350 | |||
| 351 | void internal_free(void *p) { | ||
| 352 | ThreadState *thr = cur_thread(); | ||
| 353 | if (thr->nomalloc) { | ||
| 354 | thr->nomalloc = 0; // CHECK calls internal_malloc(). | ||
| 355 | CHECK(0); | ||
| 356 | } | ||
| 357 | InternalFree(p, &thr->proc()->internal_alloc_cache); | ||
| 358 | } | ||
| 359 | |||
| 360 | } // namespace __tsan | ||
| 361 | |||
| 362 | using namespace __tsan; | ||
| 363 | |||
| 364 | extern "C" { | ||
| 365 | uptr __sanitizer_get_current_allocated_bytes() { | ||
| 366 | uptr stats[AllocatorStatCount]; | ||
| 367 | allocator()->GetStats(stats); | ||
| 368 | return stats[AllocatorStatAllocated]; | ||
| 369 | } | ||
| 370 | |||
| 371 | uptr __sanitizer_get_heap_size() { | ||
| 372 | uptr stats[AllocatorStatCount]; | ||
| 373 | allocator()->GetStats(stats); | ||
| 374 | return stats[AllocatorStatMapped]; | ||
| 375 | } | ||
| 376 | |||
| 377 | uptr __sanitizer_get_free_bytes() { | ||
| 378 | return 1; | ||
| 379 | } | ||
| 380 | |||
| 381 | uptr __sanitizer_get_unmapped_bytes() { | ||
| 382 | return 1; | ||
| 383 | } | ||
| 384 | |||
| 385 | uptr __sanitizer_get_estimated_allocated_size(uptr size) { | ||
| 386 | return size; | ||
| 387 | } | ||
| 388 | |||
| 389 | int __sanitizer_get_ownership(const void *p) { | ||
| 390 | return allocator()->GetBlockBegin(p) != 0; | ||
| 391 | } | ||
| 392 | |||
| 393 | uptr __sanitizer_get_allocated_size(const void *p) { | ||
| 394 | return user_alloc_usable_size(p); | ||
| 395 | } | ||
| 396 | |||
| 397 | void __tsan_on_thread_idle() { | ||
| 398 | ThreadState *thr = cur_thread(); | ||
| 399 | thr->clock.ResetCached(&thr->proc()->clock_cache); | ||
| 400 | thr->last_sleep_clock.ResetCached(&thr->proc()->clock_cache); | ||
| 401 | allocator()->SwallowCache(&thr->proc()->alloc_cache); | ||
| 402 | internal_allocator()->SwallowCache(&thr->proc()->internal_alloc_cache); | ||
| 403 | ctx->metamap.OnProcIdle(thr->proc()); | ||
| 404 | } | ||
| 405 | } // extern "C" | ||
lib/tsan/tsan_mman.h created+89| ... | @@ -0,0 +1,89 @@ | ||
| 1 | //===-- tsan_mman.h ---------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef TSAN_MMAN_H | ||
| 13 | #define TSAN_MMAN_H | ||
| 14 | |||
| 15 | #include "tsan_defs.h" | ||
| 16 | |||
| 17 | namespace __tsan { | ||
| 18 | |||
| 19 | const uptr kDefaultAlignment = 16; | ||
| 20 | |||
| 21 | void InitializeAllocator(); | ||
| 22 | void InitializeAllocatorLate(); | ||
| 23 | void ReplaceSystemMalloc(); | ||
| 24 | void AllocatorProcStart(Processor *proc); | ||
| 25 | void AllocatorProcFinish(Processor *proc); | ||
| 26 | void AllocatorPrintStats(); | ||
| 27 | |||
| 28 | // For user allocations. | ||
| 29 | void *user_alloc_internal(ThreadState *thr, uptr pc, uptr sz, | ||
| 30 | uptr align = kDefaultAlignment, bool signal = true); | ||
| 31 | // Does not accept NULL. | ||
| 32 | void user_free(ThreadState *thr, uptr pc, void *p, bool signal = true); | ||
| 33 | // Interceptor implementations. | ||
| 34 | void *user_alloc(ThreadState *thr, uptr pc, uptr sz); | ||
| 35 | void *user_calloc(ThreadState *thr, uptr pc, uptr sz, uptr n); | ||
| 36 | void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz); | ||
| 37 | void *user_reallocarray(ThreadState *thr, uptr pc, void *p, uptr sz, uptr n); | ||
| 38 | void *user_memalign(ThreadState *thr, uptr pc, uptr align, uptr sz); | ||
| 39 | int user_posix_memalign(ThreadState *thr, uptr pc, void **memptr, uptr align, | ||
| 40 | uptr sz); | ||
| 41 | void *user_aligned_alloc(ThreadState *thr, uptr pc, uptr align, uptr sz); | ||
| 42 | void *user_valloc(ThreadState *thr, uptr pc, uptr sz); | ||
| 43 | void *user_pvalloc(ThreadState *thr, uptr pc, uptr sz); | ||
| 44 | uptr user_alloc_usable_size(const void *p); | ||
| 45 | |||
| 46 | // Invoking malloc/free hooks that may be installed by the user. | ||
| 47 | void invoke_malloc_hook(void *ptr, uptr size); | ||
| 48 | void invoke_free_hook(void *ptr); | ||
| 49 | |||
| 50 | enum MBlockType { | ||
| 51 | MBlockScopedBuf, | ||
| 52 | MBlockString, | ||
| 53 | MBlockStackTrace, | ||
| 54 | MBlockShadowStack, | ||
| 55 | MBlockSync, | ||
| 56 | MBlockClock, | ||
| 57 | MBlockThreadContex, | ||
| 58 | MBlockDeadInfo, | ||
| 59 | MBlockRacyStacks, | ||
| 60 | MBlockRacyAddresses, | ||
| 61 | MBlockAtExit, | ||
| 62 | MBlockFlag, | ||
| 63 | MBlockReport, | ||
| 64 | MBlockReportMop, | ||
| 65 | MBlockReportThread, | ||
| 66 | MBlockReportMutex, | ||
| 67 | MBlockReportLoc, | ||
| 68 | MBlockReportStack, | ||
| 69 | MBlockSuppression, | ||
| 70 | MBlockExpectRace, | ||
| 71 | MBlockSignal, | ||
| 72 | MBlockJmpBuf, | ||
| 73 | |||
| 74 | // This must be the last. | ||
| 75 | MBlockTypeCount | ||
| 76 | }; | ||
| 77 | |||
| 78 | // For internal data structures. | ||
| 79 | void *internal_alloc(MBlockType typ, uptr sz); | ||
| 80 | void internal_free(void *p); | ||
| 81 | |||
| 82 | template <typename T> | ||
| 83 | void DestroyAndFree(T *p) { | ||
| 84 | p->~T(); | ||
| 85 | internal_free(p); | ||
| 86 | } | ||
| 87 | |||
| 88 | } // namespace __tsan | ||
| 89 | #endif // TSAN_MMAN_H | ||
lib/tsan/tsan_mutex.cpp created+289| ... | @@ -0,0 +1,289 @@ | ||
| 1 | //===-- tsan_mutex.cpp ----------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #include "sanitizer_common/sanitizer_libc.h" | ||
| 13 | #include "tsan_mutex.h" | ||
| 14 | #include "tsan_platform.h" | ||
| 15 | #include "tsan_rtl.h" | ||
| 16 | |||
| 17 | namespace __tsan { | ||
| 18 | |||
| 19 | // Simple reader-writer spin-mutex. Optimized for not-so-contended case. | ||
| 20 | // Readers have preference, can possibly starvate writers. | ||
| 21 | |||
| 22 | // The table fixes what mutexes can be locked under what mutexes. | ||
| 23 | // E.g. if the row for MutexTypeThreads contains MutexTypeReport, | ||
| 24 | // then Report mutex can be locked while under Threads mutex. | ||
| 25 | // The leaf mutexes can be locked under any other mutexes. | ||
| 26 | // Recursive locking is not supported. | ||
| 27 | #if SANITIZER_DEBUG && !SANITIZER_GO | ||
| 28 | const MutexType MutexTypeLeaf = (MutexType)-1; | ||
| 29 | static MutexType CanLockTab[MutexTypeCount][MutexTypeCount] = { | ||
| 30 | /*0 MutexTypeInvalid*/ {}, | ||
| 31 | /*1 MutexTypeTrace*/ {MutexTypeLeaf}, | ||
| 32 | /*2 MutexTypeThreads*/ {MutexTypeReport}, | ||
| 33 | /*3 MutexTypeReport*/ {MutexTypeSyncVar, | ||
| 34 | MutexTypeMBlock, MutexTypeJavaMBlock}, | ||
| 35 | /*4 MutexTypeSyncVar*/ {MutexTypeDDetector}, | ||
| 36 | /*5 MutexTypeSyncTab*/ {}, // unused | ||
| 37 | /*6 MutexTypeSlab*/ {MutexTypeLeaf}, | ||
| 38 | /*7 MutexTypeAnnotations*/ {}, | ||
| 39 | /*8 MutexTypeAtExit*/ {MutexTypeSyncVar}, | ||
| 40 | /*9 MutexTypeMBlock*/ {MutexTypeSyncVar}, | ||
| 41 | /*10 MutexTypeJavaMBlock*/ {MutexTypeSyncVar}, | ||
| 42 | /*11 MutexTypeDDetector*/ {}, | ||
| 43 | /*12 MutexTypeFired*/ {MutexTypeLeaf}, | ||
| 44 | /*13 MutexTypeRacy*/ {MutexTypeLeaf}, | ||
| 45 | /*14 MutexTypeGlobalProc*/ {}, | ||
| 46 | }; | ||
| 47 | |||
| 48 | static bool CanLockAdj[MutexTypeCount][MutexTypeCount]; | ||
| 49 | #endif | ||
| 50 | |||
| 51 | void InitializeMutex() { | ||
| 52 | #if SANITIZER_DEBUG && !SANITIZER_GO | ||
| 53 | // Build the "can lock" adjacency matrix. | ||
| 54 | // If [i][j]==true, then one can lock mutex j while under mutex i. | ||
| 55 | const int N = MutexTypeCount; | ||
| 56 | int cnt[N] = {}; | ||
| 57 | bool leaf[N] = {}; | ||
| 58 | for (int i = 1; i < N; i++) { | ||
| 59 | for (int j = 0; j < N; j++) { | ||
| 60 | MutexType z = CanLockTab[i][j]; | ||
| 61 | if (z == MutexTypeInvalid) | ||
| 62 | continue; | ||
| 63 | if (z == MutexTypeLeaf) { | ||
| 64 | CHECK(!leaf[i]); | ||
| 65 | leaf[i] = true; | ||
| 66 | continue; | ||
| 67 | } | ||
| 68 | CHECK(!CanLockAdj[i][(int)z]); | ||
| 69 | CanLockAdj[i][(int)z] = true; | ||
| 70 | cnt[i]++; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | for (int i = 0; i < N; i++) { | ||
| 74 | CHECK(!leaf[i] || cnt[i] == 0); | ||
| 75 | } | ||
| 76 | // Add leaf mutexes. | ||
| 77 | for (int i = 0; i < N; i++) { | ||
| 78 | if (!leaf[i]) | ||
| 79 | continue; | ||
| 80 | for (int j = 0; j < N; j++) { | ||
| 81 | if (i == j || leaf[j] || j == MutexTypeInvalid) | ||
| 82 | continue; | ||
| 83 | CHECK(!CanLockAdj[j][i]); | ||
| 84 | CanLockAdj[j][i] = true; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | // Build the transitive closure. | ||
| 88 | bool CanLockAdj2[MutexTypeCount][MutexTypeCount]; | ||
| 89 | for (int i = 0; i < N; i++) { | ||
| 90 | for (int j = 0; j < N; j++) { | ||
| 91 | CanLockAdj2[i][j] = CanLockAdj[i][j]; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | for (int k = 0; k < N; k++) { | ||
| 95 | for (int i = 0; i < N; i++) { | ||
| 96 | for (int j = 0; j < N; j++) { | ||
| 97 | if (CanLockAdj2[i][k] && CanLockAdj2[k][j]) { | ||
| 98 | CanLockAdj2[i][j] = true; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | } | ||
| 102 | } | ||
| 103 | #if 0 | ||
| 104 | Printf("Can lock graph:\n"); | ||
| 105 | for (int i = 0; i < N; i++) { | ||
| 106 | for (int j = 0; j < N; j++) { | ||
| 107 | Printf("%d ", CanLockAdj[i][j]); | ||
| 108 | } | ||
| 109 | Printf("\n"); | ||
| 110 | } | ||
| 111 | Printf("Can lock graph closure:\n"); | ||
| 112 | for (int i = 0; i < N; i++) { | ||
| 113 | for (int j = 0; j < N; j++) { | ||
| 114 | Printf("%d ", CanLockAdj2[i][j]); | ||
| 115 | } | ||
| 116 | Printf("\n"); | ||
| 117 | } | ||
| 118 | #endif | ||
| 119 | // Verify that the graph is acyclic. | ||
| 120 | for (int i = 0; i < N; i++) { | ||
| 121 | if (CanLockAdj2[i][i]) { | ||
| 122 | Printf("Mutex %d participates in a cycle\n", i); | ||
| 123 | Die(); | ||
| 124 | } | ||
| 125 | } | ||
| 126 | #endif | ||
| 127 | } | ||
| 128 | |||
| 129 | InternalDeadlockDetector::InternalDeadlockDetector() { | ||
| 130 | // Rely on zero initialization because some mutexes can be locked before ctor. | ||
| 131 | } | ||
| 132 | |||
| 133 | #if SANITIZER_DEBUG && !SANITIZER_GO | ||
| 134 | void InternalDeadlockDetector::Lock(MutexType t) { | ||
| 135 | // Printf("LOCK %d @%zu\n", t, seq_ + 1); | ||
| 136 | CHECK_GT(t, MutexTypeInvalid); | ||
| 137 | CHECK_LT(t, MutexTypeCount); | ||
| 138 | u64 max_seq = 0; | ||
| 139 | u64 max_idx = MutexTypeInvalid; | ||
| 140 | for (int i = 0; i != MutexTypeCount; i++) { | ||
| 141 | if (locked_[i] == 0) | ||
| 142 | continue; | ||
| 143 | CHECK_NE(locked_[i], max_seq); | ||
| 144 | if (max_seq < locked_[i]) { | ||
| 145 | max_seq = locked_[i]; | ||
| 146 | max_idx = i; | ||
| 147 | } | ||
| 148 | } | ||
| 149 | locked_[t] = ++seq_; | ||
| 150 | if (max_idx == MutexTypeInvalid) | ||
| 151 | return; | ||
| 152 | // Printf(" last %d @%zu\n", max_idx, max_seq); | ||
| 153 | if (!CanLockAdj[max_idx][t]) { | ||
| 154 | Printf("ThreadSanitizer: internal deadlock detected\n"); | ||
| 155 | Printf("ThreadSanitizer: can't lock %d while under %zu\n", | ||
| 156 | t, (uptr)max_idx); | ||
| 157 | CHECK(0); | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | void InternalDeadlockDetector::Unlock(MutexType t) { | ||
| 162 | // Printf("UNLO %d @%zu #%zu\n", t, seq_, locked_[t]); | ||
| 163 | CHECK(locked_[t]); | ||
| 164 | locked_[t] = 0; | ||
| 165 | } | ||
| 166 | |||
| 167 | void InternalDeadlockDetector::CheckNoLocks() { | ||
| 168 | for (int i = 0; i != MutexTypeCount; i++) { | ||
| 169 | CHECK_EQ(locked_[i], 0); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | #endif | ||
| 173 | |||
| 174 | void CheckNoLocks(ThreadState *thr) { | ||
| 175 | #if SANITIZER_DEBUG && !SANITIZER_GO | ||
| 176 | thr->internal_deadlock_detector.CheckNoLocks(); | ||
| 177 | #endif | ||
| 178 | } | ||
| 179 | |||
| 180 | const uptr kUnlocked = 0; | ||
| 181 | const uptr kWriteLock = 1; | ||
| 182 | const uptr kReadLock = 2; | ||
| 183 | |||
| 184 | class Backoff { | ||
| 185 | public: | ||
| 186 | Backoff() | ||
| 187 | : iter_() { | ||
| 188 | } | ||
| 189 | |||
| 190 | bool Do() { | ||
| 191 | if (iter_++ < kActiveSpinIters) | ||
| 192 | proc_yield(kActiveSpinCnt); | ||
| 193 | else | ||
| 194 | internal_sched_yield(); | ||
| 195 | return true; | ||
| 196 | } | ||
| 197 | |||
| 198 | u64 Contention() const { | ||
| 199 | u64 active = iter_ % kActiveSpinIters; | ||
| 200 | u64 passive = iter_ - active; | ||
| 201 | return active + 10 * passive; | ||
| 202 | } | ||
| 203 | |||
| 204 | private: | ||
| 205 | int iter_; | ||
| 206 | static const int kActiveSpinIters = 10; | ||
| 207 | static const int kActiveSpinCnt = 20; | ||
| 208 | }; | ||
| 209 | |||
| 210 | Mutex::Mutex(MutexType type, StatType stat_type) { | ||
| 211 | CHECK_GT(type, MutexTypeInvalid); | ||
| 212 | CHECK_LT(type, MutexTypeCount); | ||
| 213 | #if SANITIZER_DEBUG | ||
| 214 | type_ = type; | ||
| 215 | #endif | ||
| 216 | #if TSAN_COLLECT_STATS | ||
| 217 | stat_type_ = stat_type; | ||
| 218 | #endif | ||
| 219 | atomic_store(&state_, kUnlocked, memory_order_relaxed); | ||
| 220 | } | ||
| 221 | |||
| 222 | Mutex::~Mutex() { | ||
| 223 | CHECK_EQ(atomic_load(&state_, memory_order_relaxed), kUnlocked); | ||
| 224 | } | ||
| 225 | |||
| 226 | void Mutex::Lock() { | ||
| 227 | #if SANITIZER_DEBUG && !SANITIZER_GO | ||
| 228 | cur_thread()->internal_deadlock_detector.Lock(type_); | ||
| 229 | #endif | ||
| 230 | uptr cmp = kUnlocked; | ||
| 231 | if (atomic_compare_exchange_strong(&state_, &cmp, kWriteLock, | ||
| 232 | memory_order_acquire)) | ||
| 233 | return; | ||
| 234 | for (Backoff backoff; backoff.Do();) { | ||
| 235 | if (atomic_load(&state_, memory_order_relaxed) == kUnlocked) { | ||
| 236 | cmp = kUnlocked; | ||
| 237 | if (atomic_compare_exchange_weak(&state_, &cmp, kWriteLock, | ||
| 238 | memory_order_acquire)) { | ||
| 239 | #if TSAN_COLLECT_STATS && !SANITIZER_GO | ||
| 240 | StatInc(cur_thread(), stat_type_, backoff.Contention()); | ||
| 241 | #endif | ||
| 242 | return; | ||
| 243 | } | ||
| 244 | } | ||
| 245 | } | ||
| 246 | } | ||
| 247 | |||
| 248 | void Mutex::Unlock() { | ||
| 249 | uptr prev = atomic_fetch_sub(&state_, kWriteLock, memory_order_release); | ||
| 250 | (void)prev; | ||
| 251 | DCHECK_NE(prev & kWriteLock, 0); | ||
| 252 | #if SANITIZER_DEBUG && !SANITIZER_GO | ||
| 253 | cur_thread()->internal_deadlock_detector.Unlock(type_); | ||
| 254 | #endif | ||
| 255 | } | ||
| 256 | |||
| 257 | void Mutex::ReadLock() { | ||
| 258 | #if SANITIZER_DEBUG && !SANITIZER_GO | ||
| 259 | cur_thread()->internal_deadlock_detector.Lock(type_); | ||
| 260 | #endif | ||
| 261 | uptr prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire); | ||
| 262 | if ((prev & kWriteLock) == 0) | ||
| 263 | return; | ||
| 264 | for (Backoff backoff; backoff.Do();) { | ||
| 265 | prev = atomic_load(&state_, memory_order_acquire); | ||
| 266 | if ((prev & kWriteLock) == 0) { | ||
| 267 | #if TSAN_COLLECT_STATS && !SANITIZER_GO | ||
| 268 | StatInc(cur_thread(), stat_type_, backoff.Contention()); | ||
| 269 | #endif | ||
| 270 | return; | ||
| 271 | } | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | void Mutex::ReadUnlock() { | ||
| 276 | uptr prev = atomic_fetch_sub(&state_, kReadLock, memory_order_release); | ||
| 277 | (void)prev; | ||
| 278 | DCHECK_EQ(prev & kWriteLock, 0); | ||
| 279 | DCHECK_GT(prev & ~kWriteLock, 0); | ||
| 280 | #if SANITIZER_DEBUG && !SANITIZER_GO | ||
| 281 | cur_thread()->internal_deadlock_detector.Unlock(type_); | ||
| 282 | #endif | ||
| 283 | } | ||
| 284 | |||
| 285 | void Mutex::CheckLocked() { | ||
| 286 | CHECK_NE(atomic_load(&state_, memory_order_relaxed), 0); | ||
| 287 | } | ||
| 288 | |||
| 289 | } // namespace __tsan | ||
lib/tsan/tsan_mutex.h created+90| ... | @@ -0,0 +1,90 @@ | ||
| 1 | //===-- tsan_mutex.h --------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef TSAN_MUTEX_H | ||
| 13 | #define TSAN_MUTEX_H | ||
| 14 | |||
| 15 | #include "sanitizer_common/sanitizer_atomic.h" | ||
| 16 | #include "sanitizer_common/sanitizer_mutex.h" | ||
| 17 | #include "tsan_defs.h" | ||
| 18 | |||
| 19 | namespace __tsan { | ||
| 20 | |||
| 21 | enum MutexType { | ||
| 22 | MutexTypeInvalid, | ||
| 23 | MutexTypeTrace, | ||
| 24 | MutexTypeThreads, | ||
| 25 | MutexTypeReport, | ||
| 26 | MutexTypeSyncVar, | ||
| 27 | MutexTypeSyncTab, | ||
| 28 | MutexTypeSlab, | ||
| 29 | MutexTypeAnnotations, | ||
| 30 | MutexTypeAtExit, | ||
| 31 | MutexTypeMBlock, | ||
| 32 | MutexTypeJavaMBlock, | ||
| 33 | MutexTypeDDetector, | ||
| 34 | MutexTypeFired, | ||
| 35 | MutexTypeRacy, | ||
| 36 | MutexTypeGlobalProc, | ||
| 37 | |||
| 38 | // This must be the last. | ||
| 39 | MutexTypeCount | ||
| 40 | }; | ||
| 41 | |||
| 42 | class Mutex { | ||
| 43 | public: | ||
| 44 | explicit Mutex(MutexType type, StatType stat_type); | ||
| 45 | ~Mutex(); | ||
| 46 | |||
| 47 | void Lock(); | ||
| 48 | void Unlock(); | ||
| 49 | |||
| 50 | void ReadLock(); | ||
| 51 | void ReadUnlock(); | ||
| 52 | |||
| 53 | void CheckLocked(); | ||
| 54 | |||
| 55 | private: | ||
| 56 | atomic_uintptr_t state_; | ||
| 57 | #if SANITIZER_DEBUG | ||
| 58 | MutexType type_; | ||
| 59 | #endif | ||
| 60 | #if TSAN_COLLECT_STATS | ||
| 61 | StatType stat_type_; | ||
| 62 | #endif | ||
| 63 | |||
| 64 | Mutex(const Mutex&); | ||
| 65 | void operator = (const Mutex&); | ||
| 66 | }; | ||
| 67 | |||
| 68 | typedef GenericScopedLock<Mutex> Lock; | ||
| 69 | typedef GenericScopedReadLock<Mutex> ReadLock; | ||
| 70 | |||
| 71 | class InternalDeadlockDetector { | ||
| 72 | public: | ||
| 73 | InternalDeadlockDetector(); | ||
| 74 | void Lock(MutexType t); | ||
| 75 | void Unlock(MutexType t); | ||
| 76 | void CheckNoLocks(); | ||
| 77 | private: | ||
| 78 | u64 seq_; | ||
| 79 | u64 locked_[MutexTypeCount]; | ||
| 80 | }; | ||
| 81 | |||
| 82 | void InitializeMutex(); | ||
| 83 | |||
| 84 | // Checks that the current thread does not hold any runtime locks | ||
| 85 | // (e.g. when returning from an interceptor). | ||
| 86 | void CheckNoLocks(ThreadState *thr); | ||
| 87 | |||
| 88 | } // namespace __tsan | ||
| 89 | |||
| 90 | #endif // TSAN_MUTEX_H | ||
lib/tsan/tsan_mutexset.cpp created+88| ... | @@ -0,0 +1,88 @@ | ||
| 1 | //===-- tsan_mutexset.cpp -------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #include "tsan_mutexset.h" | ||
| 13 | #include "tsan_rtl.h" | ||
| 14 | |||
| 15 | namespace __tsan { | ||
| 16 | |||
| 17 | const uptr MutexSet::kMaxSize; | ||
| 18 | |||
| 19 | MutexSet::MutexSet() { | ||
| 20 | size_ = 0; | ||
| 21 | internal_memset(&descs_, 0, sizeof(descs_)); | ||
| 22 | } | ||
| 23 | |||
| 24 | void MutexSet::Add(u64 id, bool write, u64 epoch) { | ||
| 25 | // Look up existing mutex with the same id. | ||
| 26 | for (uptr i = 0; i < size_; i++) { | ||
| 27 | if (descs_[i].id == id) { | ||
| 28 | descs_[i].count++; | ||
| 29 | descs_[i].epoch = epoch; | ||
| 30 | return; | ||
| 31 | } | ||
| 32 | } | ||
| 33 | // On overflow, find the oldest mutex and drop it. | ||
| 34 | if (size_ == kMaxSize) { | ||
| 35 | u64 minepoch = (u64)-1; | ||
| 36 | u64 mini = (u64)-1; | ||
| 37 | for (uptr i = 0; i < size_; i++) { | ||
| 38 | if (descs_[i].epoch < minepoch) { | ||
| 39 | minepoch = descs_[i].epoch; | ||
| 40 | mini = i; | ||
| 41 | } | ||
| 42 | } | ||
| 43 | RemovePos(mini); | ||
| 44 | CHECK_EQ(size_, kMaxSize - 1); | ||
| 45 | } | ||
| 46 | // Add new mutex descriptor. | ||
| 47 | descs_[size_].id = id; | ||
| 48 | descs_[size_].write = write; | ||
| 49 | descs_[size_].epoch = epoch; | ||
| 50 | descs_[size_].count = 1; | ||
| 51 | size_++; | ||
| 52 | } | ||
| 53 | |||
| 54 | void MutexSet::Del(u64 id, bool write) { | ||
| 55 | for (uptr i = 0; i < size_; i++) { | ||
| 56 | if (descs_[i].id == id) { | ||
| 57 | if (--descs_[i].count == 0) | ||
| 58 | RemovePos(i); | ||
| 59 | return; | ||
| 60 | } | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | void MutexSet::Remove(u64 id) { | ||
| 65 | for (uptr i = 0; i < size_; i++) { | ||
| 66 | if (descs_[i].id == id) { | ||
| 67 | RemovePos(i); | ||
| 68 | return; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | void MutexSet::RemovePos(uptr i) { | ||
| 74 | CHECK_LT(i, size_); | ||
| 75 | descs_[i] = descs_[size_ - 1]; | ||
| 76 | size_--; | ||
| 77 | } | ||
| 78 | |||
| 79 | uptr MutexSet::Size() const { | ||
| 80 | return size_; | ||
| 81 | } | ||
| 82 | |||
| 83 | MutexSet::Desc MutexSet::Get(uptr i) const { | ||
| 84 | CHECK_LT(i, size_); | ||
| 85 | return descs_[i]; | ||
| 86 | } | ||
| 87 | |||
| 88 | } // namespace __tsan | ||
lib/tsan/tsan_mutexset.h created+69| ... | @@ -0,0 +1,69 @@ | ||
| 1 | //===-- tsan_mutexset.h -----------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | // MutexSet holds the set of mutexes currently held by a thread. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | #ifndef TSAN_MUTEXSET_H | ||
| 14 | #define TSAN_MUTEXSET_H | ||
| 15 | |||
| 16 | #include "tsan_defs.h" | ||
| 17 | |||
| 18 | namespace __tsan { | ||
| 19 | |||
| 20 | class MutexSet { | ||
| 21 | public: | ||
| 22 | // Holds limited number of mutexes. | ||
| 23 | // The oldest mutexes are discarded on overflow. | ||
| 24 | static const uptr kMaxSize = 16; | ||
| 25 | struct Desc { | ||
| 26 | u64 id; | ||
| 27 | u64 epoch; | ||
| 28 | int count; | ||
| 29 | bool write; | ||
| 30 | }; | ||
| 31 | |||
| 32 | MutexSet(); | ||
| 33 | // The 'id' is obtained from SyncVar::GetId(). | ||
| 34 | void Add(u64 id, bool write, u64 epoch); | ||
| 35 | void Del(u64 id, bool write); | ||
| 36 | void Remove(u64 id); // Removes the mutex completely (if it's destroyed). | ||
| 37 | uptr Size() const; | ||
| 38 | Desc Get(uptr i) const; | ||
| 39 | |||
| 40 | void operator=(const MutexSet &other) { | ||
| 41 | internal_memcpy(this, &other, sizeof(*this)); | ||
| 42 | } | ||
| 43 | |||
| 44 | private: | ||
| 45 | #if !SANITIZER_GO | ||
| 46 | uptr size_; | ||
| 47 | Desc descs_[kMaxSize]; | ||
| 48 | #endif | ||
| 49 | |||
| 50 | void RemovePos(uptr i); | ||
| 51 | MutexSet(const MutexSet&); | ||
| 52 | }; | ||
| 53 | |||
| 54 | // Go does not have mutexes, so do not spend memory and time. | ||
| 55 | // (Go sync.Mutex is actually a semaphore -- can be unlocked | ||
| 56 | // in different goroutine). | ||
| 57 | #if SANITIZER_GO | ||
| 58 | MutexSet::MutexSet() {} | ||
| 59 | void MutexSet::Add(u64 id, bool write, u64 epoch) {} | ||
| 60 | void MutexSet::Del(u64 id, bool write) {} | ||
| 61 | void MutexSet::Remove(u64 id) {} | ||
| 62 | void MutexSet::RemovePos(uptr i) {} | ||
| 63 | uptr MutexSet::Size() const { return 0; } | ||
| 64 | MutexSet::Desc MutexSet::Get(uptr i) const { return Desc(); } | ||
| 65 | #endif | ||
| 66 | |||
| 67 | } // namespace __tsan | ||
| 68 | |||
| 69 | #endif // TSAN_MUTEXSET_H | ||
lib/tsan/tsan_platform.h created+1028| ... | @@ -0,0 +1,1028 @@ | ||
| 1 | //===-- tsan_platform.h -----------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | // Platform-specific code. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #ifndef TSAN_PLATFORM_H | ||
| 15 | #define TSAN_PLATFORM_H | ||
| 16 | |||
| 17 | #if !defined(__LP64__) && !defined(_WIN64) | ||
| 18 | # error "Only 64-bit is supported" | ||
| 19 | #endif | ||
| 20 | |||
| 21 | #include "tsan_defs.h" | ||
| 22 | #include "tsan_trace.h" | ||
| 23 | |||
| 24 | namespace __tsan { | ||
| 25 | |||
| 26 | #if !SANITIZER_GO | ||
| 27 | |||
| 28 | #if defined(__x86_64__) | ||
| 29 | /* | ||
| 30 | C/C++ on linux/x86_64 and freebsd/x86_64 | ||
| 31 | 0000 0000 1000 - 0080 0000 0000: main binary and/or MAP_32BIT mappings (512GB) | ||
| 32 | 0040 0000 0000 - 0100 0000 0000: - | ||
| 33 | 0100 0000 0000 - 2000 0000 0000: shadow | ||
| 34 | 2000 0000 0000 - 3000 0000 0000: - | ||
| 35 | 3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects) | ||
| 36 | 4000 0000 0000 - 5500 0000 0000: - | ||
| 37 | 5500 0000 0000 - 5680 0000 0000: pie binaries without ASLR or on 4.1+ kernels | ||
| 38 | 5680 0000 0000 - 6000 0000 0000: - | ||
| 39 | 6000 0000 0000 - 6200 0000 0000: traces | ||
| 40 | 6200 0000 0000 - 7d00 0000 0000: - | ||
| 41 | 7b00 0000 0000 - 7c00 0000 0000: heap | ||
| 42 | 7c00 0000 0000 - 7e80 0000 0000: - | ||
| 43 | 7e80 0000 0000 - 8000 0000 0000: modules and main thread stack | ||
| 44 | |||
| 45 | C/C++ on netbsd/amd64 can reuse the same mapping: | ||
| 46 | * The address space starts from 0x1000 (option with 0x0) and ends with | ||
| 47 | 0x7f7ffffff000. | ||
| 48 | * LoAppMem-kHeapMemEnd can be reused as it is. | ||
| 49 | * No VDSO support. | ||
| 50 | * No MidAppMem region. | ||
| 51 | * No additional HeapMem region. | ||
| 52 | * HiAppMem contains the stack, loader, shared libraries and heap. | ||
| 53 | * Stack on NetBSD/amd64 has prereserved 128MB. | ||
| 54 | * Heap grows downwards (top-down). | ||
| 55 | * ASLR must be disabled per-process or globally. | ||
| 56 | |||
| 57 | */ | ||
| 58 | struct Mapping { | ||
| 59 | static const uptr kMetaShadowBeg = 0x300000000000ull; | ||
| 60 | static const uptr kMetaShadowEnd = 0x340000000000ull; | ||
| 61 | static const uptr kTraceMemBeg = 0x600000000000ull; | ||
| 62 | static const uptr kTraceMemEnd = 0x620000000000ull; | ||
| 63 | static const uptr kShadowBeg = 0x010000000000ull; | ||
| 64 | static const uptr kShadowEnd = 0x200000000000ull; | ||
| 65 | static const uptr kHeapMemBeg = 0x7b0000000000ull; | ||
| 66 | static const uptr kHeapMemEnd = 0x7c0000000000ull; | ||
| 67 | static const uptr kLoAppMemBeg = 0x000000001000ull; | ||
| 68 | static const uptr kLoAppMemEnd = 0x008000000000ull; | ||
| 69 | static const uptr kMidAppMemBeg = 0x550000000000ull; | ||
| 70 | static const uptr kMidAppMemEnd = 0x568000000000ull; | ||
| 71 | static const uptr kHiAppMemBeg = 0x7e8000000000ull; | ||
| 72 | static const uptr kHiAppMemEnd = 0x800000000000ull; | ||
| 73 | static const uptr kAppMemMsk = 0x780000000000ull; | ||
| 74 | static const uptr kAppMemXor = 0x040000000000ull; | ||
| 75 | static const uptr kVdsoBeg = 0xf000000000000000ull; | ||
| 76 | }; | ||
| 77 | |||
| 78 | #define TSAN_MID_APP_RANGE 1 | ||
| 79 | #elif defined(__mips64) | ||
| 80 | /* | ||
| 81 | C/C++ on linux/mips64 (40-bit VMA) | ||
| 82 | 0000 0000 00 - 0100 0000 00: - (4 GB) | ||
| 83 | 0100 0000 00 - 0200 0000 00: main binary (4 GB) | ||
| 84 | 0200 0000 00 - 2000 0000 00: - (120 GB) | ||
| 85 | 2000 0000 00 - 4000 0000 00: shadow (128 GB) | ||
| 86 | 4000 0000 00 - 5000 0000 00: metainfo (memory blocks and sync objects) (64 GB) | ||
| 87 | 5000 0000 00 - aa00 0000 00: - (360 GB) | ||
| 88 | aa00 0000 00 - ab00 0000 00: main binary (PIE) (4 GB) | ||
| 89 | ab00 0000 00 - b000 0000 00: - (20 GB) | ||
| 90 | b000 0000 00 - b200 0000 00: traces (8 GB) | ||
| 91 | b200 0000 00 - fe00 0000 00: - (304 GB) | ||
| 92 | fe00 0000 00 - ff00 0000 00: heap (4 GB) | ||
| 93 | ff00 0000 00 - ff80 0000 00: - (2 GB) | ||
| 94 | ff80 0000 00 - ffff ffff ff: modules and main thread stack (<2 GB) | ||
| 95 | */ | ||
| 96 | struct Mapping { | ||
| 97 | static const uptr kMetaShadowBeg = 0x4000000000ull; | ||
| 98 | static const uptr kMetaShadowEnd = 0x5000000000ull; | ||
| 99 | static const uptr kTraceMemBeg = 0xb000000000ull; | ||
| 100 | static const uptr kTraceMemEnd = 0xb200000000ull; | ||
| 101 | static const uptr kShadowBeg = 0x2000000000ull; | ||
| 102 | static const uptr kShadowEnd = 0x4000000000ull; | ||
| 103 | static const uptr kHeapMemBeg = 0xfe00000000ull; | ||
| 104 | static const uptr kHeapMemEnd = 0xff00000000ull; | ||
| 105 | static const uptr kLoAppMemBeg = 0x0100000000ull; | ||
| 106 | static const uptr kLoAppMemEnd = 0x0200000000ull; | ||
| 107 | static const uptr kMidAppMemBeg = 0xaa00000000ull; | ||
| 108 | static const uptr kMidAppMemEnd = 0xab00000000ull; | ||
| 109 | static const uptr kHiAppMemBeg = 0xff80000000ull; | ||
| 110 | static const uptr kHiAppMemEnd = 0xffffffffffull; | ||
| 111 | static const uptr kAppMemMsk = 0xf800000000ull; | ||
| 112 | static const uptr kAppMemXor = 0x0800000000ull; | ||
| 113 | static const uptr kVdsoBeg = 0xfffff00000ull; | ||
| 114 | }; | ||
| 115 | |||
| 116 | #define TSAN_MID_APP_RANGE 1 | ||
| 117 | #elif defined(__aarch64__) && defined(__APPLE__) | ||
| 118 | /* | ||
| 119 | C/C++ on Darwin/iOS/ARM64 (36-bit VMA, 64 GB VM) | ||
| 120 | 0000 0000 00 - 0100 0000 00: - (4 GB) | ||
| 121 | 0100 0000 00 - 0200 0000 00: main binary, modules, thread stacks (4 GB) | ||
| 122 | 0200 0000 00 - 0300 0000 00: heap (4 GB) | ||
| 123 | 0300 0000 00 - 0400 0000 00: - (4 GB) | ||
| 124 | 0400 0000 00 - 0c00 0000 00: shadow memory (32 GB) | ||
| 125 | 0c00 0000 00 - 0d00 0000 00: - (4 GB) | ||
| 126 | 0d00 0000 00 - 0e00 0000 00: metainfo (4 GB) | ||
| 127 | 0e00 0000 00 - 0f00 0000 00: - (4 GB) | ||
| 128 | 0f00 0000 00 - 0fc0 0000 00: traces (3 GB) | ||
| 129 | 0fc0 0000 00 - 1000 0000 00: - | ||
| 130 | */ | ||
| 131 | struct Mapping { | ||
| 132 | static const uptr kLoAppMemBeg = 0x0100000000ull; | ||
| 133 | static const uptr kLoAppMemEnd = 0x0200000000ull; | ||
| 134 | static const uptr kHeapMemBeg = 0x0200000000ull; | ||
| 135 | static const uptr kHeapMemEnd = 0x0300000000ull; | ||
| 136 | static const uptr kShadowBeg = 0x0400000000ull; | ||
| 137 | static const uptr kShadowEnd = 0x0c00000000ull; | ||
| 138 | static const uptr kMetaShadowBeg = 0x0d00000000ull; | ||
| 139 | static const uptr kMetaShadowEnd = 0x0e00000000ull; | ||
| 140 | static const uptr kTraceMemBeg = 0x0f00000000ull; | ||
| 141 | static const uptr kTraceMemEnd = 0x0fc0000000ull; | ||
| 142 | static const uptr kHiAppMemBeg = 0x0fc0000000ull; | ||
| 143 | static const uptr kHiAppMemEnd = 0x0fc0000000ull; | ||
| 144 | static const uptr kAppMemMsk = 0x0ull; | ||
| 145 | static const uptr kAppMemXor = 0x0ull; | ||
| 146 | static const uptr kVdsoBeg = 0x7000000000000000ull; | ||
| 147 | }; | ||
| 148 | |||
| 149 | #elif defined(__aarch64__) | ||
| 150 | // AArch64 supports multiple VMA which leads to multiple address transformation | ||
| 151 | // functions. To support these multiple VMAS transformations and mappings TSAN | ||
| 152 | // runtime for AArch64 uses an external memory read (vmaSize) to select which | ||
| 153 | // mapping to use. Although slower, it make a same instrumented binary run on | ||
| 154 | // multiple kernels. | ||
| 155 | |||
| 156 | /* | ||
| 157 | C/C++ on linux/aarch64 (39-bit VMA) | ||
| 158 | 0000 0010 00 - 0100 0000 00: main binary | ||
| 159 | 0100 0000 00 - 0800 0000 00: - | ||
| 160 | 0800 0000 00 - 2000 0000 00: shadow memory | ||
| 161 | 2000 0000 00 - 3100 0000 00: - | ||
| 162 | 3100 0000 00 - 3400 0000 00: metainfo | ||
| 163 | 3400 0000 00 - 5500 0000 00: - | ||
| 164 | 5500 0000 00 - 5600 0000 00: main binary (PIE) | ||
| 165 | 5600 0000 00 - 6000 0000 00: - | ||
| 166 | 6000 0000 00 - 6200 0000 00: traces | ||
| 167 | 6200 0000 00 - 7d00 0000 00: - | ||
| 168 | 7c00 0000 00 - 7d00 0000 00: heap | ||
| 169 | 7d00 0000 00 - 7fff ffff ff: modules and main thread stack | ||
| 170 | */ | ||
| 171 | struct Mapping39 { | ||
| 172 | static const uptr kLoAppMemBeg = 0x0000001000ull; | ||
| 173 | static const uptr kLoAppMemEnd = 0x0100000000ull; | ||
| 174 | static const uptr kShadowBeg = 0x0800000000ull; | ||
| 175 | static const uptr kShadowEnd = 0x2000000000ull; | ||
| 176 | static const uptr kMetaShadowBeg = 0x3100000000ull; | ||
| 177 | static const uptr kMetaShadowEnd = 0x3400000000ull; | ||
| 178 | static const uptr kMidAppMemBeg = 0x5500000000ull; | ||
| 179 | static const uptr kMidAppMemEnd = 0x5600000000ull; | ||
| 180 | static const uptr kTraceMemBeg = 0x6000000000ull; | ||
| 181 | static const uptr kTraceMemEnd = 0x6200000000ull; | ||
| 182 | static const uptr kHeapMemBeg = 0x7c00000000ull; | ||
| 183 | static const uptr kHeapMemEnd = 0x7d00000000ull; | ||
| 184 | static const uptr kHiAppMemBeg = 0x7e00000000ull; | ||
| 185 | static const uptr kHiAppMemEnd = 0x7fffffffffull; | ||
| 186 | static const uptr kAppMemMsk = 0x7800000000ull; | ||
| 187 | static const uptr kAppMemXor = 0x0200000000ull; | ||
| 188 | static const uptr kVdsoBeg = 0x7f00000000ull; | ||
| 189 | }; | ||
| 190 | |||
| 191 | /* | ||
| 192 | C/C++ on linux/aarch64 (42-bit VMA) | ||
| 193 | 00000 0010 00 - 01000 0000 00: main binary | ||
| 194 | 01000 0000 00 - 10000 0000 00: - | ||
| 195 | 10000 0000 00 - 20000 0000 00: shadow memory | ||
| 196 | 20000 0000 00 - 26000 0000 00: - | ||
| 197 | 26000 0000 00 - 28000 0000 00: metainfo | ||
| 198 | 28000 0000 00 - 2aa00 0000 00: - | ||
| 199 | 2aa00 0000 00 - 2ab00 0000 00: main binary (PIE) | ||
| 200 | 2ab00 0000 00 - 36200 0000 00: - | ||
| 201 | 36200 0000 00 - 36240 0000 00: traces | ||
| 202 | 36240 0000 00 - 3e000 0000 00: - | ||
| 203 | 3e000 0000 00 - 3f000 0000 00: heap | ||
| 204 | 3f000 0000 00 - 3ffff ffff ff: modules and main thread stack | ||
| 205 | */ | ||
| 206 | struct Mapping42 { | ||
| 207 | static const uptr kLoAppMemBeg = 0x00000001000ull; | ||
| 208 | static const uptr kLoAppMemEnd = 0x01000000000ull; | ||
| 209 | static const uptr kShadowBeg = 0x10000000000ull; | ||
| 210 | static const uptr kShadowEnd = 0x20000000000ull; | ||
| 211 | static const uptr kMetaShadowBeg = 0x26000000000ull; | ||
| 212 | static const uptr kMetaShadowEnd = 0x28000000000ull; | ||
| 213 | static const uptr kMidAppMemBeg = 0x2aa00000000ull; | ||
| 214 | static const uptr kMidAppMemEnd = 0x2ab00000000ull; | ||
| 215 | static const uptr kTraceMemBeg = 0x36200000000ull; | ||
| 216 | static const uptr kTraceMemEnd = 0x36400000000ull; | ||
| 217 | static const uptr kHeapMemBeg = 0x3e000000000ull; | ||
| 218 | static const uptr kHeapMemEnd = 0x3f000000000ull; | ||
| 219 | static const uptr kHiAppMemBeg = 0x3f000000000ull; | ||
| 220 | static const uptr kHiAppMemEnd = 0x3ffffffffffull; | ||
| 221 | static const uptr kAppMemMsk = 0x3c000000000ull; | ||
| 222 | static const uptr kAppMemXor = 0x04000000000ull; | ||
| 223 | static const uptr kVdsoBeg = 0x37f00000000ull; | ||
| 224 | }; | ||
| 225 | |||
| 226 | struct Mapping48 { | ||
| 227 | static const uptr kLoAppMemBeg = 0x0000000001000ull; | ||
| 228 | static const uptr kLoAppMemEnd = 0x0000200000000ull; | ||
| 229 | static const uptr kShadowBeg = 0x0002000000000ull; | ||
| 230 | static const uptr kShadowEnd = 0x0004000000000ull; | ||
| 231 | static const uptr kMetaShadowBeg = 0x0005000000000ull; | ||
| 232 | static const uptr kMetaShadowEnd = 0x0006000000000ull; | ||
| 233 | static const uptr kMidAppMemBeg = 0x0aaaa00000000ull; | ||
| 234 | static const uptr kMidAppMemEnd = 0x0aaaf00000000ull; | ||
| 235 | static const uptr kTraceMemBeg = 0x0f06000000000ull; | ||
| 236 | static const uptr kTraceMemEnd = 0x0f06200000000ull; | ||
| 237 | static const uptr kHeapMemBeg = 0x0ffff00000000ull; | ||
| 238 | static const uptr kHeapMemEnd = 0x0ffff00000000ull; | ||
| 239 | static const uptr kHiAppMemBeg = 0x0ffff00000000ull; | ||
| 240 | static const uptr kHiAppMemEnd = 0x1000000000000ull; | ||
| 241 | static const uptr kAppMemMsk = 0x0fff800000000ull; | ||
| 242 | static const uptr kAppMemXor = 0x0000800000000ull; | ||
| 243 | static const uptr kVdsoBeg = 0xffff000000000ull; | ||
| 244 | }; | ||
| 245 | |||
| 246 | // Indicates the runtime will define the memory regions at runtime. | ||
| 247 | #define TSAN_RUNTIME_VMA 1 | ||
| 248 | // Indicates that mapping defines a mid range memory segment. | ||
| 249 | #define TSAN_MID_APP_RANGE 1 | ||
| 250 | #elif defined(__powerpc64__) | ||
| 251 | // PPC64 supports multiple VMA which leads to multiple address transformation | ||
| 252 | // functions. To support these multiple VMAS transformations and mappings TSAN | ||
| 253 | // runtime for PPC64 uses an external memory read (vmaSize) to select which | ||
| 254 | // mapping to use. Although slower, it make a same instrumented binary run on | ||
| 255 | // multiple kernels. | ||
| 256 | |||
| 257 | /* | ||
| 258 | C/C++ on linux/powerpc64 (44-bit VMA) | ||
| 259 | 0000 0000 0100 - 0001 0000 0000: main binary | ||
| 260 | 0001 0000 0000 - 0001 0000 0000: - | ||
| 261 | 0001 0000 0000 - 0b00 0000 0000: shadow | ||
| 262 | 0b00 0000 0000 - 0b00 0000 0000: - | ||
| 263 | 0b00 0000 0000 - 0d00 0000 0000: metainfo (memory blocks and sync objects) | ||
| 264 | 0d00 0000 0000 - 0d00 0000 0000: - | ||
| 265 | 0d00 0000 0000 - 0f00 0000 0000: traces | ||
| 266 | 0f00 0000 0000 - 0f00 0000 0000: - | ||
| 267 | 0f00 0000 0000 - 0f50 0000 0000: heap | ||
| 268 | 0f50 0000 0000 - 0f60 0000 0000: - | ||
| 269 | 0f60 0000 0000 - 1000 0000 0000: modules and main thread stack | ||
| 270 | */ | ||
| 271 | struct Mapping44 { | ||
| 272 | static const uptr kMetaShadowBeg = 0x0b0000000000ull; | ||
| 273 | static const uptr kMetaShadowEnd = 0x0d0000000000ull; | ||
| 274 | static const uptr kTraceMemBeg = 0x0d0000000000ull; | ||
| 275 | static const uptr kTraceMemEnd = 0x0f0000000000ull; | ||
| 276 | static const uptr kShadowBeg = 0x000100000000ull; | ||
| 277 | static const uptr kShadowEnd = 0x0b0000000000ull; | ||
| 278 | static const uptr kLoAppMemBeg = 0x000000000100ull; | ||
| 279 | static const uptr kLoAppMemEnd = 0x000100000000ull; | ||
| 280 | static const uptr kHeapMemBeg = 0x0f0000000000ull; | ||
| 281 | static const uptr kHeapMemEnd = 0x0f5000000000ull; | ||
| 282 | static const uptr kHiAppMemBeg = 0x0f6000000000ull; | ||
| 283 | static const uptr kHiAppMemEnd = 0x100000000000ull; // 44 bits | ||
| 284 | static const uptr kAppMemMsk = 0x0f0000000000ull; | ||
| 285 | static const uptr kAppMemXor = 0x002100000000ull; | ||
| 286 | static const uptr kVdsoBeg = 0x3c0000000000000ull; | ||
| 287 | }; | ||
| 288 | |||
| 289 | /* | ||
| 290 | C/C++ on linux/powerpc64 (46-bit VMA) | ||
| 291 | 0000 0000 1000 - 0100 0000 0000: main binary | ||
| 292 | 0100 0000 0000 - 0200 0000 0000: - | ||
| 293 | 0100 0000 0000 - 1000 0000 0000: shadow | ||
| 294 | 1000 0000 0000 - 1000 0000 0000: - | ||
| 295 | 1000 0000 0000 - 2000 0000 0000: metainfo (memory blocks and sync objects) | ||
| 296 | 2000 0000 0000 - 2000 0000 0000: - | ||
| 297 | 2000 0000 0000 - 2200 0000 0000: traces | ||
| 298 | 2200 0000 0000 - 3d00 0000 0000: - | ||
| 299 | 3d00 0000 0000 - 3e00 0000 0000: heap | ||
| 300 | 3e00 0000 0000 - 3e80 0000 0000: - | ||
| 301 | 3e80 0000 0000 - 4000 0000 0000: modules and main thread stack | ||
| 302 | */ | ||
| 303 | struct Mapping46 { | ||
| 304 | static const uptr kMetaShadowBeg = 0x100000000000ull; | ||
| 305 | static const uptr kMetaShadowEnd = 0x200000000000ull; | ||
| 306 | static const uptr kTraceMemBeg = 0x200000000000ull; | ||
| 307 | static const uptr kTraceMemEnd = 0x220000000000ull; | ||
| 308 | static const uptr kShadowBeg = 0x010000000000ull; | ||
| 309 | static const uptr kShadowEnd = 0x100000000000ull; | ||
| 310 | static const uptr kHeapMemBeg = 0x3d0000000000ull; | ||
| 311 | static const uptr kHeapMemEnd = 0x3e0000000000ull; | ||
| 312 | static const uptr kLoAppMemBeg = 0x000000001000ull; | ||
| 313 | static const uptr kLoAppMemEnd = 0x010000000000ull; | ||
| 314 | static const uptr kHiAppMemBeg = 0x3e8000000000ull; | ||
| 315 | static const uptr kHiAppMemEnd = 0x400000000000ull; // 46 bits | ||
| 316 | static const uptr kAppMemMsk = 0x3c0000000000ull; | ||
| 317 | static const uptr kAppMemXor = 0x020000000000ull; | ||
| 318 | static const uptr kVdsoBeg = 0x7800000000000000ull; | ||
| 319 | }; | ||
| 320 | |||
| 321 | /* | ||
| 322 | C/C++ on linux/powerpc64 (47-bit VMA) | ||
| 323 | 0000 0000 1000 - 0100 0000 0000: main binary | ||
| 324 | 0100 0000 0000 - 0200 0000 0000: - | ||
| 325 | 0100 0000 0000 - 1000 0000 0000: shadow | ||
| 326 | 1000 0000 0000 - 1000 0000 0000: - | ||
| 327 | 1000 0000 0000 - 2000 0000 0000: metainfo (memory blocks and sync objects) | ||
| 328 | 2000 0000 0000 - 2000 0000 0000: - | ||
| 329 | 2000 0000 0000 - 2200 0000 0000: traces | ||
| 330 | 2200 0000 0000 - 7d00 0000 0000: - | ||
| 331 | 7d00 0000 0000 - 7e00 0000 0000: heap | ||
| 332 | 7e00 0000 0000 - 7e80 0000 0000: - | ||
| 333 | 7e80 0000 0000 - 8000 0000 0000: modules and main thread stack | ||
| 334 | */ | ||
| 335 | struct Mapping47 { | ||
| 336 | static const uptr kMetaShadowBeg = 0x100000000000ull; | ||
| 337 | static const uptr kMetaShadowEnd = 0x200000000000ull; | ||
| 338 | static const uptr kTraceMemBeg = 0x200000000000ull; | ||
| 339 | static const uptr kTraceMemEnd = 0x220000000000ull; | ||
| 340 | static const uptr kShadowBeg = 0x010000000000ull; | ||
| 341 | static const uptr kShadowEnd = 0x100000000000ull; | ||
| 342 | static const uptr kHeapMemBeg = 0x7d0000000000ull; | ||
| 343 | static const uptr kHeapMemEnd = 0x7e0000000000ull; | ||
| 344 | static const uptr kLoAppMemBeg = 0x000000001000ull; | ||
| 345 | static const uptr kLoAppMemEnd = 0x010000000000ull; | ||
| 346 | static const uptr kHiAppMemBeg = 0x7e8000000000ull; | ||
| 347 | static const uptr kHiAppMemEnd = 0x800000000000ull; // 47 bits | ||
| 348 | static const uptr kAppMemMsk = 0x7c0000000000ull; | ||
| 349 | static const uptr kAppMemXor = 0x020000000000ull; | ||
| 350 | static const uptr kVdsoBeg = 0x7800000000000000ull; | ||
| 351 | }; | ||
| 352 | |||
| 353 | // Indicates the runtime will define the memory regions at runtime. | ||
| 354 | #define TSAN_RUNTIME_VMA 1 | ||
| 355 | #endif | ||
| 356 | |||
| 357 | #elif SANITIZER_GO && !SANITIZER_WINDOWS && defined(__x86_64__) | ||
| 358 | |||
| 359 | /* Go on linux, darwin and freebsd on x86_64 | ||
| 360 | 0000 0000 1000 - 0000 1000 0000: executable | ||
| 361 | 0000 1000 0000 - 00c0 0000 0000: - | ||
| 362 | 00c0 0000 0000 - 00e0 0000 0000: heap | ||
| 363 | 00e0 0000 0000 - 2000 0000 0000: - | ||
| 364 | 2000 0000 0000 - 2380 0000 0000: shadow | ||
| 365 | 2380 0000 0000 - 3000 0000 0000: - | ||
| 366 | 3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects) | ||
| 367 | 4000 0000 0000 - 6000 0000 0000: - | ||
| 368 | 6000 0000 0000 - 6200 0000 0000: traces | ||
| 369 | 6200 0000 0000 - 8000 0000 0000: - | ||
| 370 | */ | ||
| 371 | |||
| 372 | struct Mapping { | ||
| 373 | static const uptr kMetaShadowBeg = 0x300000000000ull; | ||
| 374 | static const uptr kMetaShadowEnd = 0x400000000000ull; | ||
| 375 | static const uptr kTraceMemBeg = 0x600000000000ull; | ||
| 376 | static const uptr kTraceMemEnd = 0x620000000000ull; | ||
| 377 | static const uptr kShadowBeg = 0x200000000000ull; | ||
| 378 | static const uptr kShadowEnd = 0x238000000000ull; | ||
| 379 | static const uptr kAppMemBeg = 0x000000001000ull; | ||
| 380 | static const uptr kAppMemEnd = 0x00e000000000ull; | ||
| 381 | }; | ||
| 382 | |||
| 383 | #elif SANITIZER_GO && SANITIZER_WINDOWS | ||
| 384 | |||
| 385 | /* Go on windows | ||
| 386 | 0000 0000 1000 - 0000 1000 0000: executable | ||
| 387 | 0000 1000 0000 - 00f8 0000 0000: - | ||
| 388 | 00c0 0000 0000 - 00e0 0000 0000: heap | ||
| 389 | 00e0 0000 0000 - 0100 0000 0000: - | ||
| 390 | 0100 0000 0000 - 0500 0000 0000: shadow | ||
| 391 | 0500 0000 0000 - 0560 0000 0000: - | ||
| 392 | 0560 0000 0000 - 0760 0000 0000: traces | ||
| 393 | 0760 0000 0000 - 07d0 0000 0000: metainfo (memory blocks and sync objects) | ||
| 394 | 07d0 0000 0000 - 8000 0000 0000: - | ||
| 395 | */ | ||
| 396 | |||
| 397 | struct Mapping { | ||
| 398 | static const uptr kMetaShadowBeg = 0x076000000000ull; | ||
| 399 | static const uptr kMetaShadowEnd = 0x07d000000000ull; | ||
| 400 | static const uptr kTraceMemBeg = 0x056000000000ull; | ||
| 401 | static const uptr kTraceMemEnd = 0x076000000000ull; | ||
| 402 | static const uptr kShadowBeg = 0x010000000000ull; | ||
| 403 | static const uptr kShadowEnd = 0x050000000000ull; | ||
| 404 | static const uptr kAppMemBeg = 0x000000001000ull; | ||
| 405 | static const uptr kAppMemEnd = 0x00e000000000ull; | ||
| 406 | }; | ||
| 407 | |||
| 408 | #elif SANITIZER_GO && defined(__powerpc64__) | ||
| 409 | |||
| 410 | /* Only Mapping46 and Mapping47 are currently supported for powercp64 on Go. */ | ||
| 411 | |||
| 412 | /* Go on linux/powerpc64 (46-bit VMA) | ||
| 413 | 0000 0000 1000 - 0000 1000 0000: executable | ||
| 414 | 0000 1000 0000 - 00c0 0000 0000: - | ||
| 415 | 00c0 0000 0000 - 00e0 0000 0000: heap | ||
| 416 | 00e0 0000 0000 - 2000 0000 0000: - | ||
| 417 | 2000 0000 0000 - 2380 0000 0000: shadow | ||
| 418 | 2380 0000 0000 - 2400 0000 0000: - | ||
| 419 | 2400 0000 0000 - 3400 0000 0000: metainfo (memory blocks and sync objects) | ||
| 420 | 3400 0000 0000 - 3600 0000 0000: - | ||
| 421 | 3600 0000 0000 - 3800 0000 0000: traces | ||
| 422 | 3800 0000 0000 - 4000 0000 0000: - | ||
| 423 | */ | ||
| 424 | |||
| 425 | struct Mapping46 { | ||
| 426 | static const uptr kMetaShadowBeg = 0x240000000000ull; | ||
| 427 | static const uptr kMetaShadowEnd = 0x340000000000ull; | ||
| 428 | static const uptr kTraceMemBeg = 0x360000000000ull; | ||
| 429 | static const uptr kTraceMemEnd = 0x380000000000ull; | ||
| 430 | static const uptr kShadowBeg = 0x200000000000ull; | ||
| 431 | static const uptr kShadowEnd = 0x238000000000ull; | ||
| 432 | static const uptr kAppMemBeg = 0x000000001000ull; | ||
| 433 | static const uptr kAppMemEnd = 0x00e000000000ull; | ||
| 434 | }; | ||
| 435 | |||
| 436 | /* Go on linux/powerpc64 (47-bit VMA) | ||
| 437 | 0000 0000 1000 - 0000 1000 0000: executable | ||
| 438 | 0000 1000 0000 - 00c0 0000 0000: - | ||
| 439 | 00c0 0000 0000 - 00e0 0000 0000: heap | ||
| 440 | 00e0 0000 0000 - 2000 0000 0000: - | ||
| 441 | 2000 0000 0000 - 3000 0000 0000: shadow | ||
| 442 | 3000 0000 0000 - 3000 0000 0000: - | ||
| 443 | 3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects) | ||
| 444 | 4000 0000 0000 - 6000 0000 0000: - | ||
| 445 | 6000 0000 0000 - 6200 0000 0000: traces | ||
| 446 | 6200 0000 0000 - 8000 0000 0000: - | ||
| 447 | */ | ||
| 448 | |||
| 449 | struct Mapping47 { | ||
| 450 | static const uptr kMetaShadowBeg = 0x300000000000ull; | ||
| 451 | static const uptr kMetaShadowEnd = 0x400000000000ull; | ||
| 452 | static const uptr kTraceMemBeg = 0x600000000000ull; | ||
| 453 | static const uptr kTraceMemEnd = 0x620000000000ull; | ||
| 454 | static const uptr kShadowBeg = 0x200000000000ull; | ||
| 455 | static const uptr kShadowEnd = 0x300000000000ull; | ||
| 456 | static const uptr kAppMemBeg = 0x000000001000ull; | ||
| 457 | static const uptr kAppMemEnd = 0x00e000000000ull; | ||
| 458 | }; | ||
| 459 | |||
| 460 | #define TSAN_RUNTIME_VMA 1 | ||
| 461 | |||
| 462 | #elif SANITIZER_GO && defined(__aarch64__) | ||
| 463 | |||
| 464 | /* Go on linux/aarch64 (48-bit VMA) | ||
| 465 | 0000 0000 1000 - 0000 1000 0000: executable | ||
| 466 | 0000 1000 0000 - 00c0 0000 0000: - | ||
| 467 | 00c0 0000 0000 - 00e0 0000 0000: heap | ||
| 468 | 00e0 0000 0000 - 2000 0000 0000: - | ||
| 469 | 2000 0000 0000 - 3000 0000 0000: shadow | ||
| 470 | 3000 0000 0000 - 3000 0000 0000: - | ||
| 471 | 3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects) | ||
| 472 | 4000 0000 0000 - 6000 0000 0000: - | ||
| 473 | 6000 0000 0000 - 6200 0000 0000: traces | ||
| 474 | 6200 0000 0000 - 8000 0000 0000: - | ||
| 475 | */ | ||
| 476 | |||
| 477 | struct Mapping { | ||
| 478 | static const uptr kMetaShadowBeg = 0x300000000000ull; | ||
| 479 | static const uptr kMetaShadowEnd = 0x400000000000ull; | ||
| 480 | static const uptr kTraceMemBeg = 0x600000000000ull; | ||
| 481 | static const uptr kTraceMemEnd = 0x620000000000ull; | ||
| 482 | static const uptr kShadowBeg = 0x200000000000ull; | ||
| 483 | static const uptr kShadowEnd = 0x300000000000ull; | ||
| 484 | static const uptr kAppMemBeg = 0x000000001000ull; | ||
| 485 | static const uptr kAppMemEnd = 0x00e000000000ull; | ||
| 486 | }; | ||
| 487 | |||
| 488 | // Indicates the runtime will define the memory regions at runtime. | ||
| 489 | #define TSAN_RUNTIME_VMA 1 | ||
| 490 | |||
| 491 | #else | ||
| 492 | # error "Unknown platform" | ||
| 493 | #endif | ||
| 494 | |||
| 495 | |||
| 496 | #ifdef TSAN_RUNTIME_VMA | ||
| 497 | extern uptr vmaSize; | ||
| 498 | #endif | ||
| 499 | |||
| 500 | |||
| 501 | enum MappingType { | ||
| 502 | MAPPING_LO_APP_BEG, | ||
| 503 | MAPPING_LO_APP_END, | ||
| 504 | MAPPING_HI_APP_BEG, | ||
| 505 | MAPPING_HI_APP_END, | ||
| 506 | #ifdef TSAN_MID_APP_RANGE | ||
| 507 | MAPPING_MID_APP_BEG, | ||
| 508 | MAPPING_MID_APP_END, | ||
| 509 | #endif | ||
| 510 | MAPPING_HEAP_BEG, | ||
| 511 | MAPPING_HEAP_END, | ||
| 512 | MAPPING_APP_BEG, | ||
| 513 | MAPPING_APP_END, | ||
| 514 | MAPPING_SHADOW_BEG, | ||
| 515 | MAPPING_SHADOW_END, | ||
| 516 | MAPPING_META_SHADOW_BEG, | ||
| 517 | MAPPING_META_SHADOW_END, | ||
| 518 | MAPPING_TRACE_BEG, | ||
| 519 | MAPPING_TRACE_END, | ||
| 520 | MAPPING_VDSO_BEG, | ||
| 521 | }; | ||
| 522 | |||
| 523 | template<typename Mapping, int Type> | ||
| 524 | uptr MappingImpl(void) { | ||
| 525 | switch (Type) { | ||
| 526 | #if !SANITIZER_GO | ||
| 527 | case MAPPING_LO_APP_BEG: return Mapping::kLoAppMemBeg; | ||
| 528 | case MAPPING_LO_APP_END: return Mapping::kLoAppMemEnd; | ||
| 529 | # ifdef TSAN_MID_APP_RANGE | ||
| 530 | case MAPPING_MID_APP_BEG: return Mapping::kMidAppMemBeg; | ||
| 531 | case MAPPING_MID_APP_END: return Mapping::kMidAppMemEnd; | ||
| 532 | # endif | ||
| 533 | case MAPPING_HI_APP_BEG: return Mapping::kHiAppMemBeg; | ||
| 534 | case MAPPING_HI_APP_END: return Mapping::kHiAppMemEnd; | ||
| 535 | case MAPPING_HEAP_BEG: return Mapping::kHeapMemBeg; | ||
| 536 | case MAPPING_HEAP_END: return Mapping::kHeapMemEnd; | ||
| 537 | case MAPPING_VDSO_BEG: return Mapping::kVdsoBeg; | ||
| 538 | #else | ||
| 539 | case MAPPING_APP_BEG: return Mapping::kAppMemBeg; | ||
| 540 | case MAPPING_APP_END: return Mapping::kAppMemEnd; | ||
| 541 | #endif | ||
| 542 | case MAPPING_SHADOW_BEG: return Mapping::kShadowBeg; | ||
| 543 | case MAPPING_SHADOW_END: return Mapping::kShadowEnd; | ||
| 544 | case MAPPING_META_SHADOW_BEG: return Mapping::kMetaShadowBeg; | ||
| 545 | case MAPPING_META_SHADOW_END: return Mapping::kMetaShadowEnd; | ||
| 546 | case MAPPING_TRACE_BEG: return Mapping::kTraceMemBeg; | ||
| 547 | case MAPPING_TRACE_END: return Mapping::kTraceMemEnd; | ||
| 548 | } | ||
| 549 | } | ||
| 550 | |||
| 551 | template<int Type> | ||
| 552 | uptr MappingArchImpl(void) { | ||
| 553 | #if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO | ||
| 554 | switch (vmaSize) { | ||
| 555 | case 39: return MappingImpl<Mapping39, Type>(); | ||
| 556 | case 42: return MappingImpl<Mapping42, Type>(); | ||
| 557 | case 48: return MappingImpl<Mapping48, Type>(); | ||
| 558 | } | ||
| 559 | DCHECK(0); | ||
| 560 | return 0; | ||
| 561 | #elif defined(__powerpc64__) | ||
| 562 | switch (vmaSize) { | ||
| 563 | #if !SANITIZER_GO | ||
| 564 | case 44: return MappingImpl<Mapping44, Type>(); | ||
| 565 | #endif | ||
| 566 | case 46: return MappingImpl<Mapping46, Type>(); | ||
| 567 | case 47: return MappingImpl<Mapping47, Type>(); | ||
| 568 | } | ||
| 569 | DCHECK(0); | ||
| 570 | return 0; | ||
| 571 | #else | ||
| 572 | return MappingImpl<Mapping, Type>(); | ||
| 573 | #endif | ||
| 574 | } | ||
| 575 | |||
| 576 | #if !SANITIZER_GO | ||
| 577 | ALWAYS_INLINE | ||
| 578 | uptr LoAppMemBeg(void) { | ||
| 579 | return MappingArchImpl<MAPPING_LO_APP_BEG>(); | ||
| 580 | } | ||
| 581 | ALWAYS_INLINE | ||
| 582 | uptr LoAppMemEnd(void) { | ||
| 583 | return MappingArchImpl<MAPPING_LO_APP_END>(); | ||
| 584 | } | ||
| 585 | |||
| 586 | #ifdef TSAN_MID_APP_RANGE | ||
| 587 | ALWAYS_INLINE | ||
| 588 | uptr MidAppMemBeg(void) { | ||
| 589 | return MappingArchImpl<MAPPING_MID_APP_BEG>(); | ||
| 590 | } | ||
| 591 | ALWAYS_INLINE | ||
| 592 | uptr MidAppMemEnd(void) { | ||
| 593 | return MappingArchImpl<MAPPING_MID_APP_END>(); | ||
| 594 | } | ||
| 595 | #endif | ||
| 596 | |||
| 597 | ALWAYS_INLINE | ||
| 598 | uptr HeapMemBeg(void) { | ||
| 599 | return MappingArchImpl<MAPPING_HEAP_BEG>(); | ||
| 600 | } | ||
| 601 | ALWAYS_INLINE | ||
| 602 | uptr HeapMemEnd(void) { | ||
| 603 | return MappingArchImpl<MAPPING_HEAP_END>(); | ||
| 604 | } | ||
| 605 | |||
| 606 | ALWAYS_INLINE | ||
| 607 | uptr HiAppMemBeg(void) { | ||
| 608 | return MappingArchImpl<MAPPING_HI_APP_BEG>(); | ||
| 609 | } | ||
| 610 | ALWAYS_INLINE | ||
| 611 | uptr HiAppMemEnd(void) { | ||
| 612 | return MappingArchImpl<MAPPING_HI_APP_END>(); | ||
| 613 | } | ||
| 614 | |||
| 615 | ALWAYS_INLINE | ||
| 616 | uptr VdsoBeg(void) { | ||
| 617 | return MappingArchImpl<MAPPING_VDSO_BEG>(); | ||
| 618 | } | ||
| 619 | |||
| 620 | #else | ||
| 621 | |||
| 622 | ALWAYS_INLINE | ||
| 623 | uptr AppMemBeg(void) { | ||
| 624 | return MappingArchImpl<MAPPING_APP_BEG>(); | ||
| 625 | } | ||
| 626 | ALWAYS_INLINE | ||
| 627 | uptr AppMemEnd(void) { | ||
| 628 | return MappingArchImpl<MAPPING_APP_END>(); | ||
| 629 | } | ||
| 630 | |||
| 631 | #endif | ||
| 632 | |||
| 633 | static inline | ||
| 634 | bool GetUserRegion(int i, uptr *start, uptr *end) { | ||
| 635 | switch (i) { | ||
| 636 | default: | ||
| 637 | return false; | ||
| 638 | #if !SANITIZER_GO | ||
| 639 | case 0: | ||
| 640 | *start = LoAppMemBeg(); | ||
| 641 | *end = LoAppMemEnd(); | ||
| 642 | return true; | ||
| 643 | case 1: | ||
| 644 | *start = HiAppMemBeg(); | ||
| 645 | *end = HiAppMemEnd(); | ||
| 646 | return true; | ||
| 647 | case 2: | ||
| 648 | *start = HeapMemBeg(); | ||
| 649 | *end = HeapMemEnd(); | ||
| 650 | return true; | ||
| 651 | # ifdef TSAN_MID_APP_RANGE | ||
| 652 | case 3: | ||
| 653 | *start = MidAppMemBeg(); | ||
| 654 | *end = MidAppMemEnd(); | ||
| 655 | return true; | ||
| 656 | # endif | ||
| 657 | #else | ||
| 658 | case 0: | ||
| 659 | *start = AppMemBeg(); | ||
| 660 | *end = AppMemEnd(); | ||
| 661 | return true; | ||
| 662 | #endif | ||
| 663 | } | ||
| 664 | } | ||
| 665 | |||
| 666 | ALWAYS_INLINE | ||
| 667 | uptr ShadowBeg(void) { | ||
| 668 | return MappingArchImpl<MAPPING_SHADOW_BEG>(); | ||
| 669 | } | ||
| 670 | ALWAYS_INLINE | ||
| 671 | uptr ShadowEnd(void) { | ||
| 672 | return MappingArchImpl<MAPPING_SHADOW_END>(); | ||
| 673 | } | ||
| 674 | |||
| 675 | ALWAYS_INLINE | ||
| 676 | uptr MetaShadowBeg(void) { | ||
| 677 | return MappingArchImpl<MAPPING_META_SHADOW_BEG>(); | ||
| 678 | } | ||
| 679 | ALWAYS_INLINE | ||
| 680 | uptr MetaShadowEnd(void) { | ||
| 681 | return MappingArchImpl<MAPPING_META_SHADOW_END>(); | ||
| 682 | } | ||
| 683 | |||
| 684 | ALWAYS_INLINE | ||
| 685 | uptr TraceMemBeg(void) { | ||
| 686 | return MappingArchImpl<MAPPING_TRACE_BEG>(); | ||
| 687 | } | ||
| 688 | ALWAYS_INLINE | ||
| 689 | uptr TraceMemEnd(void) { | ||
| 690 | return MappingArchImpl<MAPPING_TRACE_END>(); | ||
| 691 | } | ||
| 692 | |||
| 693 | |||
| 694 | template<typename Mapping> | ||
| 695 | bool IsAppMemImpl(uptr mem) { | ||
| 696 | #if !SANITIZER_GO | ||
| 697 | return (mem >= Mapping::kHeapMemBeg && mem < Mapping::kHeapMemEnd) || | ||
| 698 | # ifdef TSAN_MID_APP_RANGE | ||
| 699 | (mem >= Mapping::kMidAppMemBeg && mem < Mapping::kMidAppMemEnd) || | ||
| 700 | # endif | ||
| 701 | (mem >= Mapping::kLoAppMemBeg && mem < Mapping::kLoAppMemEnd) || | ||
| 702 | (mem >= Mapping::kHiAppMemBeg && mem < Mapping::kHiAppMemEnd); | ||
| 703 | #else | ||
| 704 | return mem >= Mapping::kAppMemBeg && mem < Mapping::kAppMemEnd; | ||
| 705 | #endif | ||
| 706 | } | ||
| 707 | |||
| 708 | ALWAYS_INLINE | ||
| 709 | bool IsAppMem(uptr mem) { | ||
| 710 | #if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO | ||
| 711 | switch (vmaSize) { | ||
| 712 | case 39: return IsAppMemImpl<Mapping39>(mem); | ||
| 713 | case 42: return IsAppMemImpl<Mapping42>(mem); | ||
| 714 | case 48: return IsAppMemImpl<Mapping48>(mem); | ||
| 715 | } | ||
| 716 | DCHECK(0); | ||
| 717 | return false; | ||
| 718 | #elif defined(__powerpc64__) | ||
| 719 | switch (vmaSize) { | ||
| 720 | #if !SANITIZER_GO | ||
| 721 | case 44: return IsAppMemImpl<Mapping44>(mem); | ||
| 722 | #endif | ||
| 723 | case 46: return IsAppMemImpl<Mapping46>(mem); | ||
| 724 | case 47: return IsAppMemImpl<Mapping47>(mem); | ||
| 725 | } | ||
| 726 | DCHECK(0); | ||
| 727 | return false; | ||
| 728 | #else | ||
| 729 | return IsAppMemImpl<Mapping>(mem); | ||
| 730 | #endif | ||
| 731 | } | ||
| 732 | |||
| 733 | |||
| 734 | template<typename Mapping> | ||
| 735 | bool IsShadowMemImpl(uptr mem) { | ||
| 736 | return mem >= Mapping::kShadowBeg && mem <= Mapping::kShadowEnd; | ||
| 737 | } | ||
| 738 | |||
| 739 | ALWAYS_INLINE | ||
| 740 | bool IsShadowMem(uptr mem) { | ||
| 741 | #if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO | ||
| 742 | switch (vmaSize) { | ||
| 743 | case 39: return IsShadowMemImpl<Mapping39>(mem); | ||
| 744 | case 42: return IsShadowMemImpl<Mapping42>(mem); | ||
| 745 | case 48: return IsShadowMemImpl<Mapping48>(mem); | ||
| 746 | } | ||
| 747 | DCHECK(0); | ||
| 748 | return false; | ||
| 749 | #elif defined(__powerpc64__) | ||
| 750 | switch (vmaSize) { | ||
| 751 | #if !SANITIZER_GO | ||
| 752 | case 44: return IsShadowMemImpl<Mapping44>(mem); | ||
| 753 | #endif | ||
| 754 | case 46: return IsShadowMemImpl<Mapping46>(mem); | ||
| 755 | case 47: return IsShadowMemImpl<Mapping47>(mem); | ||
| 756 | } | ||
| 757 | DCHECK(0); | ||
| 758 | return false; | ||
| 759 | #else | ||
| 760 | return IsShadowMemImpl<Mapping>(mem); | ||
| 761 | #endif | ||
| 762 | } | ||
| 763 | |||
| 764 | |||
| 765 | template<typename Mapping> | ||
| 766 | bool IsMetaMemImpl(uptr mem) { | ||
| 767 | return mem >= Mapping::kMetaShadowBeg && mem <= Mapping::kMetaShadowEnd; | ||
| 768 | } | ||
| 769 | |||
| 770 | ALWAYS_INLINE | ||
| 771 | bool IsMetaMem(uptr mem) { | ||
| 772 | #if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO | ||
| 773 | switch (vmaSize) { | ||
| 774 | case 39: return IsMetaMemImpl<Mapping39>(mem); | ||
| 775 | case 42: return IsMetaMemImpl<Mapping42>(mem); | ||
| 776 | case 48: return IsMetaMemImpl<Mapping48>(mem); | ||
| 777 | } | ||
| 778 | DCHECK(0); | ||
| 779 | return false; | ||
| 780 | #elif defined(__powerpc64__) | ||
| 781 | switch (vmaSize) { | ||
| 782 | #if !SANITIZER_GO | ||
| 783 | case 44: return IsMetaMemImpl<Mapping44>(mem); | ||
| 784 | #endif | ||
| 785 | case 46: return IsMetaMemImpl<Mapping46>(mem); | ||
| 786 | case 47: return IsMetaMemImpl<Mapping47>(mem); | ||
| 787 | } | ||
| 788 | DCHECK(0); | ||
| 789 | return false; | ||
| 790 | #else | ||
| 791 | return IsMetaMemImpl<Mapping>(mem); | ||
| 792 | #endif | ||
| 793 | } | ||
| 794 | |||
| 795 | |||
| 796 | template<typename Mapping> | ||
| 797 | uptr MemToShadowImpl(uptr x) { | ||
| 798 | DCHECK(IsAppMem(x)); | ||
| 799 | #if !SANITIZER_GO | ||
| 800 | return (((x) & ~(Mapping::kAppMemMsk | (kShadowCell - 1))) | ||
| 801 | ^ Mapping::kAppMemXor) * kShadowCnt; | ||
| 802 | #else | ||
| 803 | # ifndef SANITIZER_WINDOWS | ||
| 804 | return ((x & ~(kShadowCell - 1)) * kShadowCnt) | Mapping::kShadowBeg; | ||
| 805 | # else | ||
| 806 | return ((x & ~(kShadowCell - 1)) * kShadowCnt) + Mapping::kShadowBeg; | ||
| 807 | # endif | ||
| 808 | #endif | ||
| 809 | } | ||
| 810 | |||
| 811 | ALWAYS_INLINE | ||
| 812 | uptr MemToShadow(uptr x) { | ||
| 813 | #if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO | ||
| 814 | switch (vmaSize) { | ||
| 815 | case 39: return MemToShadowImpl<Mapping39>(x); | ||
| 816 | case 42: return MemToShadowImpl<Mapping42>(x); | ||
| 817 | case 48: return MemToShadowImpl<Mapping48>(x); | ||
| 818 | } | ||
| 819 | DCHECK(0); | ||
| 820 | return 0; | ||
| 821 | #elif defined(__powerpc64__) | ||
| 822 | switch (vmaSize) { | ||
| 823 | #if !SANITIZER_GO | ||
| 824 | case 44: return MemToShadowImpl<Mapping44>(x); | ||
| 825 | #endif | ||
| 826 | case 46: return MemToShadowImpl<Mapping46>(x); | ||
| 827 | case 47: return MemToShadowImpl<Mapping47>(x); | ||
| 828 | } | ||
| 829 | DCHECK(0); | ||
| 830 | return 0; | ||
| 831 | #else | ||
| 832 | return MemToShadowImpl<Mapping>(x); | ||
| 833 | #endif | ||
| 834 | } | ||
| 835 | |||
| 836 | |||
| 837 | template<typename Mapping> | ||
| 838 | u32 *MemToMetaImpl(uptr x) { | ||
| 839 | DCHECK(IsAppMem(x)); | ||
| 840 | #if !SANITIZER_GO | ||
| 841 | return (u32*)(((((x) & ~(Mapping::kAppMemMsk | (kMetaShadowCell - 1)))) / | ||
| 842 | kMetaShadowCell * kMetaShadowSize) | Mapping::kMetaShadowBeg); | ||
| 843 | #else | ||
| 844 | # ifndef SANITIZER_WINDOWS | ||
| 845 | return (u32*)(((x & ~(kMetaShadowCell - 1)) / \ | ||
| 846 | kMetaShadowCell * kMetaShadowSize) | Mapping::kMetaShadowBeg); | ||
| 847 | # else | ||
| 848 | return (u32*)(((x & ~(kMetaShadowCell - 1)) / \ | ||
| 849 | kMetaShadowCell * kMetaShadowSize) + Mapping::kMetaShadowBeg); | ||
| 850 | # endif | ||
| 851 | #endif | ||
| 852 | } | ||
| 853 | |||
| 854 | ALWAYS_INLINE | ||
| 855 | u32 *MemToMeta(uptr x) { | ||
| 856 | #if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO | ||
| 857 | switch (vmaSize) { | ||
| 858 | case 39: return MemToMetaImpl<Mapping39>(x); | ||
| 859 | case 42: return MemToMetaImpl<Mapping42>(x); | ||
| 860 | case 48: return MemToMetaImpl<Mapping48>(x); | ||
| 861 | } | ||
| 862 | DCHECK(0); | ||
| 863 | return 0; | ||
| 864 | #elif defined(__powerpc64__) | ||
| 865 | switch (vmaSize) { | ||
| 866 | #if !SANITIZER_GO | ||
| 867 | case 44: return MemToMetaImpl<Mapping44>(x); | ||
| 868 | #endif | ||
| 869 | case 46: return MemToMetaImpl<Mapping46>(x); | ||
| 870 | case 47: return MemToMetaImpl<Mapping47>(x); | ||
| 871 | } | ||
| 872 | DCHECK(0); | ||
| 873 | return 0; | ||
| 874 | #else | ||
| 875 | return MemToMetaImpl<Mapping>(x); | ||
| 876 | #endif | ||
| 877 | } | ||
| 878 | |||
| 879 | |||
| 880 | template<typename Mapping> | ||
| 881 | uptr ShadowToMemImpl(uptr s) { | ||
| 882 | DCHECK(IsShadowMem(s)); | ||
| 883 | #if !SANITIZER_GO | ||
| 884 | // The shadow mapping is non-linear and we've lost some bits, so we don't have | ||
| 885 | // an easy way to restore the original app address. But the mapping is a | ||
| 886 | // bijection, so we try to restore the address as belonging to low/mid/high | ||
| 887 | // range consecutively and see if shadow->app->shadow mapping gives us the | ||
| 888 | // same address. | ||
| 889 | uptr p = (s / kShadowCnt) ^ Mapping::kAppMemXor; | ||
| 890 | if (p >= Mapping::kLoAppMemBeg && p < Mapping::kLoAppMemEnd && | ||
| 891 | MemToShadow(p) == s) | ||
| 892 | return p; | ||
| 893 | # ifdef TSAN_MID_APP_RANGE | ||
| 894 | p = ((s / kShadowCnt) ^ Mapping::kAppMemXor) + | ||
| 895 | (Mapping::kMidAppMemBeg & Mapping::kAppMemMsk); | ||
| 896 | if (p >= Mapping::kMidAppMemBeg && p < Mapping::kMidAppMemEnd && | ||
| 897 | MemToShadow(p) == s) | ||
| 898 | return p; | ||
| 899 | # endif | ||
| 900 | return ((s / kShadowCnt) ^ Mapping::kAppMemXor) | Mapping::kAppMemMsk; | ||
| 901 | #else // #if !SANITIZER_GO | ||
| 902 | # ifndef SANITIZER_WINDOWS | ||
| 903 | return (s & ~Mapping::kShadowBeg) / kShadowCnt; | ||
| 904 | # else | ||
| 905 | return (s - Mapping::kShadowBeg) / kShadowCnt; | ||
| 906 | # endif // SANITIZER_WINDOWS | ||
| 907 | #endif | ||
| 908 | } | ||
| 909 | |||
| 910 | ALWAYS_INLINE | ||
| 911 | uptr ShadowToMem(uptr s) { | ||
| 912 | #if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO | ||
| 913 | switch (vmaSize) { | ||
| 914 | case 39: return ShadowToMemImpl<Mapping39>(s); | ||
| 915 | case 42: return ShadowToMemImpl<Mapping42>(s); | ||
| 916 | case 48: return ShadowToMemImpl<Mapping48>(s); | ||
| 917 | } | ||
| 918 | DCHECK(0); | ||
| 919 | return 0; | ||
| 920 | #elif defined(__powerpc64__) | ||
| 921 | switch (vmaSize) { | ||
| 922 | #if !SANITIZER_GO | ||
| 923 | case 44: return ShadowToMemImpl<Mapping44>(s); | ||
| 924 | #endif | ||
| 925 | case 46: return ShadowToMemImpl<Mapping46>(s); | ||
| 926 | case 47: return ShadowToMemImpl<Mapping47>(s); | ||
| 927 | } | ||
| 928 | DCHECK(0); | ||
| 929 | return 0; | ||
| 930 | #else | ||
| 931 | return ShadowToMemImpl<Mapping>(s); | ||
| 932 | #endif | ||
| 933 | } | ||
| 934 | |||
| 935 | |||
| 936 | |||
| 937 | // The additional page is to catch shadow stack overflow as paging fault. | ||
| 938 | // Windows wants 64K alignment for mmaps. | ||
| 939 | const uptr kTotalTraceSize = (kTraceSize * sizeof(Event) + sizeof(Trace) | ||
| 940 | + (64 << 10) + (64 << 10) - 1) & ~((64 << 10) - 1); | ||
| 941 | |||
| 942 | template<typename Mapping> | ||
| 943 | uptr GetThreadTraceImpl(int tid) { | ||
| 944 | uptr p = Mapping::kTraceMemBeg + (uptr)tid * kTotalTraceSize; | ||
| 945 | DCHECK_LT(p, Mapping::kTraceMemEnd); | ||
| 946 | return p; | ||
| 947 | } | ||
| 948 | |||
| 949 | ALWAYS_INLINE | ||
| 950 | uptr GetThreadTrace(int tid) { | ||
| 951 | #if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO | ||
| 952 | switch (vmaSize) { | ||
| 953 | case 39: return GetThreadTraceImpl<Mapping39>(tid); | ||
| 954 | case 42: return GetThreadTraceImpl<Mapping42>(tid); | ||
| 955 | case 48: return GetThreadTraceImpl<Mapping48>(tid); | ||
| 956 | } | ||
| 957 | DCHECK(0); | ||
| 958 | return 0; | ||
| 959 | #elif defined(__powerpc64__) | ||
| 960 | switch (vmaSize) { | ||
| 961 | #if !SANITIZER_GO | ||
| 962 | case 44: return GetThreadTraceImpl<Mapping44>(tid); | ||
| 963 | #endif | ||
| 964 | case 46: return GetThreadTraceImpl<Mapping46>(tid); | ||
| 965 | case 47: return GetThreadTraceImpl<Mapping47>(tid); | ||
| 966 | } | ||
| 967 | DCHECK(0); | ||
| 968 | return 0; | ||
| 969 | #else | ||
| 970 | return GetThreadTraceImpl<Mapping>(tid); | ||
| 971 | #endif | ||
| 972 | } | ||
| 973 | |||
| 974 | |||
| 975 | template<typename Mapping> | ||
| 976 | uptr GetThreadTraceHeaderImpl(int tid) { | ||
| 977 | uptr p = Mapping::kTraceMemBeg + (uptr)tid * kTotalTraceSize | ||
| 978 | + kTraceSize * sizeof(Event); | ||
| 979 | DCHECK_LT(p, Mapping::kTraceMemEnd); | ||
| 980 | return p; | ||
| 981 | } | ||
| 982 | |||
| 983 | ALWAYS_INLINE | ||
| 984 | uptr GetThreadTraceHeader(int tid) { | ||
| 985 | #if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO | ||
| 986 | switch (vmaSize) { | ||
| 987 | case 39: return GetThreadTraceHeaderImpl<Mapping39>(tid); | ||
| 988 | case 42: return GetThreadTraceHeaderImpl<Mapping42>(tid); | ||
| 989 | case 48: return GetThreadTraceHeaderImpl<Mapping48>(tid); | ||
| 990 | } | ||
| 991 | DCHECK(0); | ||
| 992 | return 0; | ||
| 993 | #elif defined(__powerpc64__) | ||
| 994 | switch (vmaSize) { | ||
| 995 | #if !SANITIZER_GO | ||
| 996 | case 44: return GetThreadTraceHeaderImpl<Mapping44>(tid); | ||
| 997 | #endif | ||
| 998 | case 46: return GetThreadTraceHeaderImpl<Mapping46>(tid); | ||
| 999 | case 47: return GetThreadTraceHeaderImpl<Mapping47>(tid); | ||
| 1000 | } | ||
| 1001 | DCHECK(0); | ||
| 1002 | return 0; | ||
| 1003 | #else | ||
| 1004 | return GetThreadTraceHeaderImpl<Mapping>(tid); | ||
| 1005 | #endif | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | void InitializePlatform(); | ||
| 1009 | void InitializePlatformEarly(); | ||
| 1010 | void CheckAndProtect(); | ||
| 1011 | void InitializeShadowMemoryPlatform(); | ||
| 1012 | void FlushShadowMemory(); | ||
| 1013 | void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive); | ||
| 1014 | int ExtractResolvFDs(void *state, int *fds, int nfd); | ||
| 1015 | int ExtractRecvmsgFDs(void *msg, int *fds, int nfd); | ||
| 1016 | uptr ExtractLongJmpSp(uptr *env); | ||
| 1017 | void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size); | ||
| 1018 | |||
| 1019 | int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m, | ||
| 1020 | void *abstime), void *c, void *m, void *abstime, | ||
| 1021 | void(*cleanup)(void *arg), void *arg); | ||
| 1022 | |||
| 1023 | void DestroyThreadState(); | ||
| 1024 | void PlatformCleanUpThreadState(ThreadState *thr); | ||
| 1025 | |||
| 1026 | } // namespace __tsan | ||
| 1027 | |||
| 1028 | #endif // TSAN_PLATFORM_H | ||
lib/tsan/tsan_ppc_regs.h created+96| ... | @@ -0,0 +1,96 @@ | ||
| 1 | #define r0 0 | ||
| 2 | #define r1 1 | ||
| 3 | #define r2 2 | ||
| 4 | #define r3 3 | ||
| 5 | #define r4 4 | ||
| 6 | #define r5 5 | ||
| 7 | #define r6 6 | ||
| 8 | #define r7 7 | ||
| 9 | #define r8 8 | ||
| 10 | #define r9 9 | ||
| 11 | #define r10 10 | ||
| 12 | #define r11 11 | ||
| 13 | #define r12 12 | ||
| 14 | #define r13 13 | ||
| 15 | #define r14 14 | ||
| 16 | #define r15 15 | ||
| 17 | #define r16 16 | ||
| 18 | #define r17 17 | ||
| 19 | #define r18 18 | ||
| 20 | #define r19 19 | ||
| 21 | #define r20 20 | ||
| 22 | #define r21 21 | ||
| 23 | #define r22 22 | ||
| 24 | #define r23 23 | ||
| 25 | #define r24 24 | ||
| 26 | #define r25 25 | ||
| 27 | #define r26 26 | ||
| 28 | #define r27 27 | ||
| 29 | #define r28 28 | ||
| 30 | #define r29 29 | ||
| 31 | #define r30 30 | ||
| 32 | #define r31 31 | ||
| 33 | #define f0 0 | ||
| 34 | #define f1 1 | ||
| 35 | #define f2 2 | ||
| 36 | #define f3 3 | ||
| 37 | #define f4 4 | ||
| 38 | #define f5 5 | ||
| 39 | #define f6 6 | ||
| 40 | #define f7 7 | ||
| 41 | #define f8 8 | ||
| 42 | #define f9 9 | ||
| 43 | #define f10 10 | ||
| 44 | #define f11 11 | ||
| 45 | #define f12 12 | ||
| 46 | #define f13 13 | ||
| 47 | #define f14 14 | ||
| 48 | #define f15 15 | ||
| 49 | #define f16 16 | ||
| 50 | #define f17 17 | ||
| 51 | #define f18 18 | ||
| 52 | #define f19 19 | ||
| 53 | #define f20 20 | ||
| 54 | #define f21 21 | ||
| 55 | #define f22 22 | ||
| 56 | #define f23 23 | ||
| 57 | #define f24 24 | ||
| 58 | #define f25 25 | ||
| 59 | #define f26 26 | ||
| 60 | #define f27 27 | ||
| 61 | #define f28 28 | ||
| 62 | #define f29 29 | ||
| 63 | #define f30 30 | ||
| 64 | #define f31 31 | ||
| 65 | #define v0 0 | ||
| 66 | #define v1 1 | ||
| 67 | #define v2 2 | ||
| 68 | #define v3 3 | ||
| 69 | #define v4 4 | ||
| 70 | #define v5 5 | ||
| 71 | #define v6 6 | ||
| 72 | #define v7 7 | ||
| 73 | #define v8 8 | ||
| 74 | #define v9 9 | ||
| 75 | #define v10 10 | ||
| 76 | #define v11 11 | ||
| 77 | #define v12 12 | ||
| 78 | #define v13 13 | ||
| 79 | #define v14 14 | ||
| 80 | #define v15 15 | ||
| 81 | #define v16 16 | ||
| 82 | #define v17 17 | ||
| 83 | #define v18 18 | ||
| 84 | #define v19 19 | ||
| 85 | #define v20 20 | ||
| 86 | #define v21 21 | ||
| 87 | #define v22 22 | ||
| 88 | #define v23 23 | ||
| 89 | #define v24 24 | ||
| 90 | #define v25 25 | ||
| 91 | #define v26 26 | ||
| 92 | #define v27 27 | ||
| 93 | #define v28 28 | ||
| 94 | #define v29 29 | ||
| 95 | #define v30 30 | ||
| 96 | #define v31 31 | ||
lib/tsan/tsan_preinit.cpp created+26| ... | @@ -0,0 +1,26 @@ | ||
| 1 | //===-- tsan_preinit.cpp --------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer. | ||
| 10 | // | ||
| 11 | // Call __tsan_init at the very early stage of process startup. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_common/sanitizer_internal_defs.h" | ||
| 15 | #include "tsan_interface.h" | ||
| 16 | |||
| 17 | #if SANITIZER_CAN_USE_PREINIT_ARRAY | ||
| 18 | |||
| 19 | // The symbol is called __local_tsan_preinit, because it's not intended to be | ||
| 20 | // exported. | ||
| 21 | // This code linked into the main executable when -fsanitize=thread is in | ||
| 22 | // the link flags. It can only use exported interface functions. | ||
| 23 | __attribute__((section(".preinit_array"), used)) | ||
| 24 | void (*__local_tsan_preinit)(void) = __tsan_init; | ||
| 25 | |||
| 26 | #endif | ||
lib/tsan/tsan_report.cpp created+486| ... | @@ -0,0 +1,486 @@ | ||
| 1 | //===-- tsan_report.cpp ---------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #include "tsan_report.h" | ||
| 13 | #include "tsan_platform.h" | ||
| 14 | #include "tsan_rtl.h" | ||
| 15 | #include "sanitizer_common/sanitizer_file.h" | ||
| 16 | #include "sanitizer_common/sanitizer_placement_new.h" | ||
| 17 | #include "sanitizer_common/sanitizer_report_decorator.h" | ||
| 18 | #include "sanitizer_common/sanitizer_stacktrace_printer.h" | ||
| 19 | |||
| 20 | namespace __tsan { | ||
| 21 | |||
| 22 | ReportStack::ReportStack() : frames(nullptr), suppressable(false) {} | ||
| 23 | |||
| 24 | ReportStack *ReportStack::New() { | ||
| 25 | void *mem = internal_alloc(MBlockReportStack, sizeof(ReportStack)); | ||
| 26 | return new(mem) ReportStack(); | ||
| 27 | } | ||
| 28 | |||
| 29 | ReportLocation::ReportLocation(ReportLocationType type) | ||
| 30 | : type(type), global(), heap_chunk_start(0), heap_chunk_size(0), tid(0), | ||
| 31 | fd(0), suppressable(false), stack(nullptr) {} | ||
| 32 | |||
| 33 | ReportLocation *ReportLocation::New(ReportLocationType type) { | ||
| 34 | void *mem = internal_alloc(MBlockReportStack, sizeof(ReportLocation)); | ||
| 35 | return new(mem) ReportLocation(type); | ||
| 36 | } | ||
| 37 | |||
| 38 | class Decorator: public __sanitizer::SanitizerCommonDecorator { | ||
| 39 | public: | ||
| 40 | Decorator() : SanitizerCommonDecorator() { } | ||
| 41 | const char *Access() { return Blue(); } | ||
| 42 | const char *ThreadDescription() { return Cyan(); } | ||
| 43 | const char *Location() { return Green(); } | ||
| 44 | const char *Sleep() { return Yellow(); } | ||
| 45 | const char *Mutex() { return Magenta(); } | ||
| 46 | }; | ||
| 47 | |||
| 48 | ReportDesc::ReportDesc() | ||
| 49 | : tag(kExternalTagNone) | ||
| 50 | , stacks() | ||
| 51 | , mops() | ||
| 52 | , locs() | ||
| 53 | , mutexes() | ||
| 54 | , threads() | ||
| 55 | , unique_tids() | ||
| 56 | , sleep() | ||
| 57 | , count() { | ||
| 58 | } | ||
| 59 | |||
| 60 | ReportMop::ReportMop() | ||
| 61 | : mset() { | ||
| 62 | } | ||
| 63 | |||
| 64 | ReportDesc::~ReportDesc() { | ||
| 65 | // FIXME(dvyukov): it must be leaking a lot of memory. | ||
| 66 | } | ||
| 67 | |||
| 68 | #if !SANITIZER_GO | ||
| 69 | |||
| 70 | const int kThreadBufSize = 32; | ||
| 71 | const char *thread_name(char *buf, int tid) { | ||
| 72 | if (tid == 0) | ||
| 73 | return "main thread"; | ||
| 74 | internal_snprintf(buf, kThreadBufSize, "thread T%d", tid); | ||
| 75 | return buf; | ||
| 76 | } | ||
| 77 | |||
| 78 | static const char *ReportTypeString(ReportType typ, uptr tag) { | ||
| 79 | switch (typ) { | ||
| 80 | case ReportTypeRace: | ||
| 81 | return "data race"; | ||
| 82 | case ReportTypeVptrRace: | ||
| 83 | return "data race on vptr (ctor/dtor vs virtual call)"; | ||
| 84 | case ReportTypeUseAfterFree: | ||
| 85 | return "heap-use-after-free"; | ||
| 86 | case ReportTypeVptrUseAfterFree: | ||
| 87 | return "heap-use-after-free (virtual call vs free)"; | ||
| 88 | case ReportTypeExternalRace: { | ||
| 89 | const char *str = GetReportHeaderFromTag(tag); | ||
| 90 | return str ? str : "race on external object"; | ||
| 91 | } | ||
| 92 | case ReportTypeThreadLeak: | ||
| 93 | return "thread leak"; | ||
| 94 | case ReportTypeMutexDestroyLocked: | ||
| 95 | return "destroy of a locked mutex"; | ||
| 96 | case ReportTypeMutexDoubleLock: | ||
| 97 | return "double lock of a mutex"; | ||
| 98 | case ReportTypeMutexInvalidAccess: | ||
| 99 | return "use of an invalid mutex (e.g. uninitialized or destroyed)"; | ||
| 100 | case ReportTypeMutexBadUnlock: | ||
| 101 | return "unlock of an unlocked mutex (or by a wrong thread)"; | ||
| 102 | case ReportTypeMutexBadReadLock: | ||
| 103 | return "read lock of a write locked mutex"; | ||
| 104 | case ReportTypeMutexBadReadUnlock: | ||
| 105 | return "read unlock of a write locked mutex"; | ||
| 106 | case ReportTypeSignalUnsafe: | ||
| 107 | return "signal-unsafe call inside of a signal"; | ||
| 108 | case ReportTypeErrnoInSignal: | ||
| 109 | return "signal handler spoils errno"; | ||
| 110 | case ReportTypeDeadlock: | ||
| 111 | return "lock-order-inversion (potential deadlock)"; | ||
| 112 | // No default case so compiler warns us if we miss one | ||
| 113 | } | ||
| 114 | UNREACHABLE("missing case"); | ||
| 115 | } | ||
| 116 | |||
| 117 | #if SANITIZER_MAC | ||
| 118 | static const char *const kInterposedFunctionPrefix = "wrap_"; | ||
| 119 | #else | ||
| 120 | static const char *const kInterposedFunctionPrefix = "__interceptor_"; | ||
| 121 | #endif | ||
| 122 | |||
| 123 | void PrintStack(const ReportStack *ent) { | ||
| 124 | if (ent == 0 || ent->frames == 0) { | ||
| 125 | Printf(" [failed to restore the stack]\n\n"); | ||
| 126 | return; | ||
| 127 | } | ||
| 128 | SymbolizedStack *frame = ent->frames; | ||
| 129 | for (int i = 0; frame && frame->info.address; frame = frame->next, i++) { | ||
| 130 | InternalScopedString res(2 * GetPageSizeCached()); | ||
| 131 | RenderFrame(&res, common_flags()->stack_trace_format, i, frame->info, | ||
| 132 | common_flags()->symbolize_vs_style, | ||
| 133 | common_flags()->strip_path_prefix, kInterposedFunctionPrefix); | ||
| 134 | Printf("%s\n", res.data()); | ||
| 135 | } | ||
| 136 | Printf("\n"); | ||
| 137 | } | ||
| 138 | |||
| 139 | static void PrintMutexSet(Vector<ReportMopMutex> const& mset) { | ||
| 140 | for (uptr i = 0; i < mset.Size(); i++) { | ||
| 141 | if (i == 0) | ||
| 142 | Printf(" (mutexes:"); | ||
| 143 | const ReportMopMutex m = mset[i]; | ||
| 144 | Printf(" %s M%llu", m.write ? "write" : "read", m.id); | ||
| 145 | Printf(i == mset.Size() - 1 ? ")" : ","); | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | static const char *MopDesc(bool first, bool write, bool atomic) { | ||
| 150 | return atomic ? (first ? (write ? "Atomic write" : "Atomic read") | ||
| 151 | : (write ? "Previous atomic write" : "Previous atomic read")) | ||
| 152 | : (first ? (write ? "Write" : "Read") | ||
| 153 | : (write ? "Previous write" : "Previous read")); | ||
| 154 | } | ||
| 155 | |||
| 156 | static const char *ExternalMopDesc(bool first, bool write) { | ||
| 157 | return first ? (write ? "Modifying" : "Read-only") | ||
| 158 | : (write ? "Previous modifying" : "Previous read-only"); | ||
| 159 | } | ||
| 160 | |||
| 161 | static void PrintMop(const ReportMop *mop, bool first) { | ||
| 162 | Decorator d; | ||
| 163 | char thrbuf[kThreadBufSize]; | ||
| 164 | Printf("%s", d.Access()); | ||
| 165 | if (mop->external_tag == kExternalTagNone) { | ||
| 166 | Printf(" %s of size %d at %p by %s", | ||
| 167 | MopDesc(first, mop->write, mop->atomic), mop->size, | ||
| 168 | (void *)mop->addr, thread_name(thrbuf, mop->tid)); | ||
| 169 | } else { | ||
| 170 | const char *object_type = GetObjectTypeFromTag(mop->external_tag); | ||
| 171 | if (object_type == nullptr) | ||
| 172 | object_type = "external object"; | ||
| 173 | Printf(" %s access of %s at %p by %s", | ||
| 174 | ExternalMopDesc(first, mop->write), object_type, | ||
| 175 | (void *)mop->addr, thread_name(thrbuf, mop->tid)); | ||
| 176 | } | ||
| 177 | PrintMutexSet(mop->mset); | ||
| 178 | Printf(":\n"); | ||
| 179 | Printf("%s", d.Default()); | ||
| 180 | PrintStack(mop->stack); | ||
| 181 | } | ||
| 182 | |||
| 183 | static void PrintLocation(const ReportLocation *loc) { | ||
| 184 | Decorator d; | ||
| 185 | char thrbuf[kThreadBufSize]; | ||
| 186 | bool print_stack = false; | ||
| 187 | Printf("%s", d.Location()); | ||
| 188 | if (loc->type == ReportLocationGlobal) { | ||
| 189 | const DataInfo &global = loc->global; | ||
| 190 | if (global.size != 0) | ||
| 191 | Printf(" Location is global '%s' of size %zu at %p (%s+%p)\n\n", | ||
| 192 | global.name, global.size, global.start, | ||
| 193 | StripModuleName(global.module), global.module_offset); | ||
| 194 | else | ||
| 195 | Printf(" Location is global '%s' at %p (%s+%p)\n\n", global.name, | ||
| 196 | global.start, StripModuleName(global.module), | ||
| 197 | global.module_offset); | ||
| 198 | } else if (loc->type == ReportLocationHeap) { | ||
| 199 | char thrbuf[kThreadBufSize]; | ||
| 200 | const char *object_type = GetObjectTypeFromTag(loc->external_tag); | ||
| 201 | if (!object_type) { | ||
| 202 | Printf(" Location is heap block of size %zu at %p allocated by %s:\n", | ||
| 203 | loc->heap_chunk_size, loc->heap_chunk_start, | ||
| 204 | thread_name(thrbuf, loc->tid)); | ||
| 205 | } else { | ||
| 206 | Printf(" Location is %s of size %zu at %p allocated by %s:\n", | ||
| 207 | object_type, loc->heap_chunk_size, loc->heap_chunk_start, | ||
| 208 | thread_name(thrbuf, loc->tid)); | ||
| 209 | } | ||
| 210 | print_stack = true; | ||
| 211 | } else if (loc->type == ReportLocationStack) { | ||
| 212 | Printf(" Location is stack of %s.\n\n", thread_name(thrbuf, loc->tid)); | ||
| 213 | } else if (loc->type == ReportLocationTLS) { | ||
| 214 | Printf(" Location is TLS of %s.\n\n", thread_name(thrbuf, loc->tid)); | ||
| 215 | } else if (loc->type == ReportLocationFD) { | ||
| 216 | Printf(" Location is file descriptor %d created by %s at:\n", | ||
| 217 | loc->fd, thread_name(thrbuf, loc->tid)); | ||
| 218 | print_stack = true; | ||
| 219 | } | ||
| 220 | Printf("%s", d.Default()); | ||
| 221 | if (print_stack) | ||
| 222 | PrintStack(loc->stack); | ||
| 223 | } | ||
| 224 | |||
| 225 | static void PrintMutexShort(const ReportMutex *rm, const char *after) { | ||
| 226 | Decorator d; | ||
| 227 | Printf("%sM%zd%s%s", d.Mutex(), rm->id, d.Default(), after); | ||
| 228 | } | ||
| 229 | |||
| 230 | static void PrintMutexShortWithAddress(const ReportMutex *rm, | ||
| 231 | const char *after) { | ||
| 232 | Decorator d; | ||
| 233 | Printf("%sM%zd (%p)%s%s", d.Mutex(), rm->id, rm->addr, d.Default(), after); | ||
| 234 | } | ||
| 235 | |||
| 236 | static void PrintMutex(const ReportMutex *rm) { | ||
| 237 | Decorator d; | ||
| 238 | if (rm->destroyed) { | ||
| 239 | Printf("%s", d.Mutex()); | ||
| 240 | Printf(" Mutex M%llu is already destroyed.\n\n", rm->id); | ||
| 241 | Printf("%s", d.Default()); | ||
| 242 | } else { | ||
| 243 | Printf("%s", d.Mutex()); | ||
| 244 | Printf(" Mutex M%llu (%p) created at:\n", rm->id, rm->addr); | ||
| 245 | Printf("%s", d.Default()); | ||
| 246 | PrintStack(rm->stack); | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | static void PrintThread(const ReportThread *rt) { | ||
| 251 | Decorator d; | ||
| 252 | if (rt->id == 0) // Little sense in describing the main thread. | ||
| 253 | return; | ||
| 254 | Printf("%s", d.ThreadDescription()); | ||
| 255 | Printf(" Thread T%d", rt->id); | ||
| 256 | if (rt->name && rt->name[0] != '\0') | ||
| 257 | Printf(" '%s'", rt->name); | ||
| 258 | char thrbuf[kThreadBufSize]; | ||
| 259 | const char *thread_status = rt->running ? "running" : "finished"; | ||
| 260 | if (rt->thread_type == ThreadType::Worker) { | ||
| 261 | Printf(" (tid=%zu, %s) is a GCD worker thread\n", rt->os_id, thread_status); | ||
| 262 | Printf("\n"); | ||
| 263 | Printf("%s", d.Default()); | ||
| 264 | return; | ||
| 265 | } | ||
| 266 | Printf(" (tid=%zu, %s) created by %s", rt->os_id, thread_status, | ||
| 267 | thread_name(thrbuf, rt->parent_tid)); | ||
| 268 | if (rt->stack) | ||
| 269 | Printf(" at:"); | ||
| 270 | Printf("\n"); | ||
| 271 | Printf("%s", d.Default()); | ||
| 272 | PrintStack(rt->stack); | ||
| 273 | } | ||
| 274 | |||
| 275 | static void PrintSleep(const ReportStack *s) { | ||
| 276 | Decorator d; | ||
| 277 | Printf("%s", d.Sleep()); | ||
| 278 | Printf(" As if synchronized via sleep:\n"); | ||
| 279 | Printf("%s", d.Default()); | ||
| 280 | PrintStack(s); | ||
| 281 | } | ||
| 282 | |||
| 283 | static ReportStack *ChooseSummaryStack(const ReportDesc *rep) { | ||
| 284 | if (rep->mops.Size()) | ||
| 285 | return rep->mops[0]->stack; | ||
| 286 | if (rep->stacks.Size()) | ||
| 287 | return rep->stacks[0]; | ||
| 288 | if (rep->mutexes.Size()) | ||
| 289 | return rep->mutexes[0]->stack; | ||
| 290 | if (rep->threads.Size()) | ||
| 291 | return rep->threads[0]->stack; | ||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | |||
| 295 | static bool FrameIsInternal(const SymbolizedStack *frame) { | ||
| 296 | if (frame == 0) | ||
| 297 | return false; | ||
| 298 | const char *file = frame->info.file; | ||
| 299 | const char *module = frame->info.module; | ||
| 300 | if (file != 0 && | ||
| 301 | (internal_strstr(file, "tsan_interceptors_posix.cpp") || | ||
| 302 | internal_strstr(file, "sanitizer_common_interceptors.inc") || | ||
| 303 | internal_strstr(file, "tsan_interface_"))) | ||
| 304 | return true; | ||
| 305 | if (module != 0 && (internal_strstr(module, "libclang_rt.tsan_"))) | ||
| 306 | return true; | ||
| 307 | return false; | ||
| 308 | } | ||
| 309 | |||
| 310 | static SymbolizedStack *SkipTsanInternalFrames(SymbolizedStack *frames) { | ||
| 311 | while (FrameIsInternal(frames) && frames->next) | ||
| 312 | frames = frames->next; | ||
| 313 | return frames; | ||
| 314 | } | ||
| 315 | |||
| 316 | void PrintReport(const ReportDesc *rep) { | ||
| 317 | Decorator d; | ||
| 318 | Printf("==================\n"); | ||
| 319 | const char *rep_typ_str = ReportTypeString(rep->typ, rep->tag); | ||
| 320 | Printf("%s", d.Warning()); | ||
| 321 | Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str, | ||
| 322 | (int)internal_getpid()); | ||
| 323 | Printf("%s", d.Default()); | ||
| 324 | |||
| 325 | if (rep->typ == ReportTypeDeadlock) { | ||
| 326 | char thrbuf[kThreadBufSize]; | ||
| 327 | Printf(" Cycle in lock order graph: "); | ||
| 328 | for (uptr i = 0; i < rep->mutexes.Size(); i++) | ||
| 329 | PrintMutexShortWithAddress(rep->mutexes[i], " => "); | ||
| 330 | PrintMutexShort(rep->mutexes[0], "\n\n"); | ||
| 331 | CHECK_GT(rep->mutexes.Size(), 0U); | ||
| 332 | CHECK_EQ(rep->mutexes.Size() * (flags()->second_deadlock_stack ? 2 : 1), | ||
| 333 | rep->stacks.Size()); | ||
| 334 | for (uptr i = 0; i < rep->mutexes.Size(); i++) { | ||
| 335 | Printf(" Mutex "); | ||
| 336 | PrintMutexShort(rep->mutexes[(i + 1) % rep->mutexes.Size()], | ||
| 337 | " acquired here while holding mutex "); | ||
| 338 | PrintMutexShort(rep->mutexes[i], " in "); | ||
| 339 | Printf("%s", d.ThreadDescription()); | ||
| 340 | Printf("%s:\n", thread_name(thrbuf, rep->unique_tids[i])); | ||
| 341 | Printf("%s", d.Default()); | ||
| 342 | if (flags()->second_deadlock_stack) { | ||
| 343 | PrintStack(rep->stacks[2*i]); | ||
| 344 | Printf(" Mutex "); | ||
| 345 | PrintMutexShort(rep->mutexes[i], | ||
| 346 | " previously acquired by the same thread here:\n"); | ||
| 347 | PrintStack(rep->stacks[2*i+1]); | ||
| 348 | } else { | ||
| 349 | PrintStack(rep->stacks[i]); | ||
| 350 | if (i == 0) | ||
| 351 | Printf(" Hint: use TSAN_OPTIONS=second_deadlock_stack=1 " | ||
| 352 | "to get more informative warning message\n\n"); | ||
| 353 | } | ||
| 354 | } | ||
| 355 | } else { | ||
| 356 | for (uptr i = 0; i < rep->stacks.Size(); i++) { | ||
| 357 | if (i) | ||
| 358 | Printf(" and:\n"); | ||
| 359 | PrintStack(rep->stacks[i]); | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 | for (uptr i = 0; i < rep->mops.Size(); i++) | ||
| 364 | PrintMop(rep->mops[i], i == 0); | ||
| 365 | |||
| 366 | if (rep->sleep) | ||
| 367 | PrintSleep(rep->sleep); | ||
| 368 | |||
| 369 | for (uptr i = 0; i < rep->locs.Size(); i++) | ||
| 370 | PrintLocation(rep->locs[i]); | ||
| 371 | |||
| 372 | if (rep->typ != ReportTypeDeadlock) { | ||
| 373 | for (uptr i = 0; i < rep->mutexes.Size(); i++) | ||
| 374 | PrintMutex(rep->mutexes[i]); | ||
| 375 | } | ||
| 376 | |||
| 377 | for (uptr i = 0; i < rep->threads.Size(); i++) | ||
| 378 | PrintThread(rep->threads[i]); | ||
| 379 | |||
| 380 | if (rep->typ == ReportTypeThreadLeak && rep->count > 1) | ||
| 381 | Printf(" And %d more similar thread leaks.\n\n", rep->count - 1); | ||
| 382 | |||
| 383 | if (ReportStack *stack = ChooseSummaryStack(rep)) { | ||
| 384 | if (SymbolizedStack *frame = SkipTsanInternalFrames(stack->frames)) | ||
| 385 | ReportErrorSummary(rep_typ_str, frame->info); | ||
| 386 | } | ||
| 387 | |||
| 388 | if (common_flags()->print_module_map == 2) PrintModuleMap(); | ||
| 389 | |||
| 390 | Printf("==================\n"); | ||
| 391 | } | ||
| 392 | |||
| 393 | #else // #if !SANITIZER_GO | ||
| 394 | |||
| 395 | const int kMainThreadId = 1; | ||
| 396 | |||
| 397 | void PrintStack(const ReportStack *ent) { | ||
| 398 | if (ent == 0 || ent->frames == 0) { | ||
| 399 | Printf(" [failed to restore the stack]\n"); | ||
| 400 | return; | ||
| 401 | } | ||
| 402 | SymbolizedStack *frame = ent->frames; | ||
| 403 | for (int i = 0; frame; frame = frame->next, i++) { | ||
| 404 | const AddressInfo &info = frame->info; | ||
| 405 | Printf(" %s()\n %s:%d +0x%zx\n", info.function, | ||
| 406 | StripPathPrefix(info.file, common_flags()->strip_path_prefix), | ||
| 407 | info.line, (void *)info.module_offset); | ||
| 408 | } | ||
| 409 | } | ||
| 410 | |||
| 411 | static void PrintMop(const ReportMop *mop, bool first) { | ||
| 412 | Printf("\n"); | ||
| 413 | Printf("%s at %p by ", | ||
| 414 | (first ? (mop->write ? "Write" : "Read") | ||
| 415 | : (mop->write ? "Previous write" : "Previous read")), mop->addr); | ||
| 416 | if (mop->tid == kMainThreadId) | ||
| 417 | Printf("main goroutine:\n"); | ||
| 418 | else | ||
| 419 | Printf("goroutine %d:\n", mop->tid); | ||
| 420 | PrintStack(mop->stack); | ||
| 421 | } | ||
| 422 | |||
| 423 | static void PrintLocation(const ReportLocation *loc) { | ||
| 424 | switch (loc->type) { | ||
| 425 | case ReportLocationHeap: { | ||
| 426 | Printf("\n"); | ||
| 427 | Printf("Heap block of size %zu at %p allocated by ", | ||
| 428 | loc->heap_chunk_size, loc->heap_chunk_start); | ||
| 429 | if (loc->tid == kMainThreadId) | ||
| 430 | Printf("main goroutine:\n"); | ||
| 431 | else | ||
| 432 | Printf("goroutine %d:\n", loc->tid); | ||
| 433 | PrintStack(loc->stack); | ||
| 434 | break; | ||
| 435 | } | ||
| 436 | case ReportLocationGlobal: { | ||
| 437 | Printf("\n"); | ||
| 438 | Printf("Global var %s of size %zu at %p declared at %s:%zu\n", | ||
| 439 | loc->global.name, loc->global.size, loc->global.start, | ||
| 440 | loc->global.file, loc->global.line); | ||
| 441 | break; | ||
| 442 | } | ||
| 443 | default: | ||
| 444 | break; | ||
| 445 | } | ||
| 446 | } | ||
| 447 | |||
| 448 | static void PrintThread(const ReportThread *rt) { | ||
| 449 | if (rt->id == kMainThreadId) | ||
| 450 | return; | ||
| 451 | Printf("\n"); | ||
| 452 | Printf("Goroutine %d (%s) created at:\n", | ||
| 453 | rt->id, rt->running ? "running" : "finished"); | ||
| 454 | PrintStack(rt->stack); | ||
| 455 | } | ||
| 456 | |||
| 457 | void PrintReport(const ReportDesc *rep) { | ||
| 458 | Printf("==================\n"); | ||
| 459 | if (rep->typ == ReportTypeRace) { | ||
| 460 | Printf("WARNING: DATA RACE"); | ||
| 461 | for (uptr i = 0; i < rep->mops.Size(); i++) | ||
| 462 | PrintMop(rep->mops[i], i == 0); | ||
| 463 | for (uptr i = 0; i < rep->locs.Size(); i++) | ||
| 464 | PrintLocation(rep->locs[i]); | ||
| 465 | for (uptr i = 0; i < rep->threads.Size(); i++) | ||
| 466 | PrintThread(rep->threads[i]); | ||
| 467 | } else if (rep->typ == ReportTypeDeadlock) { | ||
| 468 | Printf("WARNING: DEADLOCK\n"); | ||
| 469 | for (uptr i = 0; i < rep->mutexes.Size(); i++) { | ||
| 470 | Printf("Goroutine %d lock mutex %d while holding mutex %d:\n", | ||
| 471 | 999, rep->mutexes[i]->id, | ||
| 472 | rep->mutexes[(i+1) % rep->mutexes.Size()]->id); | ||
| 473 | PrintStack(rep->stacks[2*i]); | ||
| 474 | Printf("\n"); | ||
| 475 | Printf("Mutex %d was previously locked here:\n", | ||
| 476 | rep->mutexes[(i+1) % rep->mutexes.Size()]->id); | ||
| 477 | PrintStack(rep->stacks[2*i + 1]); | ||
| 478 | Printf("\n"); | ||
| 479 | } | ||
| 480 | } | ||
| 481 | Printf("==================\n"); | ||
| 482 | } | ||
| 483 | |||
| 484 | #endif | ||
| 485 | |||
| 486 | } // namespace __tsan | ||
lib/tsan/tsan_report.h created+135| ... | @@ -0,0 +1,135 @@ | ||
| 1 | //===-- tsan_report.h -------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef TSAN_REPORT_H | ||
| 13 | #define TSAN_REPORT_H | ||
| 14 | |||
| 15 | #include "sanitizer_common/sanitizer_symbolizer.h" | ||
| 16 | #include "sanitizer_common/sanitizer_thread_registry.h" | ||
| 17 | #include "sanitizer_common/sanitizer_vector.h" | ||
| 18 | #include "tsan_defs.h" | ||
| 19 | |||
| 20 | namespace __tsan { | ||
| 21 | |||
| 22 | enum ReportType { | ||
| 23 | ReportTypeRace, | ||
| 24 | ReportTypeVptrRace, | ||
| 25 | ReportTypeUseAfterFree, | ||
| 26 | ReportTypeVptrUseAfterFree, | ||
| 27 | ReportTypeExternalRace, | ||
| 28 | ReportTypeThreadLeak, | ||
| 29 | ReportTypeMutexDestroyLocked, | ||
| 30 | ReportTypeMutexDoubleLock, | ||
| 31 | ReportTypeMutexInvalidAccess, | ||
| 32 | ReportTypeMutexBadUnlock, | ||
| 33 | ReportTypeMutexBadReadLock, | ||
| 34 | ReportTypeMutexBadReadUnlock, | ||
| 35 | ReportTypeSignalUnsafe, | ||
| 36 | ReportTypeErrnoInSignal, | ||
| 37 | ReportTypeDeadlock | ||
| 38 | }; | ||
| 39 | |||
| 40 | struct ReportStack { | ||
| 41 | SymbolizedStack *frames; | ||
| 42 | bool suppressable; | ||
| 43 | static ReportStack *New(); | ||
| 44 | |||
| 45 | private: | ||
| 46 | ReportStack(); | ||
| 47 | }; | ||
| 48 | |||
| 49 | struct ReportMopMutex { | ||
| 50 | u64 id; | ||
| 51 | bool write; | ||
| 52 | }; | ||
| 53 | |||
| 54 | struct ReportMop { | ||
| 55 | int tid; | ||
| 56 | uptr addr; | ||
| 57 | int size; | ||
| 58 | bool write; | ||
| 59 | bool atomic; | ||
| 60 | uptr external_tag; | ||
| 61 | Vector<ReportMopMutex> mset; | ||
| 62 | ReportStack *stack; | ||
| 63 | |||
| 64 | ReportMop(); | ||
| 65 | }; | ||
| 66 | |||
| 67 | enum ReportLocationType { | ||
| 68 | ReportLocationGlobal, | ||
| 69 | ReportLocationHeap, | ||
| 70 | ReportLocationStack, | ||
| 71 | ReportLocationTLS, | ||
| 72 | ReportLocationFD | ||
| 73 | }; | ||
| 74 | |||
| 75 | struct ReportLocation { | ||
| 76 | ReportLocationType type; | ||
| 77 | DataInfo global; | ||
| 78 | uptr heap_chunk_start; | ||
| 79 | uptr heap_chunk_size; | ||
| 80 | uptr external_tag; | ||
| 81 | int tid; | ||
| 82 | int fd; | ||
| 83 | bool suppressable; | ||
| 84 | ReportStack *stack; | ||
| 85 | |||
| 86 | static ReportLocation *New(ReportLocationType type); | ||
| 87 | private: | ||
| 88 | explicit ReportLocation(ReportLocationType type); | ||
| 89 | }; | ||
| 90 | |||
| 91 | struct ReportThread { | ||
| 92 | int id; | ||
| 93 | tid_t os_id; | ||
| 94 | bool running; | ||
| 95 | ThreadType thread_type; | ||
| 96 | char *name; | ||
| 97 | u32 parent_tid; | ||
| 98 | ReportStack *stack; | ||
| 99 | }; | ||
| 100 | |||
| 101 | struct ReportMutex { | ||
| 102 | u64 id; | ||
| 103 | uptr addr; | ||
| 104 | bool destroyed; | ||
| 105 | ReportStack *stack; | ||
| 106 | }; | ||
| 107 | |||
| 108 | class ReportDesc { | ||
| 109 | public: | ||
| 110 | ReportType typ; | ||
| 111 | uptr tag; | ||
| 112 | Vector<ReportStack*> stacks; | ||
| 113 | Vector<ReportMop*> mops; | ||
| 114 | Vector<ReportLocation*> locs; | ||
| 115 | Vector<ReportMutex*> mutexes; | ||
| 116 | Vector<ReportThread*> threads; | ||
| 117 | Vector<int> unique_tids; | ||
| 118 | ReportStack *sleep; | ||
| 119 | int count; | ||
| 120 | |||
| 121 | ReportDesc(); | ||
| 122 | ~ReportDesc(); | ||
| 123 | |||
| 124 | private: | ||
| 125 | ReportDesc(const ReportDesc&); | ||
| 126 | void operator = (const ReportDesc&); | ||
| 127 | }; | ||
| 128 | |||
| 129 | // Format and output the report to the console/log. No additional logic. | ||
| 130 | void PrintReport(const ReportDesc *rep); | ||
| 131 | void PrintStack(const ReportStack *stack); | ||
| 132 | |||
| 133 | } // namespace __tsan | ||
| 134 | |||
| 135 | #endif // TSAN_REPORT_H | ||
lib/tsan/tsan_rtl.cpp created+1127| ... | @@ -0,0 +1,1127 @@ | ||
| 1 | //===-- tsan_rtl.cpp ------------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | // Main file (entry points) for the TSan run-time. | ||
| 12 | //===----------------------------------------------------------------------===// | ||
| 13 | |||
| 14 | #include "sanitizer_common/sanitizer_atomic.h" | ||
| 15 | #include "sanitizer_common/sanitizer_common.h" | ||
| 16 | #include "sanitizer_common/sanitizer_file.h" | ||
| 17 | #include "sanitizer_common/sanitizer_libc.h" | ||
| 18 | #include "sanitizer_common/sanitizer_stackdepot.h" | ||
| 19 | #include "sanitizer_common/sanitizer_placement_new.h" | ||
| 20 | #include "sanitizer_common/sanitizer_symbolizer.h" | ||
| 21 | #include "tsan_defs.h" | ||
| 22 | #include "tsan_platform.h" | ||
| 23 | #include "tsan_rtl.h" | ||
| 24 | #include "tsan_mman.h" | ||
| 25 | #include "tsan_suppressions.h" | ||
| 26 | #include "tsan_symbolize.h" | ||
| 27 | #include "ubsan/ubsan_init.h" | ||
| 28 | |||
| 29 | #ifdef __SSE3__ | ||
| 30 | // <emmintrin.h> transitively includes <stdlib.h>, | ||
| 31 | // and it's prohibited to include std headers into tsan runtime. | ||
| 32 | // So we do this dirty trick. | ||
| 33 | #define _MM_MALLOC_H_INCLUDED | ||
| 34 | #define __MM_MALLOC_H | ||
| 35 | #include <emmintrin.h> | ||
| 36 | typedef __m128i m128; | ||
| 37 | #endif | ||
| 38 | |||
| 39 | volatile int __tsan_resumed = 0; | ||
| 40 | |||
| 41 | extern "C" void __tsan_resume() { | ||
| 42 | __tsan_resumed = 1; | ||
| 43 | } | ||
| 44 | |||
| 45 | namespace __tsan { | ||
| 46 | |||
| 47 | #if !SANITIZER_GO && !SANITIZER_MAC | ||
| 48 | __attribute__((tls_model("initial-exec"))) | ||
| 49 | THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64); | ||
| 50 | #endif | ||
| 51 | static char ctx_placeholder[sizeof(Context)] ALIGNED(64); | ||
| 52 | Context *ctx; | ||
| 53 | |||
| 54 | // Can be overriden by a front-end. | ||
| 55 | #ifdef TSAN_EXTERNAL_HOOKS | ||
| 56 | bool OnFinalize(bool failed); | ||
| 57 | void OnInitialize(); | ||
| 58 | #else | ||
| 59 | SANITIZER_WEAK_CXX_DEFAULT_IMPL | ||
| 60 | bool OnFinalize(bool failed) { | ||
| 61 | return failed; | ||
| 62 | } | ||
| 63 | SANITIZER_WEAK_CXX_DEFAULT_IMPL | ||
| 64 | void OnInitialize() {} | ||
| 65 | #endif | ||
| 66 | |||
| 67 | static char thread_registry_placeholder[sizeof(ThreadRegistry)]; | ||
| 68 | |||
| 69 | static ThreadContextBase *CreateThreadContext(u32 tid) { | ||
| 70 | // Map thread trace when context is created. | ||
| 71 | char name[50]; | ||
| 72 | internal_snprintf(name, sizeof(name), "trace %u", tid); | ||
| 73 | MapThreadTrace(GetThreadTrace(tid), TraceSize() * sizeof(Event), name); | ||
| 74 | const uptr hdr = GetThreadTraceHeader(tid); | ||
| 75 | internal_snprintf(name, sizeof(name), "trace header %u", tid); | ||
| 76 | MapThreadTrace(hdr, sizeof(Trace), name); | ||
| 77 | new((void*)hdr) Trace(); | ||
| 78 | // We are going to use only a small part of the trace with the default | ||
| 79 | // value of history_size. However, the constructor writes to the whole trace. | ||
| 80 | // Unmap the unused part. | ||
| 81 | uptr hdr_end = hdr + sizeof(Trace); | ||
| 82 | hdr_end -= sizeof(TraceHeader) * (kTraceParts - TraceParts()); | ||
| 83 | hdr_end = RoundUp(hdr_end, GetPageSizeCached()); | ||
| 84 | if (hdr_end < hdr + sizeof(Trace)) | ||
| 85 | UnmapOrDie((void*)hdr_end, hdr + sizeof(Trace) - hdr_end); | ||
| 86 | void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext)); | ||
| 87 | return new(mem) ThreadContext(tid); | ||
| 88 | } | ||
| 89 | |||
| 90 | #if !SANITIZER_GO | ||
| 91 | static const u32 kThreadQuarantineSize = 16; | ||
| 92 | #else | ||
| 93 | static const u32 kThreadQuarantineSize = 64; | ||
| 94 | #endif | ||
| 95 | |||
| 96 | Context::Context() | ||
| 97 | : initialized() | ||
| 98 | , report_mtx(MutexTypeReport, StatMtxReport) | ||
| 99 | , nreported() | ||
| 100 | , nmissed_expected() | ||
| 101 | , thread_registry(new(thread_registry_placeholder) ThreadRegistry( | ||
| 102 | CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse)) | ||
| 103 | , racy_mtx(MutexTypeRacy, StatMtxRacy) | ||
| 104 | , racy_stacks() | ||
| 105 | , racy_addresses() | ||
| 106 | , fired_suppressions_mtx(MutexTypeFired, StatMtxFired) | ||
| 107 | , clock_alloc("clock allocator") { | ||
| 108 | fired_suppressions.reserve(8); | ||
| 109 | } | ||
| 110 | |||
| 111 | // The objects are allocated in TLS, so one may rely on zero-initialization. | ||
| 112 | ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch, | ||
| 113 | unsigned reuse_count, | ||
| 114 | uptr stk_addr, uptr stk_size, | ||
| 115 | uptr tls_addr, uptr tls_size) | ||
| 116 | : fast_state(tid, epoch) | ||
| 117 | // Do not touch these, rely on zero initialization, | ||
| 118 | // they may be accessed before the ctor. | ||
| 119 | // , ignore_reads_and_writes() | ||
| 120 | // , ignore_interceptors() | ||
| 121 | , clock(tid, reuse_count) | ||
| 122 | #if !SANITIZER_GO | ||
| 123 | , jmp_bufs() | ||
| 124 | #endif | ||
| 125 | , tid(tid) | ||
| 126 | , unique_id(unique_id) | ||
| 127 | , stk_addr(stk_addr) | ||
| 128 | , stk_size(stk_size) | ||
| 129 | , tls_addr(tls_addr) | ||
| 130 | , tls_size(tls_size) | ||
| 131 | #if !SANITIZER_GO | ||
| 132 | , last_sleep_clock(tid) | ||
| 133 | #endif | ||
| 134 | { | ||
| 135 | } | ||
| 136 | |||
| 137 | #if !SANITIZER_GO | ||
| 138 | static void MemoryProfiler(Context *ctx, fd_t fd, int i) { | ||
| 139 | uptr n_threads; | ||
| 140 | uptr n_running_threads; | ||
| 141 | ctx->thread_registry->GetNumberOfThreads(&n_threads, &n_running_threads); | ||
| 142 | InternalMmapVector<char> buf(4096); | ||
| 143 | WriteMemoryProfile(buf.data(), buf.size(), n_threads, n_running_threads); | ||
| 144 | WriteToFile(fd, buf.data(), internal_strlen(buf.data())); | ||
| 145 | } | ||
| 146 | |||
| 147 | static void *BackgroundThread(void *arg) { | ||
| 148 | // This is a non-initialized non-user thread, nothing to see here. | ||
| 149 | // We don't use ScopedIgnoreInterceptors, because we want ignores to be | ||
| 150 | // enabled even when the thread function exits (e.g. during pthread thread | ||
| 151 | // shutdown code). | ||
| 152 | cur_thread_init(); | ||
| 153 | cur_thread()->ignore_interceptors++; | ||
| 154 | const u64 kMs2Ns = 1000 * 1000; | ||
| 155 | |||
| 156 | fd_t mprof_fd = kInvalidFd; | ||
| 157 | if (flags()->profile_memory && flags()->profile_memory[0]) { | ||
| 158 | if (internal_strcmp(flags()->profile_memory, "stdout") == 0) { | ||
| 159 | mprof_fd = 1; | ||
| 160 | } else if (internal_strcmp(flags()->profile_memory, "stderr") == 0) { | ||
| 161 | mprof_fd = 2; | ||
| 162 | } else { | ||
| 163 | InternalScopedString filename(kMaxPathLength); | ||
| 164 | filename.append("%s.%d", flags()->profile_memory, (int)internal_getpid()); | ||
| 165 | fd_t fd = OpenFile(filename.data(), WrOnly); | ||
| 166 | if (fd == kInvalidFd) { | ||
| 167 | Printf("ThreadSanitizer: failed to open memory profile file '%s'\n", | ||
| 168 | &filename[0]); | ||
| 169 | } else { | ||
| 170 | mprof_fd = fd; | ||
| 171 | } | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | u64 last_flush = NanoTime(); | ||
| 176 | uptr last_rss = 0; | ||
| 177 | for (int i = 0; | ||
| 178 | atomic_load(&ctx->stop_background_thread, memory_order_relaxed) == 0; | ||
| 179 | i++) { | ||
| 180 | SleepForMillis(100); | ||
| 181 | u64 now = NanoTime(); | ||
| 182 | |||
| 183 | // Flush memory if requested. | ||
| 184 | if (flags()->flush_memory_ms > 0) { | ||
| 185 | if (last_flush + flags()->flush_memory_ms * kMs2Ns < now) { | ||
| 186 | VPrintf(1, "ThreadSanitizer: periodic memory flush\n"); | ||
| 187 | FlushShadowMemory(); | ||
| 188 | last_flush = NanoTime(); | ||
| 189 | } | ||
| 190 | } | ||
| 191 | // GetRSS can be expensive on huge programs, so don't do it every 100ms. | ||
| 192 | if (flags()->memory_limit_mb > 0) { | ||
| 193 | uptr rss = GetRSS(); | ||
| 194 | uptr limit = uptr(flags()->memory_limit_mb) << 20; | ||
| 195 | VPrintf(1, "ThreadSanitizer: memory flush check" | ||
| 196 | " RSS=%llu LAST=%llu LIMIT=%llu\n", | ||
| 197 | (u64)rss >> 20, (u64)last_rss >> 20, (u64)limit >> 20); | ||
| 198 | if (2 * rss > limit + last_rss) { | ||
| 199 | VPrintf(1, "ThreadSanitizer: flushing memory due to RSS\n"); | ||
| 200 | FlushShadowMemory(); | ||
| 201 | rss = GetRSS(); | ||
| 202 | VPrintf(1, "ThreadSanitizer: memory flushed RSS=%llu\n", (u64)rss>>20); | ||
| 203 | } | ||
| 204 | last_rss = rss; | ||
| 205 | } | ||
| 206 | |||
| 207 | // Write memory profile if requested. | ||
| 208 | if (mprof_fd != kInvalidFd) | ||
| 209 | MemoryProfiler(ctx, mprof_fd, i); | ||
| 210 | |||
| 211 | // Flush symbolizer cache if requested. | ||
| 212 | if (flags()->flush_symbolizer_ms > 0) { | ||
| 213 | u64 last = atomic_load(&ctx->last_symbolize_time_ns, | ||
| 214 | memory_order_relaxed); | ||
| 215 | if (last != 0 && last + flags()->flush_symbolizer_ms * kMs2Ns < now) { | ||
| 216 | Lock l(&ctx->report_mtx); | ||
| 217 | ScopedErrorReportLock l2; | ||
| 218 | SymbolizeFlush(); | ||
| 219 | atomic_store(&ctx->last_symbolize_time_ns, 0, memory_order_relaxed); | ||
| 220 | } | ||
| 221 | } | ||
| 222 | } | ||
| 223 | return nullptr; | ||
| 224 | } | ||
| 225 | |||
| 226 | static void StartBackgroundThread() { | ||
| 227 | ctx->background_thread = internal_start_thread(&BackgroundThread, 0); | ||
| 228 | } | ||
| 229 | |||
| 230 | #ifndef __mips__ | ||
| 231 | static void StopBackgroundThread() { | ||
| 232 | atomic_store(&ctx->stop_background_thread, 1, memory_order_relaxed); | ||
| 233 | internal_join_thread(ctx->background_thread); | ||
| 234 | ctx->background_thread = 0; | ||
| 235 | } | ||
| 236 | #endif | ||
| 237 | #endif | ||
| 238 | |||
| 239 | void DontNeedShadowFor(uptr addr, uptr size) { | ||
| 240 | ReleaseMemoryPagesToOS(MemToShadow(addr), MemToShadow(addr + size)); | ||
| 241 | } | ||
| 242 | |||
| 243 | #if !SANITIZER_GO | ||
| 244 | void UnmapShadow(ThreadState *thr, uptr addr, uptr size) { | ||
| 245 | if (size == 0) return; | ||
| 246 | DontNeedShadowFor(addr, size); | ||
| 247 | ScopedGlobalProcessor sgp; | ||
| 248 | ctx->metamap.ResetRange(thr->proc(), addr, size); | ||
| 249 | } | ||
| 250 | #endif | ||
| 251 | |||
| 252 | void MapShadow(uptr addr, uptr size) { | ||
| 253 | // Global data is not 64K aligned, but there are no adjacent mappings, | ||
| 254 | // so we can get away with unaligned mapping. | ||
| 255 | // CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment | ||
| 256 | const uptr kPageSize = GetPageSizeCached(); | ||
| 257 | uptr shadow_begin = RoundDownTo((uptr)MemToShadow(addr), kPageSize); | ||
| 258 | uptr shadow_end = RoundUpTo((uptr)MemToShadow(addr + size), kPageSize); | ||
| 259 | if (!MmapFixedNoReserve(shadow_begin, shadow_end - shadow_begin, "shadow")) | ||
| 260 | Die(); | ||
| 261 | |||
| 262 | // Meta shadow is 2:1, so tread carefully. | ||
| 263 | static bool data_mapped = false; | ||
| 264 | static uptr mapped_meta_end = 0; | ||
| 265 | uptr meta_begin = (uptr)MemToMeta(addr); | ||
| 266 | uptr meta_end = (uptr)MemToMeta(addr + size); | ||
| 267 | meta_begin = RoundDownTo(meta_begin, 64 << 10); | ||
| 268 | meta_end = RoundUpTo(meta_end, 64 << 10); | ||
| 269 | if (!data_mapped) { | ||
| 270 | // First call maps data+bss. | ||
| 271 | data_mapped = true; | ||
| 272 | if (!MmapFixedNoReserve(meta_begin, meta_end - meta_begin, "meta shadow")) | ||
| 273 | Die(); | ||
| 274 | } else { | ||
| 275 | // Mapping continous heap. | ||
| 276 | // Windows wants 64K alignment. | ||
| 277 | meta_begin = RoundDownTo(meta_begin, 64 << 10); | ||
| 278 | meta_end = RoundUpTo(meta_end, 64 << 10); | ||
| 279 | if (meta_end <= mapped_meta_end) | ||
| 280 | return; | ||
| 281 | if (meta_begin < mapped_meta_end) | ||
| 282 | meta_begin = mapped_meta_end; | ||
| 283 | if (!MmapFixedNoReserve(meta_begin, meta_end - meta_begin, "meta shadow")) | ||
| 284 | Die(); | ||
| 285 | mapped_meta_end = meta_end; | ||
| 286 | } | ||
| 287 | VPrintf(2, "mapped meta shadow for (%p-%p) at (%p-%p)\n", | ||
| 288 | addr, addr+size, meta_begin, meta_end); | ||
| 289 | } | ||
| 290 | |||
| 291 | void MapThreadTrace(uptr addr, uptr size, const char *name) { | ||
| 292 | DPrintf("#0: Mapping trace at %p-%p(0x%zx)\n", addr, addr + size, size); | ||
| 293 | CHECK_GE(addr, TraceMemBeg()); | ||
| 294 | CHECK_LE(addr + size, TraceMemEnd()); | ||
| 295 | CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment | ||
| 296 | if (!MmapFixedNoReserve(addr, size, name)) { | ||
| 297 | Printf("FATAL: ThreadSanitizer can not mmap thread trace (%p/%p)\n", | ||
| 298 | addr, size); | ||
| 299 | Die(); | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | static void CheckShadowMapping() { | ||
| 304 | uptr beg, end; | ||
| 305 | for (int i = 0; GetUserRegion(i, &beg, &end); i++) { | ||
| 306 | // Skip cases for empty regions (heap definition for architectures that | ||
| 307 | // do not use 64-bit allocator). | ||
| 308 | if (beg == end) | ||
| 309 | continue; | ||
| 310 | VPrintf(3, "checking shadow region %p-%p\n", beg, end); | ||
| 311 | uptr prev = 0; | ||
| 312 | for (uptr p0 = beg; p0 <= end; p0 += (end - beg) / 4) { | ||
| 313 | for (int x = -(int)kShadowCell; x <= (int)kShadowCell; x += kShadowCell) { | ||
| 314 | const uptr p = RoundDown(p0 + x, kShadowCell); | ||
| 315 | if (p < beg || p >= end) | ||
| 316 | continue; | ||
| 317 | const uptr s = MemToShadow(p); | ||
| 318 | const uptr m = (uptr)MemToMeta(p); | ||
| 319 | VPrintf(3, " checking pointer %p: shadow=%p meta=%p\n", p, s, m); | ||
| 320 | CHECK(IsAppMem(p)); | ||
| 321 | CHECK(IsShadowMem(s)); | ||
| 322 | CHECK_EQ(p, ShadowToMem(s)); | ||
| 323 | CHECK(IsMetaMem(m)); | ||
| 324 | if (prev) { | ||
| 325 | // Ensure that shadow and meta mappings are linear within a single | ||
| 326 | // user range. Lots of code that processes memory ranges assumes it. | ||
| 327 | const uptr prev_s = MemToShadow(prev); | ||
| 328 | const uptr prev_m = (uptr)MemToMeta(prev); | ||
| 329 | CHECK_EQ(s - prev_s, (p - prev) * kShadowMultiplier); | ||
| 330 | CHECK_EQ((m - prev_m) / kMetaShadowSize, | ||
| 331 | (p - prev) / kMetaShadowCell); | ||
| 332 | } | ||
| 333 | prev = p; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | } | ||
| 337 | } | ||
| 338 | |||
| 339 | #if !SANITIZER_GO | ||
| 340 | static void OnStackUnwind(const SignalContext &sig, const void *, | ||
| 341 | BufferedStackTrace *stack) { | ||
| 342 | stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context, | ||
| 343 | common_flags()->fast_unwind_on_fatal); | ||
| 344 | } | ||
| 345 | |||
| 346 | static void TsanOnDeadlySignal(int signo, void *siginfo, void *context) { | ||
| 347 | HandleDeadlySignal(siginfo, context, GetTid(), &OnStackUnwind, nullptr); | ||
| 348 | } | ||
| 349 | #endif | ||
| 350 | |||
| 351 | void Initialize(ThreadState *thr) { | ||
| 352 | // Thread safe because done before all threads exist. | ||
| 353 | static bool is_initialized = false; | ||
| 354 | if (is_initialized) | ||
| 355 | return; | ||
| 356 | is_initialized = true; | ||
| 357 | // We are not ready to handle interceptors yet. | ||
| 358 | ScopedIgnoreInterceptors ignore; | ||
| 359 | SanitizerToolName = "ThreadSanitizer"; | ||
| 360 | // Install tool-specific callbacks in sanitizer_common. | ||
| 361 | SetCheckFailedCallback(TsanCheckFailed); | ||
| 362 | |||
| 363 | ctx = new(ctx_placeholder) Context; | ||
| 364 | const char *env_name = SANITIZER_GO ? "GORACE" : "TSAN_OPTIONS"; | ||
| 365 | const char *options = GetEnv(env_name); | ||
| 366 | CacheBinaryName(); | ||
| 367 | CheckASLR(); | ||
| 368 | InitializeFlags(&ctx->flags, options, env_name); | ||
| 369 | AvoidCVE_2016_2143(); | ||
| 370 | __sanitizer::InitializePlatformEarly(); | ||
| 371 | __tsan::InitializePlatformEarly(); | ||
| 372 | |||
| 373 | #if !SANITIZER_GO | ||
| 374 | // Re-exec ourselves if we need to set additional env or command line args. | ||
| 375 | MaybeReexec(); | ||
| 376 | |||
| 377 | InitializeAllocator(); | ||
| 378 | ReplaceSystemMalloc(); | ||
| 379 | #endif | ||
| 380 | if (common_flags()->detect_deadlocks) | ||
| 381 | ctx->dd = DDetector::Create(flags()); | ||
| 382 | Processor *proc = ProcCreate(); | ||
| 383 | ProcWire(proc, thr); | ||
| 384 | InitializeInterceptors(); | ||
| 385 | CheckShadowMapping(); | ||
| 386 | InitializePlatform(); | ||
| 387 | InitializeMutex(); | ||
| 388 | InitializeDynamicAnnotations(); | ||
| 389 | #if !SANITIZER_GO | ||
| 390 | InitializeShadowMemory(); | ||
| 391 | InitializeAllocatorLate(); | ||
| 392 | InstallDeadlySignalHandlers(TsanOnDeadlySignal); | ||
| 393 | #endif | ||
| 394 | // Setup correct file descriptor for error reports. | ||
| 395 | __sanitizer_set_report_path(common_flags()->log_path); | ||
| 396 | InitializeSuppressions(); | ||
| 397 | #if !SANITIZER_GO | ||
| 398 | InitializeLibIgnore(); | ||
| 399 | Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer); | ||
| 400 | #endif | ||
| 401 | |||
| 402 | VPrintf(1, "***** Running under ThreadSanitizer v2 (pid %d) *****\n", | ||
| 403 | (int)internal_getpid()); | ||
| 404 | |||
| 405 | // Initialize thread 0. | ||
| 406 | int tid = ThreadCreate(thr, 0, 0, true); | ||
| 407 | CHECK_EQ(tid, 0); | ||
| 408 | ThreadStart(thr, tid, GetTid(), ThreadType::Regular); | ||
| 409 | #if TSAN_CONTAINS_UBSAN | ||
| 410 | __ubsan::InitAsPlugin(); | ||
| 411 | #endif | ||
| 412 | ctx->initialized = true; | ||
| 413 | |||
| 414 | #if !SANITIZER_GO | ||
| 415 | Symbolizer::LateInitialize(); | ||
| 416 | #endif | ||
| 417 | |||
| 418 | if (flags()->stop_on_start) { | ||
| 419 | Printf("ThreadSanitizer is suspended at startup (pid %d)." | ||
| 420 | " Call __tsan_resume().\n", | ||
| 421 | (int)internal_getpid()); | ||
| 422 | while (__tsan_resumed == 0) {} | ||
| 423 | } | ||
| 424 | |||
| 425 | OnInitialize(); | ||
| 426 | } | ||
| 427 | |||
| 428 | void MaybeSpawnBackgroundThread() { | ||
| 429 | // On MIPS, TSan initialization is run before | ||
| 430 | // __pthread_initialize_minimal_internal() is finished, so we can not spawn | ||
| 431 | // new threads. | ||
| 432 | #if !SANITIZER_GO && !defined(__mips__) | ||
| 433 | static atomic_uint32_t bg_thread = {}; | ||
| 434 | if (atomic_load(&bg_thread, memory_order_relaxed) == 0 && | ||
| 435 | atomic_exchange(&bg_thread, 1, memory_order_relaxed) == 0) { | ||
| 436 | StartBackgroundThread(); | ||
| 437 | SetSandboxingCallback(StopBackgroundThread); | ||
| 438 | } | ||
| 439 | #endif | ||
| 440 | } | ||
| 441 | |||
| 442 | |||
| 443 | int Finalize(ThreadState *thr) { | ||
| 444 | bool failed = false; | ||
| 445 | |||
| 446 | if (common_flags()->print_module_map == 1) PrintModuleMap(); | ||
| 447 | |||
| 448 | if (flags()->atexit_sleep_ms > 0 && ThreadCount(thr) > 1) | ||
| 449 | SleepForMillis(flags()->atexit_sleep_ms); | ||
| 450 | |||
| 451 | // Wait for pending reports. | ||
| 452 | ctx->report_mtx.Lock(); | ||
| 453 | { ScopedErrorReportLock l; } | ||
| 454 | ctx->report_mtx.Unlock(); | ||
| 455 | |||
| 456 | #if !SANITIZER_GO | ||
| 457 | if (Verbosity()) AllocatorPrintStats(); | ||
| 458 | #endif | ||
| 459 | |||
| 460 | ThreadFinalize(thr); | ||
| 461 | |||
| 462 | if (ctx->nreported) { | ||
| 463 | failed = true; | ||
| 464 | #if !SANITIZER_GO | ||
| 465 | Printf("ThreadSanitizer: reported %d warnings\n", ctx->nreported); | ||
| 466 | #else | ||
| 467 | Printf("Found %d data race(s)\n", ctx->nreported); | ||
| 468 | #endif | ||
| 469 | } | ||
| 470 | |||
| 471 | if (ctx->nmissed_expected) { | ||
| 472 | failed = true; | ||
| 473 | Printf("ThreadSanitizer: missed %d expected races\n", | ||
| 474 | ctx->nmissed_expected); | ||
| 475 | } | ||
| 476 | |||
| 477 | if (common_flags()->print_suppressions) | ||
| 478 | PrintMatchedSuppressions(); | ||
| 479 | #if !SANITIZER_GO | ||
| 480 | if (flags()->print_benign) | ||
| 481 | PrintMatchedBenignRaces(); | ||
| 482 | #endif | ||
| 483 | |||
| 484 | failed = OnFinalize(failed); | ||
| 485 | |||
| 486 | #if TSAN_COLLECT_STATS | ||
| 487 | StatAggregate(ctx->stat, thr->stat); | ||
| 488 | StatOutput(ctx->stat); | ||
| 489 | #endif | ||
| 490 | |||
| 491 | return failed ? common_flags()->exitcode : 0; | ||
| 492 | } | ||
| 493 | |||
| 494 | #if !SANITIZER_GO | ||
| 495 | void ForkBefore(ThreadState *thr, uptr pc) { | ||
| 496 | ctx->thread_registry->Lock(); | ||
| 497 | ctx->report_mtx.Lock(); | ||
| 498 | // Ignore memory accesses in the pthread_atfork callbacks. | ||
| 499 | // If any of them triggers a data race we will deadlock | ||
| 500 | // on the report_mtx. | ||
| 501 | // We could ignore interceptors and sync operations as well, | ||
| 502 | // but so far it's unclear if it will do more good or harm. | ||
| 503 | // Unnecessarily ignoring things can lead to false positives later. | ||
| 504 | ThreadIgnoreBegin(thr, pc); | ||
| 505 | } | ||
| 506 | |||
| 507 | void ForkParentAfter(ThreadState *thr, uptr pc) { | ||
| 508 | ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore. | ||
| 509 | ctx->report_mtx.Unlock(); | ||
| 510 | ctx->thread_registry->Unlock(); | ||
| 511 | } | ||
| 512 | |||
| 513 | void ForkChildAfter(ThreadState *thr, uptr pc) { | ||
| 514 | ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore. | ||
| 515 | ctx->report_mtx.Unlock(); | ||
| 516 | ctx->thread_registry->Unlock(); | ||
| 517 | |||
| 518 | uptr nthread = 0; | ||
| 519 | ctx->thread_registry->GetNumberOfThreads(0, 0, &nthread /* alive threads */); | ||
| 520 | VPrintf(1, "ThreadSanitizer: forked new process with pid %d," | ||
| 521 | " parent had %d threads\n", (int)internal_getpid(), (int)nthread); | ||
| 522 | if (nthread == 1) { | ||
| 523 | StartBackgroundThread(); | ||
| 524 | } else { | ||
| 525 | // We've just forked a multi-threaded process. We cannot reasonably function | ||
| 526 | // after that (some mutexes may be locked before fork). So just enable | ||
| 527 | // ignores for everything in the hope that we will exec soon. | ||
| 528 | ctx->after_multithreaded_fork = true; | ||
| 529 | thr->ignore_interceptors++; | ||
| 530 | ThreadIgnoreBegin(thr, pc); | ||
| 531 | ThreadIgnoreSyncBegin(thr, pc); | ||
| 532 | } | ||
| 533 | } | ||
| 534 | #endif | ||
| 535 | |||
| 536 | #if SANITIZER_GO | ||
| 537 | NOINLINE | ||
| 538 | void GrowShadowStack(ThreadState *thr) { | ||
| 539 | const int sz = thr->shadow_stack_end - thr->shadow_stack; | ||
| 540 | const int newsz = 2 * sz; | ||
| 541 | uptr *newstack = (uptr*)internal_alloc(MBlockShadowStack, | ||
| 542 | newsz * sizeof(uptr)); | ||
| 543 | internal_memcpy(newstack, thr->shadow_stack, sz * sizeof(uptr)); | ||
| 544 | internal_free(thr->shadow_stack); | ||
| 545 | thr->shadow_stack = newstack; | ||
| 546 | thr->shadow_stack_pos = newstack + sz; | ||
| 547 | thr->shadow_stack_end = newstack + newsz; | ||
| 548 | } | ||
| 549 | #endif | ||
| 550 | |||
| 551 | u32 CurrentStackId(ThreadState *thr, uptr pc) { | ||
| 552 | if (!thr->is_inited) // May happen during bootstrap. | ||
| 553 | return 0; | ||
| 554 | if (pc != 0) { | ||
| 555 | #if !SANITIZER_GO | ||
| 556 | DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end); | ||
| 557 | #else | ||
| 558 | if (thr->shadow_stack_pos == thr->shadow_stack_end) | ||
| 559 | GrowShadowStack(thr); | ||
| 560 | #endif | ||
| 561 | thr->shadow_stack_pos[0] = pc; | ||
| 562 | thr->shadow_stack_pos++; | ||
| 563 | } | ||
| 564 | u32 id = StackDepotPut( | ||
| 565 | StackTrace(thr->shadow_stack, thr->shadow_stack_pos - thr->shadow_stack)); | ||
| 566 | if (pc != 0) | ||
| 567 | thr->shadow_stack_pos--; | ||
| 568 | return id; | ||
| 569 | } | ||
| 570 | |||
| 571 | void TraceSwitch(ThreadState *thr) { | ||
| 572 | #if !SANITIZER_GO | ||
| 573 | if (ctx->after_multithreaded_fork) | ||
| 574 | return; | ||
| 575 | #endif | ||
| 576 | thr->nomalloc++; | ||
| 577 | Trace *thr_trace = ThreadTrace(thr->tid); | ||
| 578 | Lock l(&thr_trace->mtx); | ||
| 579 | unsigned trace = (thr->fast_state.epoch() / kTracePartSize) % TraceParts(); | ||
| 580 | TraceHeader *hdr = &thr_trace->headers[trace]; | ||
| 581 | hdr->epoch0 = thr->fast_state.epoch(); | ||
| 582 | ObtainCurrentStack(thr, 0, &hdr->stack0); | ||
| 583 | hdr->mset0 = thr->mset; | ||
| 584 | thr->nomalloc--; | ||
| 585 | } | ||
| 586 | |||
| 587 | Trace *ThreadTrace(int tid) { | ||
| 588 | return (Trace*)GetThreadTraceHeader(tid); | ||
| 589 | } | ||
| 590 | |||
| 591 | uptr TraceTopPC(ThreadState *thr) { | ||
| 592 | Event *events = (Event*)GetThreadTrace(thr->tid); | ||
| 593 | uptr pc = events[thr->fast_state.GetTracePos()]; | ||
| 594 | return pc; | ||
| 595 | } | ||
| 596 | |||
| 597 | uptr TraceSize() { | ||
| 598 | return (uptr)(1ull << (kTracePartSizeBits + flags()->history_size + 1)); | ||
| 599 | } | ||
| 600 | |||
| 601 | uptr TraceParts() { | ||
| 602 | return TraceSize() / kTracePartSize; | ||
| 603 | } | ||
| 604 | |||
| 605 | #if !SANITIZER_GO | ||
| 606 | extern "C" void __tsan_trace_switch() { | ||
| 607 | TraceSwitch(cur_thread()); | ||
| 608 | } | ||
| 609 | |||
| 610 | extern "C" void __tsan_report_race() { | ||
| 611 | ReportRace(cur_thread()); | ||
| 612 | } | ||
| 613 | #endif | ||
| 614 | |||
| 615 | ALWAYS_INLINE | ||
| 616 | Shadow LoadShadow(u64 *p) { | ||
| 617 | u64 raw = atomic_load((atomic_uint64_t*)p, memory_order_relaxed); | ||
| 618 | return Shadow(raw); | ||
| 619 | } | ||
| 620 | |||
| 621 | ALWAYS_INLINE | ||
| 622 | void StoreShadow(u64 *sp, u64 s) { | ||
| 623 | atomic_store((atomic_uint64_t*)sp, s, memory_order_relaxed); | ||
| 624 | } | ||
| 625 | |||
| 626 | ALWAYS_INLINE | ||
| 627 | void StoreIfNotYetStored(u64 *sp, u64 *s) { | ||
| 628 | StoreShadow(sp, *s); | ||
| 629 | *s = 0; | ||
| 630 | } | ||
| 631 | |||
| 632 | ALWAYS_INLINE | ||
| 633 | void HandleRace(ThreadState *thr, u64 *shadow_mem, | ||
| 634 | Shadow cur, Shadow old) { | ||
| 635 | thr->racy_state[0] = cur.raw(); | ||
| 636 | thr->racy_state[1] = old.raw(); | ||
| 637 | thr->racy_shadow_addr = shadow_mem; | ||
| 638 | #if !SANITIZER_GO | ||
| 639 | HACKY_CALL(__tsan_report_race); | ||
| 640 | #else | ||
| 641 | ReportRace(thr); | ||
| 642 | #endif | ||
| 643 | } | ||
| 644 | |||
| 645 | static inline bool HappensBefore(Shadow old, ThreadState *thr) { | ||
| 646 | return thr->clock.get(old.TidWithIgnore()) >= old.epoch(); | ||
| 647 | } | ||
| 648 | |||
| 649 | ALWAYS_INLINE | ||
| 650 | void MemoryAccessImpl1(ThreadState *thr, uptr addr, | ||
| 651 | int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic, | ||
| 652 | u64 *shadow_mem, Shadow cur) { | ||
| 653 | StatInc(thr, StatMop); | ||
| 654 | StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead); | ||
| 655 | StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog)); | ||
| 656 | |||
| 657 | // This potentially can live in an MMX/SSE scratch register. | ||
| 658 | // The required intrinsics are: | ||
| 659 | // __m128i _mm_move_epi64(__m128i*); | ||
| 660 | // _mm_storel_epi64(u64*, __m128i); | ||
| 661 | u64 store_word = cur.raw(); | ||
| 662 | bool stored = false; | ||
| 663 | |||
| 664 | // scan all the shadow values and dispatch to 4 categories: | ||
| 665 | // same, replace, candidate and race (see comments below). | ||
| 666 | // we consider only 3 cases regarding access sizes: | ||
| 667 | // equal, intersect and not intersect. initially I considered | ||
| 668 | // larger and smaller as well, it allowed to replace some | ||
| 669 | // 'candidates' with 'same' or 'replace', but I think | ||
| 670 | // it's just not worth it (performance- and complexity-wise). | ||
| 671 | |||
| 672 | Shadow old(0); | ||
| 673 | |||
| 674 | // It release mode we manually unroll the loop, | ||
| 675 | // because empirically gcc generates better code this way. | ||
| 676 | // However, we can't afford unrolling in debug mode, because the function | ||
| 677 | // consumes almost 4K of stack. Gtest gives only 4K of stack to death test | ||
| 678 | // threads, which is not enough for the unrolled loop. | ||
| 679 | #if SANITIZER_DEBUG | ||
| 680 | for (int idx = 0; idx < 4; idx++) { | ||
| 681 | #include "tsan_update_shadow_word_inl.h" | ||
| 682 | } | ||
| 683 | #else | ||
| 684 | int idx = 0; | ||
| 685 | #include "tsan_update_shadow_word_inl.h" | ||
| 686 | idx = 1; | ||
| 687 | if (stored) { | ||
| 688 | #include "tsan_update_shadow_word_inl.h" | ||
| 689 | } else { | ||
| 690 | #include "tsan_update_shadow_word_inl.h" | ||
| 691 | } | ||
| 692 | idx = 2; | ||
| 693 | if (stored) { | ||
| 694 | #include "tsan_update_shadow_word_inl.h" | ||
| 695 | } else { | ||
| 696 | #include "tsan_update_shadow_word_inl.h" | ||
| 697 | } | ||
| 698 | idx = 3; | ||
| 699 | if (stored) { | ||
| 700 | #include "tsan_update_shadow_word_inl.h" | ||
| 701 | } else { | ||
| 702 | #include "tsan_update_shadow_word_inl.h" | ||
| 703 | } | ||
| 704 | #endif | ||
| 705 | |||
| 706 | // we did not find any races and had already stored | ||
| 707 | // the current access info, so we are done | ||
| 708 | if (LIKELY(stored)) | ||
| 709 | return; | ||
| 710 | // choose a random candidate slot and replace it | ||
| 711 | StoreShadow(shadow_mem + (cur.epoch() % kShadowCnt), store_word); | ||
| 712 | StatInc(thr, StatShadowReplace); | ||
| 713 | return; | ||
| 714 | RACE: | ||
| 715 | HandleRace(thr, shadow_mem, cur, old); | ||
| 716 | return; | ||
| 717 | } | ||
| 718 | |||
| 719 | void UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr, | ||
| 720 | int size, bool kAccessIsWrite, bool kIsAtomic) { | ||
| 721 | while (size) { | ||
| 722 | int size1 = 1; | ||
| 723 | int kAccessSizeLog = kSizeLog1; | ||
| 724 | if (size >= 8 && (addr & ~7) == ((addr + 7) & ~7)) { | ||
| 725 | size1 = 8; | ||
| 726 | kAccessSizeLog = kSizeLog8; | ||
| 727 | } else if (size >= 4 && (addr & ~7) == ((addr + 3) & ~7)) { | ||
| 728 | size1 = 4; | ||
| 729 | kAccessSizeLog = kSizeLog4; | ||
| 730 | } else if (size >= 2 && (addr & ~7) == ((addr + 1) & ~7)) { | ||
| 731 | size1 = 2; | ||
| 732 | kAccessSizeLog = kSizeLog2; | ||
| 733 | } | ||
| 734 | MemoryAccess(thr, pc, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic); | ||
| 735 | addr += size1; | ||
| 736 | size -= size1; | ||
| 737 | } | ||
| 738 | } | ||
| 739 | |||
| 740 | ALWAYS_INLINE | ||
| 741 | bool ContainsSameAccessSlow(u64 *s, u64 a, u64 sync_epoch, bool is_write) { | ||
| 742 | Shadow cur(a); | ||
| 743 | for (uptr i = 0; i < kShadowCnt; i++) { | ||
| 744 | Shadow old(LoadShadow(&s[i])); | ||
| 745 | if (Shadow::Addr0AndSizeAreEqual(cur, old) && | ||
| 746 | old.TidWithIgnore() == cur.TidWithIgnore() && | ||
| 747 | old.epoch() > sync_epoch && | ||
| 748 | old.IsAtomic() == cur.IsAtomic() && | ||
| 749 | old.IsRead() <= cur.IsRead()) | ||
| 750 | return true; | ||
| 751 | } | ||
| 752 | return false; | ||
| 753 | } | ||
| 754 | |||
| 755 | #if defined(__SSE3__) | ||
| 756 | #define SHUF(v0, v1, i0, i1, i2, i3) _mm_castps_si128(_mm_shuffle_ps( \ | ||
| 757 | _mm_castsi128_ps(v0), _mm_castsi128_ps(v1), \ | ||
| 758 | (i0)*1 + (i1)*4 + (i2)*16 + (i3)*64)) | ||
| 759 | ALWAYS_INLINE | ||
| 760 | bool ContainsSameAccessFast(u64 *s, u64 a, u64 sync_epoch, bool is_write) { | ||
| 761 | // This is an optimized version of ContainsSameAccessSlow. | ||
| 762 | // load current access into access[0:63] | ||
| 763 | const m128 access = _mm_cvtsi64_si128(a); | ||
| 764 | // duplicate high part of access in addr0: | ||
| 765 | // addr0[0:31] = access[32:63] | ||
| 766 | // addr0[32:63] = access[32:63] | ||
| 767 | // addr0[64:95] = access[32:63] | ||
| 768 | // addr0[96:127] = access[32:63] | ||
| 769 | const m128 addr0 = SHUF(access, access, 1, 1, 1, 1); | ||
| 770 | // load 4 shadow slots | ||
| 771 | const m128 shadow0 = _mm_load_si128((__m128i*)s); | ||
| 772 | const m128 shadow1 = _mm_load_si128((__m128i*)s + 1); | ||
| 773 | // load high parts of 4 shadow slots into addr_vect: | ||
| 774 | // addr_vect[0:31] = shadow0[32:63] | ||
| 775 | // addr_vect[32:63] = shadow0[96:127] | ||
| 776 | // addr_vect[64:95] = shadow1[32:63] | ||
| 777 | // addr_vect[96:127] = shadow1[96:127] | ||
| 778 | m128 addr_vect = SHUF(shadow0, shadow1, 1, 3, 1, 3); | ||
| 779 | if (!is_write) { | ||
| 780 | // set IsRead bit in addr_vect | ||
| 781 | const m128 rw_mask1 = _mm_cvtsi64_si128(1<<15); | ||
| 782 | const m128 rw_mask = SHUF(rw_mask1, rw_mask1, 0, 0, 0, 0); | ||
| 783 | addr_vect = _mm_or_si128(addr_vect, rw_mask); | ||
| 784 | } | ||
| 785 | // addr0 == addr_vect? | ||
| 786 | const m128 addr_res = _mm_cmpeq_epi32(addr0, addr_vect); | ||
| 787 | // epoch1[0:63] = sync_epoch | ||
| 788 | const m128 epoch1 = _mm_cvtsi64_si128(sync_epoch); | ||
| 789 | // epoch[0:31] = sync_epoch[0:31] | ||
| 790 | // epoch[32:63] = sync_epoch[0:31] | ||
| 791 | // epoch[64:95] = sync_epoch[0:31] | ||
| 792 | // epoch[96:127] = sync_epoch[0:31] | ||
| 793 | const m128 epoch = SHUF(epoch1, epoch1, 0, 0, 0, 0); | ||
| 794 | // load low parts of shadow cell epochs into epoch_vect: | ||
| 795 | // epoch_vect[0:31] = shadow0[0:31] | ||
| 796 | // epoch_vect[32:63] = shadow0[64:95] | ||
| 797 | // epoch_vect[64:95] = shadow1[0:31] | ||
| 798 | // epoch_vect[96:127] = shadow1[64:95] | ||
| 799 | const m128 epoch_vect = SHUF(shadow0, shadow1, 0, 2, 0, 2); | ||
| 800 | // epoch_vect >= sync_epoch? | ||
| 801 | const m128 epoch_res = _mm_cmpgt_epi32(epoch_vect, epoch); | ||
| 802 | // addr_res & epoch_res | ||
| 803 | const m128 res = _mm_and_si128(addr_res, epoch_res); | ||
| 804 | // mask[0] = res[7] | ||
| 805 | // mask[1] = res[15] | ||
| 806 | // ... | ||
| 807 | // mask[15] = res[127] | ||
| 808 | const int mask = _mm_movemask_epi8(res); | ||
| 809 | return mask != 0; | ||
| 810 | } | ||
| 811 | #endif | ||
| 812 | |||
| 813 | ALWAYS_INLINE | ||
| 814 | bool ContainsSameAccess(u64 *s, u64 a, u64 sync_epoch, bool is_write) { | ||
| 815 | #if defined(__SSE3__) | ||
| 816 | bool res = ContainsSameAccessFast(s, a, sync_epoch, is_write); | ||
| 817 | // NOTE: this check can fail if the shadow is concurrently mutated | ||
| 818 | // by other threads. But it still can be useful if you modify | ||
| 819 | // ContainsSameAccessFast and want to ensure that it's not completely broken. | ||
| 820 | // DCHECK_EQ(res, ContainsSameAccessSlow(s, a, sync_epoch, is_write)); | ||
| 821 | return res; | ||
| 822 | #else | ||
| 823 | return ContainsSameAccessSlow(s, a, sync_epoch, is_write); | ||
| 824 | #endif | ||
| 825 | } | ||
| 826 | |||
| 827 | ALWAYS_INLINE USED | ||
| 828 | void MemoryAccess(ThreadState *thr, uptr pc, uptr addr, | ||
| 829 | int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic) { | ||
| 830 | u64 *shadow_mem = (u64*)MemToShadow(addr); | ||
| 831 | DPrintf2("#%d: MemoryAccess: @%p %p size=%d" | ||
| 832 | " is_write=%d shadow_mem=%p {%zx, %zx, %zx, %zx}\n", | ||
| 833 | (int)thr->fast_state.tid(), (void*)pc, (void*)addr, | ||
| 834 | (int)(1 << kAccessSizeLog), kAccessIsWrite, shadow_mem, | ||
| 835 | (uptr)shadow_mem[0], (uptr)shadow_mem[1], | ||
| 836 | (uptr)shadow_mem[2], (uptr)shadow_mem[3]); | ||
| 837 | #if SANITIZER_DEBUG | ||
| 838 | if (!IsAppMem(addr)) { | ||
| 839 | Printf("Access to non app mem %zx\n", addr); | ||
| 840 | DCHECK(IsAppMem(addr)); | ||
| 841 | } | ||
| 842 | if (!IsShadowMem((uptr)shadow_mem)) { | ||
| 843 | Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr); | ||
| 844 | DCHECK(IsShadowMem((uptr)shadow_mem)); | ||
| 845 | } | ||
| 846 | #endif | ||
| 847 | |||
| 848 | if (!SANITIZER_GO && !kAccessIsWrite && *shadow_mem == kShadowRodata) { | ||
| 849 | // Access to .rodata section, no races here. | ||
| 850 | // Measurements show that it can be 10-20% of all memory accesses. | ||
| 851 | StatInc(thr, StatMop); | ||
| 852 | StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead); | ||
| 853 | StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog)); | ||
| 854 | StatInc(thr, StatMopRodata); | ||
| 855 | return; | ||
| 856 | } | ||
| 857 | |||
| 858 | FastState fast_state = thr->fast_state; | ||
| 859 | if (UNLIKELY(fast_state.GetIgnoreBit())) { | ||
| 860 | StatInc(thr, StatMop); | ||
| 861 | StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead); | ||
| 862 | StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog)); | ||
| 863 | StatInc(thr, StatMopIgnored); | ||
| 864 | return; | ||
| 865 | } | ||
| 866 | |||
| 867 | Shadow cur(fast_state); | ||
| 868 | cur.SetAddr0AndSizeLog(addr & 7, kAccessSizeLog); | ||
| 869 | cur.SetWrite(kAccessIsWrite); | ||
| 870 | cur.SetAtomic(kIsAtomic); | ||
| 871 | |||
| 872 | if (LIKELY(ContainsSameAccess(shadow_mem, cur.raw(), | ||
| 873 | thr->fast_synch_epoch, kAccessIsWrite))) { | ||
| 874 | StatInc(thr, StatMop); | ||
| 875 | StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead); | ||
| 876 | StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog)); | ||
| 877 | StatInc(thr, StatMopSame); | ||
| 878 | return; | ||
| 879 | } | ||
| 880 | |||
| 881 | if (kCollectHistory) { | ||
| 882 | fast_state.IncrementEpoch(); | ||
| 883 | thr->fast_state = fast_state; | ||
| 884 | TraceAddEvent(thr, fast_state, EventTypeMop, pc); | ||
| 885 | cur.IncrementEpoch(); | ||
| 886 | } | ||
| 887 | |||
| 888 | MemoryAccessImpl1(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic, | ||
| 889 | shadow_mem, cur); | ||
| 890 | } | ||
| 891 | |||
| 892 | // Called by MemoryAccessRange in tsan_rtl_thread.cpp | ||
| 893 | ALWAYS_INLINE USED | ||
| 894 | void MemoryAccessImpl(ThreadState *thr, uptr addr, | ||
| 895 | int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic, | ||
| 896 | u64 *shadow_mem, Shadow cur) { | ||
| 897 | if (LIKELY(ContainsSameAccess(shadow_mem, cur.raw(), | ||
| 898 | thr->fast_synch_epoch, kAccessIsWrite))) { | ||
| 899 | StatInc(thr, StatMop); | ||
| 900 | StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead); | ||
| 901 | StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog)); | ||
| 902 | StatInc(thr, StatMopSame); | ||
| 903 | return; | ||
| 904 | } | ||
| 905 | |||
| 906 | MemoryAccessImpl1(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic, | ||
| 907 | shadow_mem, cur); | ||
| 908 | } | ||
| 909 | |||
| 910 | static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size, | ||
| 911 | u64 val) { | ||
| 912 | (void)thr; | ||
| 913 | (void)pc; | ||
| 914 | if (size == 0) | ||
| 915 | return; | ||
| 916 | // FIXME: fix me. | ||
| 917 | uptr offset = addr % kShadowCell; | ||
| 918 | if (offset) { | ||
| 919 | offset = kShadowCell - offset; | ||
| 920 | if (size <= offset) | ||
| 921 | return; | ||
| 922 | addr += offset; | ||
| 923 | size -= offset; | ||
| 924 | } | ||
| 925 | DCHECK_EQ(addr % 8, 0); | ||
| 926 | // If a user passes some insane arguments (memset(0)), | ||
| 927 | // let it just crash as usual. | ||
| 928 | if (!IsAppMem(addr) || !IsAppMem(addr + size - 1)) | ||
| 929 | return; | ||
| 930 | // Don't want to touch lots of shadow memory. | ||
| 931 | // If a program maps 10MB stack, there is no need reset the whole range. | ||
| 932 | size = (size + (kShadowCell - 1)) & ~(kShadowCell - 1); | ||
| 933 | // UnmapOrDie/MmapFixedNoReserve does not work on Windows. | ||
| 934 | if (SANITIZER_WINDOWS || size < common_flags()->clear_shadow_mmap_threshold) { | ||
| 935 | u64 *p = (u64*)MemToShadow(addr); | ||
| 936 | CHECK(IsShadowMem((uptr)p)); | ||
| 937 | CHECK(IsShadowMem((uptr)(p + size * kShadowCnt / kShadowCell - 1))); | ||
| 938 | // FIXME: may overwrite a part outside the region | ||
| 939 | for (uptr i = 0; i < size / kShadowCell * kShadowCnt;) { | ||
| 940 | p[i++] = val; | ||
| 941 | for (uptr j = 1; j < kShadowCnt; j++) | ||
| 942 | p[i++] = 0; | ||
| 943 | } | ||
| 944 | } else { | ||
| 945 | // The region is big, reset only beginning and end. | ||
| 946 | const uptr kPageSize = GetPageSizeCached(); | ||
| 947 | u64 *begin = (u64*)MemToShadow(addr); | ||
| 948 | u64 *end = begin + size / kShadowCell * kShadowCnt; | ||
| 949 | u64 *p = begin; | ||
| 950 | // Set at least first kPageSize/2 to page boundary. | ||
| 951 | while ((p < begin + kPageSize / kShadowSize / 2) || ((uptr)p % kPageSize)) { | ||
| 952 | *p++ = val; | ||
| 953 | for (uptr j = 1; j < kShadowCnt; j++) | ||
| 954 | *p++ = 0; | ||
| 955 | } | ||
| 956 | // Reset middle part. | ||
| 957 | u64 *p1 = p; | ||
| 958 | p = RoundDown(end, kPageSize); | ||
| 959 | UnmapOrDie((void*)p1, (uptr)p - (uptr)p1); | ||
| 960 | if (!MmapFixedNoReserve((uptr)p1, (uptr)p - (uptr)p1)) | ||
| 961 | Die(); | ||
| 962 | // Set the ending. | ||
| 963 | while (p < end) { | ||
| 964 | *p++ = val; | ||
| 965 | for (uptr j = 1; j < kShadowCnt; j++) | ||
| 966 | *p++ = 0; | ||
| 967 | } | ||
| 968 | } | ||
| 969 | } | ||
| 970 | |||
| 971 | void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size) { | ||
| 972 | MemoryRangeSet(thr, pc, addr, size, 0); | ||
| 973 | } | ||
| 974 | |||
| 975 | void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size) { | ||
| 976 | // Processing more than 1k (4k of shadow) is expensive, | ||
| 977 | // can cause excessive memory consumption (user does not necessary touch | ||
| 978 | // the whole range) and most likely unnecessary. | ||
| 979 | if (size > 1024) | ||
| 980 | size = 1024; | ||
| 981 | CHECK_EQ(thr->is_freeing, false); | ||
| 982 | thr->is_freeing = true; | ||
| 983 | MemoryAccessRange(thr, pc, addr, size, true); | ||
| 984 | thr->is_freeing = false; | ||
| 985 | if (kCollectHistory) { | ||
| 986 | thr->fast_state.IncrementEpoch(); | ||
| 987 | TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc); | ||
| 988 | } | ||
| 989 | Shadow s(thr->fast_state); | ||
| 990 | s.ClearIgnoreBit(); | ||
| 991 | s.MarkAsFreed(); | ||
| 992 | s.SetWrite(true); | ||
| 993 | s.SetAddr0AndSizeLog(0, 3); | ||
| 994 | MemoryRangeSet(thr, pc, addr, size, s.raw()); | ||
| 995 | } | ||
| 996 | |||
| 997 | void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size) { | ||
| 998 | if (kCollectHistory) { | ||
| 999 | thr->fast_state.IncrementEpoch(); | ||
| 1000 | TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc); | ||
| 1001 | } | ||
| 1002 | Shadow s(thr->fast_state); | ||
| 1003 | s.ClearIgnoreBit(); | ||
| 1004 | s.SetWrite(true); | ||
| 1005 | s.SetAddr0AndSizeLog(0, 3); | ||
| 1006 | MemoryRangeSet(thr, pc, addr, size, s.raw()); | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | void MemoryRangeImitateWriteOrResetRange(ThreadState *thr, uptr pc, uptr addr, | ||
| 1010 | uptr size) { | ||
| 1011 | if (thr->ignore_reads_and_writes == 0) | ||
| 1012 | MemoryRangeImitateWrite(thr, pc, addr, size); | ||
| 1013 | else | ||
| 1014 | MemoryResetRange(thr, pc, addr, size); | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | ALWAYS_INLINE USED | ||
| 1018 | void FuncEntry(ThreadState *thr, uptr pc) { | ||
| 1019 | StatInc(thr, StatFuncEnter); | ||
| 1020 | DPrintf2("#%d: FuncEntry %p\n", (int)thr->fast_state.tid(), (void*)pc); | ||
| 1021 | if (kCollectHistory) { | ||
| 1022 | thr->fast_state.IncrementEpoch(); | ||
| 1023 | TraceAddEvent(thr, thr->fast_state, EventTypeFuncEnter, pc); | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | // Shadow stack maintenance can be replaced with | ||
| 1027 | // stack unwinding during trace switch (which presumably must be faster). | ||
| 1028 | DCHECK_GE(thr->shadow_stack_pos, thr->shadow_stack); | ||
| 1029 | #if !SANITIZER_GO | ||
| 1030 | DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end); | ||
| 1031 | #else | ||
| 1032 | if (thr->shadow_stack_pos == thr->shadow_stack_end) | ||
| 1033 | GrowShadowStack(thr); | ||
| 1034 | #endif | ||
| 1035 | thr->shadow_stack_pos[0] = pc; | ||
| 1036 | thr->shadow_stack_pos++; | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | ALWAYS_INLINE USED | ||
| 1040 | void FuncExit(ThreadState *thr) { | ||
| 1041 | StatInc(thr, StatFuncExit); | ||
| 1042 | DPrintf2("#%d: FuncExit\n", (int)thr->fast_state.tid()); | ||
| 1043 | if (kCollectHistory) { | ||
| 1044 | thr->fast_state.IncrementEpoch(); | ||
| 1045 | TraceAddEvent(thr, thr->fast_state, EventTypeFuncExit, 0); | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | DCHECK_GT(thr->shadow_stack_pos, thr->shadow_stack); | ||
| 1049 | #if !SANITIZER_GO | ||
| 1050 | DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end); | ||
| 1051 | #endif | ||
| 1052 | thr->shadow_stack_pos--; | ||
| 1053 | } | ||
| 1054 | |||
| 1055 | void ThreadIgnoreBegin(ThreadState *thr, uptr pc, bool save_stack) { | ||
| 1056 | DPrintf("#%d: ThreadIgnoreBegin\n", thr->tid); | ||
| 1057 | thr->ignore_reads_and_writes++; | ||
| 1058 | CHECK_GT(thr->ignore_reads_and_writes, 0); | ||
| 1059 | thr->fast_state.SetIgnoreBit(); | ||
| 1060 | #if !SANITIZER_GO | ||
| 1061 | if (save_stack && !ctx->after_multithreaded_fork) | ||
| 1062 | thr->mop_ignore_set.Add(CurrentStackId(thr, pc)); | ||
| 1063 | #endif | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | void ThreadIgnoreEnd(ThreadState *thr, uptr pc) { | ||
| 1067 | DPrintf("#%d: ThreadIgnoreEnd\n", thr->tid); | ||
| 1068 | CHECK_GT(thr->ignore_reads_and_writes, 0); | ||
| 1069 | thr->ignore_reads_and_writes--; | ||
| 1070 | if (thr->ignore_reads_and_writes == 0) { | ||
| 1071 | thr->fast_state.ClearIgnoreBit(); | ||
| 1072 | #if !SANITIZER_GO | ||
| 1073 | thr->mop_ignore_set.Reset(); | ||
| 1074 | #endif | ||
| 1075 | } | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | #if !SANITIZER_GO | ||
| 1079 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE | ||
| 1080 | uptr __tsan_testonly_shadow_stack_current_size() { | ||
| 1081 | ThreadState *thr = cur_thread(); | ||
| 1082 | return thr->shadow_stack_pos - thr->shadow_stack; | ||
| 1083 | } | ||
| 1084 | #endif | ||
| 1085 | |||
| 1086 | void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc, bool save_stack) { | ||
| 1087 | DPrintf("#%d: ThreadIgnoreSyncBegin\n", thr->tid); | ||
| 1088 | thr->ignore_sync++; | ||
| 1089 | CHECK_GT(thr->ignore_sync, 0); | ||
| 1090 | #if !SANITIZER_GO | ||
| 1091 | if (save_stack && !ctx->after_multithreaded_fork) | ||
| 1092 | thr->sync_ignore_set.Add(CurrentStackId(thr, pc)); | ||
| 1093 | #endif | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc) { | ||
| 1097 | DPrintf("#%d: ThreadIgnoreSyncEnd\n", thr->tid); | ||
| 1098 | CHECK_GT(thr->ignore_sync, 0); | ||
| 1099 | thr->ignore_sync--; | ||
| 1100 | #if !SANITIZER_GO | ||
| 1101 | if (thr->ignore_sync == 0) | ||
| 1102 | thr->sync_ignore_set.Reset(); | ||
| 1103 | #endif | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | bool MD5Hash::operator==(const MD5Hash &other) const { | ||
| 1107 | return hash[0] == other.hash[0] && hash[1] == other.hash[1]; | ||
| 1108 | } | ||
| 1109 | |||
| 1110 | #if SANITIZER_DEBUG | ||
| 1111 | void build_consistency_debug() {} | ||
| 1112 | #else | ||
| 1113 | void build_consistency_release() {} | ||
| 1114 | #endif | ||
| 1115 | |||
| 1116 | #if TSAN_COLLECT_STATS | ||
| 1117 | void build_consistency_stats() {} | ||
| 1118 | #else | ||
| 1119 | void build_consistency_nostats() {} | ||
| 1120 | #endif | ||
| 1121 | |||
| 1122 | } // namespace __tsan | ||
| 1123 | |||
| 1124 | #if !SANITIZER_GO | ||
| 1125 | // Must be included in this file to make sure everything is inlined. | ||
| 1126 | #include "tsan_interface_inl.h" | ||
| 1127 | #endif | ||
lib/tsan/tsan_rtl.h created+893| ... | @@ -0,0 +1,893 @@ | ||
| 1 | //===-- tsan_rtl.h ----------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | // Main internal TSan header file. | ||
| 12 | // | ||
| 13 | // Ground rules: | ||
| 14 | // - C++ run-time should not be used (static CTORs, RTTI, exceptions, static | ||
| 15 | // function-scope locals) | ||
| 16 | // - All functions/classes/etc reside in namespace __tsan, except for those | ||
| 17 | // declared in tsan_interface.h. | ||
| 18 | // - Platform-specific files should be used instead of ifdefs (*). | ||
| 19 | // - No system headers included in header files (*). | ||
| 20 | // - Platform specific headres included only into platform-specific files (*). | ||
| 21 | // | ||
| 22 | // (*) Except when inlining is critical for performance. | ||
| 23 | //===----------------------------------------------------------------------===// | ||
| 24 | |||
| 25 | #ifndef TSAN_RTL_H | ||
| 26 | #define TSAN_RTL_H | ||
| 27 | |||
| 28 | #include "sanitizer_common/sanitizer_allocator.h" | ||
| 29 | #include "sanitizer_common/sanitizer_allocator_internal.h" | ||
| 30 | #include "sanitizer_common/sanitizer_asm.h" | ||
| 31 | #include "sanitizer_common/sanitizer_common.h" | ||
| 32 | #include "sanitizer_common/sanitizer_deadlock_detector_interface.h" | ||
| 33 | #include "sanitizer_common/sanitizer_libignore.h" | ||
| 34 | #include "sanitizer_common/sanitizer_suppressions.h" | ||
| 35 | #include "sanitizer_common/sanitizer_thread_registry.h" | ||
| 36 | #include "sanitizer_common/sanitizer_vector.h" | ||
| 37 | #include "tsan_clock.h" | ||
| 38 | #include "tsan_defs.h" | ||
| 39 | #include "tsan_flags.h" | ||
| 40 | #include "tsan_mman.h" | ||
| 41 | #include "tsan_sync.h" | ||
| 42 | #include "tsan_trace.h" | ||
| 43 | #include "tsan_report.h" | ||
| 44 | #include "tsan_platform.h" | ||
| 45 | #include "tsan_mutexset.h" | ||
| 46 | #include "tsan_ignoreset.h" | ||
| 47 | #include "tsan_stack_trace.h" | ||
| 48 | |||
| 49 | #if SANITIZER_WORDSIZE != 64 | ||
| 50 | # error "ThreadSanitizer is supported only on 64-bit platforms" | ||
| 51 | #endif | ||
| 52 | |||
| 53 | namespace __tsan { | ||
| 54 | |||
| 55 | #if !SANITIZER_GO | ||
| 56 | struct MapUnmapCallback; | ||
| 57 | #if defined(__mips64) || defined(__aarch64__) || defined(__powerpc__) | ||
| 58 | |||
| 59 | struct AP32 { | ||
| 60 | static const uptr kSpaceBeg = 0; | ||
| 61 | static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; | ||
| 62 | static const uptr kMetadataSize = 0; | ||
| 63 | typedef __sanitizer::CompactSizeClassMap SizeClassMap; | ||
| 64 | static const uptr kRegionSizeLog = 20; | ||
| 65 | using AddressSpaceView = LocalAddressSpaceView; | ||
| 66 | typedef __tsan::MapUnmapCallback MapUnmapCallback; | ||
| 67 | static const uptr kFlags = 0; | ||
| 68 | }; | ||
| 69 | typedef SizeClassAllocator32<AP32> PrimaryAllocator; | ||
| 70 | #else | ||
| 71 | struct AP64 { // Allocator64 parameters. Deliberately using a short name. | ||
| 72 | static const uptr kSpaceBeg = Mapping::kHeapMemBeg; | ||
| 73 | static const uptr kSpaceSize = Mapping::kHeapMemEnd - Mapping::kHeapMemBeg; | ||
| 74 | static const uptr kMetadataSize = 0; | ||
| 75 | typedef DefaultSizeClassMap SizeClassMap; | ||
| 76 | typedef __tsan::MapUnmapCallback MapUnmapCallback; | ||
| 77 | static const uptr kFlags = 0; | ||
| 78 | using AddressSpaceView = LocalAddressSpaceView; | ||
| 79 | }; | ||
| 80 | typedef SizeClassAllocator64<AP64> PrimaryAllocator; | ||
| 81 | #endif | ||
| 82 | typedef CombinedAllocator<PrimaryAllocator> Allocator; | ||
| 83 | typedef Allocator::AllocatorCache AllocatorCache; | ||
| 84 | Allocator *allocator(); | ||
| 85 | #endif | ||
| 86 | |||
| 87 | void TsanCheckFailed(const char *file, int line, const char *cond, | ||
| 88 | u64 v1, u64 v2); | ||
| 89 | |||
| 90 | const u64 kShadowRodata = (u64)-1; // .rodata shadow marker | ||
| 91 | |||
| 92 | // FastState (from most significant bit): | ||
| 93 | // ignore : 1 | ||
| 94 | // tid : kTidBits | ||
| 95 | // unused : - | ||
| 96 | // history_size : 3 | ||
| 97 | // epoch : kClkBits | ||
| 98 | class FastState { | ||
| 99 | public: | ||
| 100 | FastState(u64 tid, u64 epoch) { | ||
| 101 | x_ = tid << kTidShift; | ||
| 102 | x_ |= epoch; | ||
| 103 | DCHECK_EQ(tid, this->tid()); | ||
| 104 | DCHECK_EQ(epoch, this->epoch()); | ||
| 105 | DCHECK_EQ(GetIgnoreBit(), false); | ||
| 106 | } | ||
| 107 | |||
| 108 | explicit FastState(u64 x) | ||
| 109 | : x_(x) { | ||
| 110 | } | ||
| 111 | |||
| 112 | u64 raw() const { | ||
| 113 | return x_; | ||
| 114 | } | ||
| 115 | |||
| 116 | u64 tid() const { | ||
| 117 | u64 res = (x_ & ~kIgnoreBit) >> kTidShift; | ||
| 118 | return res; | ||
| 119 | } | ||
| 120 | |||
| 121 | u64 TidWithIgnore() const { | ||
| 122 | u64 res = x_ >> kTidShift; | ||
| 123 | return res; | ||
| 124 | } | ||
| 125 | |||
| 126 | u64 epoch() const { | ||
| 127 | u64 res = x_ & ((1ull << kClkBits) - 1); | ||
| 128 | return res; | ||
| 129 | } | ||
| 130 | |||
| 131 | void IncrementEpoch() { | ||
| 132 | u64 old_epoch = epoch(); | ||
| 133 | x_ += 1; | ||
| 134 | DCHECK_EQ(old_epoch + 1, epoch()); | ||
| 135 | (void)old_epoch; | ||
| 136 | } | ||
| 137 | |||
| 138 | void SetIgnoreBit() { x_ |= kIgnoreBit; } | ||
| 139 | void ClearIgnoreBit() { x_ &= ~kIgnoreBit; } | ||
| 140 | bool GetIgnoreBit() const { return (s64)x_ < 0; } | ||
| 141 | |||
| 142 | void SetHistorySize(int hs) { | ||
| 143 | CHECK_GE(hs, 0); | ||
| 144 | CHECK_LE(hs, 7); | ||
| 145 | x_ = (x_ & ~(kHistoryMask << kHistoryShift)) | (u64(hs) << kHistoryShift); | ||
| 146 | } | ||
| 147 | |||
| 148 | ALWAYS_INLINE | ||
| 149 | int GetHistorySize() const { | ||
| 150 | return (int)((x_ >> kHistoryShift) & kHistoryMask); | ||
| 151 | } | ||
| 152 | |||
| 153 | void ClearHistorySize() { | ||
| 154 | SetHistorySize(0); | ||
| 155 | } | ||
| 156 | |||
| 157 | ALWAYS_INLINE | ||
| 158 | u64 GetTracePos() const { | ||
| 159 | const int hs = GetHistorySize(); | ||
| 160 | // When hs == 0, the trace consists of 2 parts. | ||
| 161 | const u64 mask = (1ull << (kTracePartSizeBits + hs + 1)) - 1; | ||
| 162 | return epoch() & mask; | ||
| 163 | } | ||
| 164 | |||
| 165 | private: | ||
| 166 | friend class Shadow; | ||
| 167 | static const int kTidShift = 64 - kTidBits - 1; | ||
| 168 | static const u64 kIgnoreBit = 1ull << 63; | ||
| 169 | static const u64 kFreedBit = 1ull << 63; | ||
| 170 | static const u64 kHistoryShift = kClkBits; | ||
| 171 | static const u64 kHistoryMask = 7; | ||
| 172 | u64 x_; | ||
| 173 | }; | ||
| 174 | |||
| 175 | // Shadow (from most significant bit): | ||
| 176 | // freed : 1 | ||
| 177 | // tid : kTidBits | ||
| 178 | // is_atomic : 1 | ||
| 179 | // is_read : 1 | ||
| 180 | // size_log : 2 | ||
| 181 | // addr0 : 3 | ||
| 182 | // epoch : kClkBits | ||
| 183 | class Shadow : public FastState { | ||
| 184 | public: | ||
| 185 | explicit Shadow(u64 x) | ||
| 186 | : FastState(x) { | ||
| 187 | } | ||
| 188 | |||
| 189 | explicit Shadow(const FastState &s) | ||
| 190 | : FastState(s.x_) { | ||
| 191 | ClearHistorySize(); | ||
| 192 | } | ||
| 193 | |||
| 194 | void SetAddr0AndSizeLog(u64 addr0, unsigned kAccessSizeLog) { | ||
| 195 | DCHECK_EQ((x_ >> kClkBits) & 31, 0); | ||
| 196 | DCHECK_LE(addr0, 7); | ||
| 197 | DCHECK_LE(kAccessSizeLog, 3); | ||
| 198 | x_ |= ((kAccessSizeLog << 3) | addr0) << kClkBits; | ||
| 199 | DCHECK_EQ(kAccessSizeLog, size_log()); | ||
| 200 | DCHECK_EQ(addr0, this->addr0()); | ||
| 201 | } | ||
| 202 | |||
| 203 | void SetWrite(unsigned kAccessIsWrite) { | ||
| 204 | DCHECK_EQ(x_ & kReadBit, 0); | ||
| 205 | if (!kAccessIsWrite) | ||
| 206 | x_ |= kReadBit; | ||
| 207 | DCHECK_EQ(kAccessIsWrite, IsWrite()); | ||
| 208 | } | ||
| 209 | |||
| 210 | void SetAtomic(bool kIsAtomic) { | ||
| 211 | DCHECK(!IsAtomic()); | ||
| 212 | if (kIsAtomic) | ||
| 213 | x_ |= kAtomicBit; | ||
| 214 | DCHECK_EQ(IsAtomic(), kIsAtomic); | ||
| 215 | } | ||
| 216 | |||
| 217 | bool IsAtomic() const { | ||
| 218 | return x_ & kAtomicBit; | ||
| 219 | } | ||
| 220 | |||
| 221 | bool IsZero() const { | ||
| 222 | return x_ == 0; | ||
| 223 | } | ||
| 224 | |||
| 225 | static inline bool TidsAreEqual(const Shadow s1, const Shadow s2) { | ||
| 226 | u64 shifted_xor = (s1.x_ ^ s2.x_) >> kTidShift; | ||
| 227 | DCHECK_EQ(shifted_xor == 0, s1.TidWithIgnore() == s2.TidWithIgnore()); | ||
| 228 | return shifted_xor == 0; | ||
| 229 | } | ||
| 230 | |||
| 231 | static ALWAYS_INLINE | ||
| 232 | bool Addr0AndSizeAreEqual(const Shadow s1, const Shadow s2) { | ||
| 233 | u64 masked_xor = ((s1.x_ ^ s2.x_) >> kClkBits) & 31; | ||
| 234 | return masked_xor == 0; | ||
| 235 | } | ||
| 236 | |||
| 237 | static ALWAYS_INLINE bool TwoRangesIntersect(Shadow s1, Shadow s2, | ||
| 238 | unsigned kS2AccessSize) { | ||
| 239 | bool res = false; | ||
| 240 | u64 diff = s1.addr0() - s2.addr0(); | ||
| 241 | if ((s64)diff < 0) { // s1.addr0 < s2.addr0 | ||
| 242 | // if (s1.addr0() + size1) > s2.addr0()) return true; | ||
| 243 | if (s1.size() > -diff) | ||
| 244 | res = true; | ||
| 245 | } else { | ||
| 246 | // if (s2.addr0() + kS2AccessSize > s1.addr0()) return true; | ||
| 247 | if (kS2AccessSize > diff) | ||
| 248 | res = true; | ||
| 249 | } | ||
| 250 | DCHECK_EQ(res, TwoRangesIntersectSlow(s1, s2)); | ||
| 251 | DCHECK_EQ(res, TwoRangesIntersectSlow(s2, s1)); | ||
| 252 | return res; | ||
| 253 | } | ||
| 254 | |||
| 255 | u64 ALWAYS_INLINE addr0() const { return (x_ >> kClkBits) & 7; } | ||
| 256 | u64 ALWAYS_INLINE size() const { return 1ull << size_log(); } | ||
| 257 | bool ALWAYS_INLINE IsWrite() const { return !IsRead(); } | ||
| 258 | bool ALWAYS_INLINE IsRead() const { return x_ & kReadBit; } | ||
| 259 | |||
| 260 | // The idea behind the freed bit is as follows. | ||
| 261 | // When the memory is freed (or otherwise unaccessible) we write to the shadow | ||
| 262 | // values with tid/epoch related to the free and the freed bit set. | ||
| 263 | // During memory accesses processing the freed bit is considered | ||
| 264 | // as msb of tid. So any access races with shadow with freed bit set | ||
| 265 | // (it is as if write from a thread with which we never synchronized before). | ||
| 266 | // This allows us to detect accesses to freed memory w/o additional | ||
| 267 | // overheads in memory access processing and at the same time restore | ||
| 268 | // tid/epoch of free. | ||
| 269 | void MarkAsFreed() { | ||
| 270 | x_ |= kFreedBit; | ||
| 271 | } | ||
| 272 | |||
| 273 | bool IsFreed() const { | ||
| 274 | return x_ & kFreedBit; | ||
| 275 | } | ||
| 276 | |||
| 277 | bool GetFreedAndReset() { | ||
| 278 | bool res = x_ & kFreedBit; | ||
| 279 | x_ &= ~kFreedBit; | ||
| 280 | return res; | ||
| 281 | } | ||
| 282 | |||
| 283 | bool ALWAYS_INLINE IsBothReadsOrAtomic(bool kIsWrite, bool kIsAtomic) const { | ||
| 284 | bool v = x_ & ((u64(kIsWrite ^ 1) << kReadShift) | ||
| 285 | | (u64(kIsAtomic) << kAtomicShift)); | ||
| 286 | DCHECK_EQ(v, (!IsWrite() && !kIsWrite) || (IsAtomic() && kIsAtomic)); | ||
| 287 | return v; | ||
| 288 | } | ||
| 289 | |||
| 290 | bool ALWAYS_INLINE IsRWNotWeaker(bool kIsWrite, bool kIsAtomic) const { | ||
| 291 | bool v = ((x_ >> kReadShift) & 3) | ||
| 292 | <= u64((kIsWrite ^ 1) | (kIsAtomic << 1)); | ||
| 293 | DCHECK_EQ(v, (IsAtomic() < kIsAtomic) || | ||
| 294 | (IsAtomic() == kIsAtomic && !IsWrite() <= !kIsWrite)); | ||
| 295 | return v; | ||
| 296 | } | ||
| 297 | |||
| 298 | bool ALWAYS_INLINE IsRWWeakerOrEqual(bool kIsWrite, bool kIsAtomic) const { | ||
| 299 | bool v = ((x_ >> kReadShift) & 3) | ||
| 300 | >= u64((kIsWrite ^ 1) | (kIsAtomic << 1)); | ||
| 301 | DCHECK_EQ(v, (IsAtomic() > kIsAtomic) || | ||
| 302 | (IsAtomic() == kIsAtomic && !IsWrite() >= !kIsWrite)); | ||
| 303 | return v; | ||
| 304 | } | ||
| 305 | |||
| 306 | private: | ||
| 307 | static const u64 kReadShift = 5 + kClkBits; | ||
| 308 | static const u64 kReadBit = 1ull << kReadShift; | ||
| 309 | static const u64 kAtomicShift = 6 + kClkBits; | ||
| 310 | static const u64 kAtomicBit = 1ull << kAtomicShift; | ||
| 311 | |||
| 312 | u64 size_log() const { return (x_ >> (3 + kClkBits)) & 3; } | ||
| 313 | |||
| 314 | static bool TwoRangesIntersectSlow(const Shadow s1, const Shadow s2) { | ||
| 315 | if (s1.addr0() == s2.addr0()) return true; | ||
| 316 | if (s1.addr0() < s2.addr0() && s1.addr0() + s1.size() > s2.addr0()) | ||
| 317 | return true; | ||
| 318 | if (s2.addr0() < s1.addr0() && s2.addr0() + s2.size() > s1.addr0()) | ||
| 319 | return true; | ||
| 320 | return false; | ||
| 321 | } | ||
| 322 | }; | ||
| 323 | |||
| 324 | struct ThreadSignalContext; | ||
| 325 | |||
| 326 | struct JmpBuf { | ||
| 327 | uptr sp; | ||
| 328 | int int_signal_send; | ||
| 329 | bool in_blocking_func; | ||
| 330 | uptr in_signal_handler; | ||
| 331 | uptr *shadow_stack_pos; | ||
| 332 | }; | ||
| 333 | |||
| 334 | // A Processor represents a physical thread, or a P for Go. | ||
| 335 | // It is used to store internal resources like allocate cache, and does not | ||
| 336 | // participate in race-detection logic (invisible to end user). | ||
| 337 | // In C++ it is tied to an OS thread just like ThreadState, however ideally | ||
| 338 | // it should be tied to a CPU (this way we will have fewer allocator caches). | ||
| 339 | // In Go it is tied to a P, so there are significantly fewer Processor's than | ||
| 340 | // ThreadState's (which are tied to Gs). | ||
| 341 | // A ThreadState must be wired with a Processor to handle events. | ||
| 342 | struct Processor { | ||
| 343 | ThreadState *thr; // currently wired thread, or nullptr | ||
| 344 | #if !SANITIZER_GO | ||
| 345 | AllocatorCache alloc_cache; | ||
| 346 | InternalAllocatorCache internal_alloc_cache; | ||
| 347 | #endif | ||
| 348 | DenseSlabAllocCache block_cache; | ||
| 349 | DenseSlabAllocCache sync_cache; | ||
| 350 | DenseSlabAllocCache clock_cache; | ||
| 351 | DDPhysicalThread *dd_pt; | ||
| 352 | }; | ||
| 353 | |||
| 354 | #if !SANITIZER_GO | ||
| 355 | // ScopedGlobalProcessor temporary setups a global processor for the current | ||
| 356 | // thread, if it does not have one. Intended for interceptors that can run | ||
| 357 | // at the very thread end, when we already destroyed the thread processor. | ||
| 358 | struct ScopedGlobalProcessor { | ||
| 359 | ScopedGlobalProcessor(); | ||
| 360 | ~ScopedGlobalProcessor(); | ||
| 361 | }; | ||
| 362 | #endif | ||
| 363 | |||
| 364 | // This struct is stored in TLS. | ||
| 365 | struct ThreadState { | ||
| 366 | FastState fast_state; | ||
| 367 | // Synch epoch represents the threads's epoch before the last synchronization | ||
| 368 | // action. It allows to reduce number of shadow state updates. | ||
| 369 | // For example, fast_synch_epoch=100, last write to addr X was at epoch=150, | ||
| 370 | // if we are processing write to X from the same thread at epoch=200, | ||
| 371 | // we do nothing, because both writes happen in the same 'synch epoch'. | ||
| 372 | // That is, if another memory access does not race with the former write, | ||
| 373 | // it does not race with the latter as well. | ||
| 374 | // QUESTION: can we can squeeze this into ThreadState::Fast? | ||
| 375 | // E.g. ThreadState::Fast is a 44-bit, 32 are taken by synch_epoch and 12 are | ||
| 376 | // taken by epoch between synchs. | ||
| 377 | // This way we can save one load from tls. | ||
| 378 | u64 fast_synch_epoch; | ||
| 379 | // Technically `current` should be a separate THREADLOCAL variable; | ||
| 380 | // but it is placed here in order to share cache line with previous fields. | ||
| 381 | ThreadState* current; | ||
| 382 | // This is a slow path flag. On fast path, fast_state.GetIgnoreBit() is read. | ||
| 383 | // We do not distinguish beteween ignoring reads and writes | ||
| 384 | // for better performance. | ||
| 385 | int ignore_reads_and_writes; | ||
| 386 | int ignore_sync; | ||
| 387 | int suppress_reports; | ||
| 388 | // Go does not support ignores. | ||
| 389 | #if !SANITIZER_GO | ||
| 390 | IgnoreSet mop_ignore_set; | ||
| 391 | IgnoreSet sync_ignore_set; | ||
| 392 | #endif | ||
| 393 | // C/C++ uses fixed size shadow stack embed into Trace. | ||
| 394 | // Go uses malloc-allocated shadow stack with dynamic size. | ||
| 395 | uptr *shadow_stack; | ||
| 396 | uptr *shadow_stack_end; | ||
| 397 | uptr *shadow_stack_pos; | ||
| 398 | u64 *racy_shadow_addr; | ||
| 399 | u64 racy_state[2]; | ||
| 400 | MutexSet mset; | ||
| 401 | ThreadClock clock; | ||
| 402 | #if !SANITIZER_GO | ||
| 403 | Vector<JmpBuf> jmp_bufs; | ||
| 404 | int ignore_interceptors; | ||
| 405 | #endif | ||
| 406 | #if TSAN_COLLECT_STATS | ||
| 407 | u64 stat[StatCnt]; | ||
| 408 | #endif | ||
| 409 | const int tid; | ||
| 410 | const int unique_id; | ||
| 411 | bool in_symbolizer; | ||
| 412 | bool in_ignored_lib; | ||
| 413 | bool is_inited; | ||
| 414 | bool is_dead; | ||
| 415 | bool is_freeing; | ||
| 416 | bool is_vptr_access; | ||
| 417 | const uptr stk_addr; | ||
| 418 | const uptr stk_size; | ||
| 419 | const uptr tls_addr; | ||
| 420 | const uptr tls_size; | ||
| 421 | ThreadContext *tctx; | ||
| 422 | |||
| 423 | #if SANITIZER_DEBUG && !SANITIZER_GO | ||
| 424 | InternalDeadlockDetector internal_deadlock_detector; | ||
| 425 | #endif | ||
| 426 | DDLogicalThread *dd_lt; | ||
| 427 | |||
| 428 | // Current wired Processor, or nullptr. Required to handle any events. | ||
| 429 | Processor *proc1; | ||
| 430 | #if !SANITIZER_GO | ||
| 431 | Processor *proc() { return proc1; } | ||
| 432 | #else | ||
| 433 | Processor *proc(); | ||
| 434 | #endif | ||
| 435 | |||
| 436 | atomic_uintptr_t in_signal_handler; | ||
| 437 | ThreadSignalContext *signal_ctx; | ||
| 438 | |||
| 439 | #if !SANITIZER_GO | ||
| 440 | u32 last_sleep_stack_id; | ||
| 441 | ThreadClock last_sleep_clock; | ||
| 442 | #endif | ||
| 443 | |||
| 444 | // Set in regions of runtime that must be signal-safe and fork-safe. | ||
| 445 | // If set, malloc must not be called. | ||
| 446 | int nomalloc; | ||
| 447 | |||
| 448 | const ReportDesc *current_report; | ||
| 449 | |||
| 450 | explicit ThreadState(Context *ctx, int tid, int unique_id, u64 epoch, | ||
| 451 | unsigned reuse_count, | ||
| 452 | uptr stk_addr, uptr stk_size, | ||
| 453 | uptr tls_addr, uptr tls_size); | ||
| 454 | }; | ||
| 455 | |||
| 456 | #if !SANITIZER_GO | ||
| 457 | #if SANITIZER_MAC || SANITIZER_ANDROID | ||
| 458 | ThreadState *cur_thread(); | ||
| 459 | void set_cur_thread(ThreadState *thr); | ||
| 460 | void cur_thread_finalize(); | ||
| 461 | INLINE void cur_thread_init() { } | ||
| 462 | #else | ||
| 463 | __attribute__((tls_model("initial-exec"))) | ||
| 464 | extern THREADLOCAL char cur_thread_placeholder[]; | ||
| 465 | INLINE ThreadState *cur_thread() { | ||
| 466 | return reinterpret_cast<ThreadState *>(cur_thread_placeholder)->current; | ||
| 467 | } | ||
| 468 | INLINE void cur_thread_init() { | ||
| 469 | ThreadState *thr = reinterpret_cast<ThreadState *>(cur_thread_placeholder); | ||
| 470 | if (UNLIKELY(!thr->current)) | ||
| 471 | thr->current = thr; | ||
| 472 | } | ||
| 473 | INLINE void set_cur_thread(ThreadState *thr) { | ||
| 474 | reinterpret_cast<ThreadState *>(cur_thread_placeholder)->current = thr; | ||
| 475 | } | ||
| 476 | INLINE void cur_thread_finalize() { } | ||
| 477 | #endif // SANITIZER_MAC || SANITIZER_ANDROID | ||
| 478 | #endif // SANITIZER_GO | ||
| 479 | |||
| 480 | class ThreadContext : public ThreadContextBase { | ||
| 481 | public: | ||
| 482 | explicit ThreadContext(int tid); | ||
| 483 | ~ThreadContext(); | ||
| 484 | ThreadState *thr; | ||
| 485 | u32 creation_stack_id; | ||
| 486 | SyncClock sync; | ||
| 487 | // Epoch at which the thread had started. | ||
| 488 | // If we see an event from the thread stamped by an older epoch, | ||
| 489 | // the event is from a dead thread that shared tid with this thread. | ||
| 490 | u64 epoch0; | ||
| 491 | u64 epoch1; | ||
| 492 | |||
| 493 | // Override superclass callbacks. | ||
| 494 | void OnDead() override; | ||
| 495 | void OnJoined(void *arg) override; | ||
| 496 | void OnFinished() override; | ||
| 497 | void OnStarted(void *arg) override; | ||
| 498 | void OnCreated(void *arg) override; | ||
| 499 | void OnReset() override; | ||
| 500 | void OnDetached(void *arg) override; | ||
| 501 | }; | ||
| 502 | |||
| 503 | struct RacyStacks { | ||
| 504 | MD5Hash hash[2]; | ||
| 505 | bool operator==(const RacyStacks &other) const { | ||
| 506 | if (hash[0] == other.hash[0] && hash[1] == other.hash[1]) | ||
| 507 | return true; | ||
| 508 | if (hash[0] == other.hash[1] && hash[1] == other.hash[0]) | ||
| 509 | return true; | ||
| 510 | return false; | ||
| 511 | } | ||
| 512 | }; | ||
| 513 | |||
| 514 | struct RacyAddress { | ||
| 515 | uptr addr_min; | ||
| 516 | uptr addr_max; | ||
| 517 | }; | ||
| 518 | |||
| 519 | struct FiredSuppression { | ||
| 520 | ReportType type; | ||
| 521 | uptr pc_or_addr; | ||
| 522 | Suppression *supp; | ||
| 523 | }; | ||
| 524 | |||
| 525 | struct Context { | ||
| 526 | Context(); | ||
| 527 | |||
| 528 | bool initialized; | ||
| 529 | #if !SANITIZER_GO | ||
| 530 | bool after_multithreaded_fork; | ||
| 531 | #endif | ||
| 532 | |||
| 533 | MetaMap metamap; | ||
| 534 | |||
| 535 | Mutex report_mtx; | ||
| 536 | int nreported; | ||
| 537 | int nmissed_expected; | ||
| 538 | atomic_uint64_t last_symbolize_time_ns; | ||
| 539 | |||
| 540 | void *background_thread; | ||
| 541 | atomic_uint32_t stop_background_thread; | ||
| 542 | |||
| 543 | ThreadRegistry *thread_registry; | ||
| 544 | |||
| 545 | Mutex racy_mtx; | ||
| 546 | Vector<RacyStacks> racy_stacks; | ||
| 547 | Vector<RacyAddress> racy_addresses; | ||
| 548 | // Number of fired suppressions may be large enough. | ||
| 549 | Mutex fired_suppressions_mtx; | ||
| 550 | InternalMmapVector<FiredSuppression> fired_suppressions; | ||
| 551 | DDetector *dd; | ||
| 552 | |||
| 553 | ClockAlloc clock_alloc; | ||
| 554 | |||
| 555 | Flags flags; | ||
| 556 | |||
| 557 | u64 stat[StatCnt]; | ||
| 558 | u64 int_alloc_cnt[MBlockTypeCount]; | ||
| 559 | u64 int_alloc_siz[MBlockTypeCount]; | ||
| 560 | }; | ||
| 561 | |||
| 562 | extern Context *ctx; // The one and the only global runtime context. | ||
| 563 | |||
| 564 | ALWAYS_INLINE Flags *flags() { | ||
| 565 | return &ctx->flags; | ||
| 566 | } | ||
| 567 | |||
| 568 | struct ScopedIgnoreInterceptors { | ||
| 569 | ScopedIgnoreInterceptors() { | ||
| 570 | #if !SANITIZER_GO | ||
| 571 | cur_thread()->ignore_interceptors++; | ||
| 572 | #endif | ||
| 573 | } | ||
| 574 | |||
| 575 | ~ScopedIgnoreInterceptors() { | ||
| 576 | #if !SANITIZER_GO | ||
| 577 | cur_thread()->ignore_interceptors--; | ||
| 578 | #endif | ||
| 579 | } | ||
| 580 | }; | ||
| 581 | |||
| 582 | const char *GetObjectTypeFromTag(uptr tag); | ||
| 583 | const char *GetReportHeaderFromTag(uptr tag); | ||
| 584 | uptr TagFromShadowStackFrame(uptr pc); | ||
| 585 | |||
| 586 | class ScopedReportBase { | ||
| 587 | public: | ||
| 588 | void AddMemoryAccess(uptr addr, uptr external_tag, Shadow s, StackTrace stack, | ||
| 589 | const MutexSet *mset); | ||
| 590 | void AddStack(StackTrace stack, bool suppressable = false); | ||
| 591 | void AddThread(const ThreadContext *tctx, bool suppressable = false); | ||
| 592 | void AddThread(int unique_tid, bool suppressable = false); | ||
| 593 | void AddUniqueTid(int unique_tid); | ||
| 594 | void AddMutex(const SyncVar *s); | ||
| 595 | u64 AddMutex(u64 id); | ||
| 596 | void AddLocation(uptr addr, uptr size); | ||
| 597 | void AddSleep(u32 stack_id); | ||
| 598 | void SetCount(int count); | ||
| 599 | |||
| 600 | const ReportDesc *GetReport() const; | ||
| 601 | |||
| 602 | protected: | ||
| 603 | ScopedReportBase(ReportType typ, uptr tag); | ||
| 604 | ~ScopedReportBase(); | ||
| 605 | |||
| 606 | private: | ||
| 607 | ReportDesc *rep_; | ||
| 608 | // Symbolizer makes lots of intercepted calls. If we try to process them, | ||
| 609 | // at best it will cause deadlocks on internal mutexes. | ||
| 610 | ScopedIgnoreInterceptors ignore_interceptors_; | ||
| 611 | |||
| 612 | void AddDeadMutex(u64 id); | ||
| 613 | |||
| 614 | ScopedReportBase(const ScopedReportBase &) = delete; | ||
| 615 | void operator=(const ScopedReportBase &) = delete; | ||
| 616 | }; | ||
| 617 | |||
| 618 | class ScopedReport : public ScopedReportBase { | ||
| 619 | public: | ||
| 620 | explicit ScopedReport(ReportType typ, uptr tag = kExternalTagNone); | ||
| 621 | ~ScopedReport(); | ||
| 622 | |||
| 623 | private: | ||
| 624 | ScopedErrorReportLock lock_; | ||
| 625 | }; | ||
| 626 | |||
| 627 | ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack); | ||
| 628 | void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk, | ||
| 629 | MutexSet *mset, uptr *tag = nullptr); | ||
| 630 | |||
| 631 | // The stack could look like: | ||
| 632 | // <start> | <main> | <foo> | tag | <bar> | ||
| 633 | // This will extract the tag and keep: | ||
| 634 | // <start> | <main> | <foo> | <bar> | ||
| 635 | template<typename StackTraceTy> | ||
| 636 | void ExtractTagFromStack(StackTraceTy *stack, uptr *tag = nullptr) { | ||
| 637 | if (stack->size < 2) return; | ||
| 638 | uptr possible_tag_pc = stack->trace[stack->size - 2]; | ||
| 639 | uptr possible_tag = TagFromShadowStackFrame(possible_tag_pc); | ||
| 640 | if (possible_tag == kExternalTagNone) return; | ||
| 641 | stack->trace_buffer[stack->size - 2] = stack->trace_buffer[stack->size - 1]; | ||
| 642 | stack->size -= 1; | ||
| 643 | if (tag) *tag = possible_tag; | ||
| 644 | } | ||
| 645 | |||
| 646 | template<typename StackTraceTy> | ||
| 647 | void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack, | ||
| 648 | uptr *tag = nullptr) { | ||
| 649 | uptr size = thr->shadow_stack_pos - thr->shadow_stack; | ||
| 650 | uptr start = 0; | ||
| 651 | if (size + !!toppc > kStackTraceMax) { | ||
| 652 | start = size + !!toppc - kStackTraceMax; | ||
| 653 | size = kStackTraceMax - !!toppc; | ||
| 654 | } | ||
| 655 | stack->Init(&thr->shadow_stack[start], size, toppc); | ||
| 656 | ExtractTagFromStack(stack, tag); | ||
| 657 | } | ||
| 658 | |||
| 659 | #define GET_STACK_TRACE_FATAL(thr, pc) \ | ||
| 660 | VarSizeStackTrace stack; \ | ||
| 661 | ObtainCurrentStack(thr, pc, &stack); \ | ||
| 662 | stack.ReverseOrder(); | ||
| 663 | |||
| 664 | #if TSAN_COLLECT_STATS | ||
| 665 | void StatAggregate(u64 *dst, u64 *src); | ||
| 666 | void StatOutput(u64 *stat); | ||
| 667 | #endif | ||
| 668 | |||
| 669 | void ALWAYS_INLINE StatInc(ThreadState *thr, StatType typ, u64 n = 1) { | ||
| 670 | #if TSAN_COLLECT_STATS | ||
| 671 | thr->stat[typ] += n; | ||
| 672 | #endif | ||
| 673 | } | ||
| 674 | void ALWAYS_INLINE StatSet(ThreadState *thr, StatType typ, u64 n) { | ||
| 675 | #if TSAN_COLLECT_STATS | ||
| 676 | thr->stat[typ] = n; | ||
| 677 | #endif | ||
| 678 | } | ||
| 679 | |||
| 680 | void MapShadow(uptr addr, uptr size); | ||
| 681 | void MapThreadTrace(uptr addr, uptr size, const char *name); | ||
| 682 | void DontNeedShadowFor(uptr addr, uptr size); | ||
| 683 | void UnmapShadow(ThreadState *thr, uptr addr, uptr size); | ||
| 684 | void InitializeShadowMemory(); | ||
| 685 | void InitializeInterceptors(); | ||
| 686 | void InitializeLibIgnore(); | ||
| 687 | void InitializeDynamicAnnotations(); | ||
| 688 | |||
| 689 | void ForkBefore(ThreadState *thr, uptr pc); | ||
| 690 | void ForkParentAfter(ThreadState *thr, uptr pc); | ||
| 691 | void ForkChildAfter(ThreadState *thr, uptr pc); | ||
| 692 | |||
| 693 | void ReportRace(ThreadState *thr); | ||
| 694 | bool OutputReport(ThreadState *thr, const ScopedReport &srep); | ||
| 695 | bool IsFiredSuppression(Context *ctx, ReportType type, StackTrace trace); | ||
| 696 | bool IsExpectedReport(uptr addr, uptr size); | ||
| 697 | void PrintMatchedBenignRaces(); | ||
| 698 | |||
| 699 | #if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1 | ||
| 700 | # define DPrintf Printf | ||
| 701 | #else | ||
| 702 | # define DPrintf(...) | ||
| 703 | #endif | ||
| 704 | |||
| 705 | #if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 2 | ||
| 706 | # define DPrintf2 Printf | ||
| 707 | #else | ||
| 708 | # define DPrintf2(...) | ||
| 709 | #endif | ||
| 710 | |||
| 711 | u32 CurrentStackId(ThreadState *thr, uptr pc); | ||
| 712 | ReportStack *SymbolizeStackId(u32 stack_id); | ||
| 713 | void PrintCurrentStack(ThreadState *thr, uptr pc); | ||
| 714 | void PrintCurrentStackSlow(uptr pc); // uses libunwind | ||
| 715 | |||
| 716 | void Initialize(ThreadState *thr); | ||
| 717 | void MaybeSpawnBackgroundThread(); | ||
| 718 | int Finalize(ThreadState *thr); | ||
| 719 | |||
| 720 | void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write); | ||
| 721 | void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write); | ||
| 722 | |||
| 723 | void MemoryAccess(ThreadState *thr, uptr pc, uptr addr, | ||
| 724 | int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic); | ||
| 725 | void MemoryAccessImpl(ThreadState *thr, uptr addr, | ||
| 726 | int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic, | ||
| 727 | u64 *shadow_mem, Shadow cur); | ||
| 728 | void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, | ||
| 729 | uptr size, bool is_write); | ||
| 730 | void MemoryAccessRangeStep(ThreadState *thr, uptr pc, uptr addr, | ||
| 731 | uptr size, uptr step, bool is_write); | ||
| 732 | void UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr, | ||
| 733 | int size, bool kAccessIsWrite, bool kIsAtomic); | ||
| 734 | |||
| 735 | const int kSizeLog1 = 0; | ||
| 736 | const int kSizeLog2 = 1; | ||
| 737 | const int kSizeLog4 = 2; | ||
| 738 | const int kSizeLog8 = 3; | ||
| 739 | |||
| 740 | void ALWAYS_INLINE MemoryRead(ThreadState *thr, uptr pc, | ||
| 741 | uptr addr, int kAccessSizeLog) { | ||
| 742 | MemoryAccess(thr, pc, addr, kAccessSizeLog, false, false); | ||
| 743 | } | ||
| 744 | |||
| 745 | void ALWAYS_INLINE MemoryWrite(ThreadState *thr, uptr pc, | ||
| 746 | uptr addr, int kAccessSizeLog) { | ||
| 747 | MemoryAccess(thr, pc, addr, kAccessSizeLog, true, false); | ||
| 748 | } | ||
| 749 | |||
| 750 | void ALWAYS_INLINE MemoryReadAtomic(ThreadState *thr, uptr pc, | ||
| 751 | uptr addr, int kAccessSizeLog) { | ||
| 752 | MemoryAccess(thr, pc, addr, kAccessSizeLog, false, true); | ||
| 753 | } | ||
| 754 | |||
| 755 | void ALWAYS_INLINE MemoryWriteAtomic(ThreadState *thr, uptr pc, | ||
| 756 | uptr addr, int kAccessSizeLog) { | ||
| 757 | MemoryAccess(thr, pc, addr, kAccessSizeLog, true, true); | ||
| 758 | } | ||
| 759 | |||
| 760 | void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size); | ||
| 761 | void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size); | ||
| 762 | void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size); | ||
| 763 | void MemoryRangeImitateWriteOrResetRange(ThreadState *thr, uptr pc, uptr addr, | ||
| 764 | uptr size); | ||
| 765 | |||
| 766 | void ThreadIgnoreBegin(ThreadState *thr, uptr pc, bool save_stack = true); | ||
| 767 | void ThreadIgnoreEnd(ThreadState *thr, uptr pc); | ||
| 768 | void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc, bool save_stack = true); | ||
| 769 | void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc); | ||
| 770 | |||
| 771 | void FuncEntry(ThreadState *thr, uptr pc); | ||
| 772 | void FuncExit(ThreadState *thr); | ||
| 773 | |||
| 774 | int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached); | ||
| 775 | void ThreadStart(ThreadState *thr, int tid, tid_t os_id, | ||
| 776 | ThreadType thread_type); | ||
| 777 | void ThreadFinish(ThreadState *thr); | ||
| 778 | int ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid); | ||
| 779 | void ThreadJoin(ThreadState *thr, uptr pc, int tid); | ||
| 780 | void ThreadDetach(ThreadState *thr, uptr pc, int tid); | ||
| 781 | void ThreadFinalize(ThreadState *thr); | ||
| 782 | void ThreadSetName(ThreadState *thr, const char *name); | ||
| 783 | int ThreadCount(ThreadState *thr); | ||
| 784 | void ProcessPendingSignals(ThreadState *thr); | ||
| 785 | void ThreadNotJoined(ThreadState *thr, uptr pc, int tid, uptr uid); | ||
| 786 | |||
| 787 | Processor *ProcCreate(); | ||
| 788 | void ProcDestroy(Processor *proc); | ||
| 789 | void ProcWire(Processor *proc, ThreadState *thr); | ||
| 790 | void ProcUnwire(Processor *proc, ThreadState *thr); | ||
| 791 | |||
| 792 | // Note: the parameter is called flagz, because flags is already taken | ||
| 793 | // by the global function that returns flags. | ||
| 794 | void MutexCreate(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0); | ||
| 795 | void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0); | ||
| 796 | void MutexPreLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0); | ||
| 797 | void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0, | ||
| 798 | int rec = 1); | ||
| 799 | int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0); | ||
| 800 | void MutexPreReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0); | ||
| 801 | void MutexPostReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0); | ||
| 802 | void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr); | ||
| 803 | void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr); | ||
| 804 | void MutexRepair(ThreadState *thr, uptr pc, uptr addr); // call on EOWNERDEAD | ||
| 805 | void MutexInvalidAccess(ThreadState *thr, uptr pc, uptr addr); | ||
| 806 | |||
| 807 | void Acquire(ThreadState *thr, uptr pc, uptr addr); | ||
| 808 | // AcquireGlobal synchronizes the current thread with all other threads. | ||
| 809 | // In terms of happens-before relation, it draws a HB edge from all threads | ||
| 810 | // (where they happen to execute right now) to the current thread. We use it to | ||
| 811 | // handle Go finalizers. Namely, finalizer goroutine executes AcquireGlobal | ||
| 812 | // right before executing finalizers. This provides a coarse, but simple | ||
| 813 | // approximation of the actual required synchronization. | ||
| 814 | void AcquireGlobal(ThreadState *thr, uptr pc); | ||
| 815 | void Release(ThreadState *thr, uptr pc, uptr addr); | ||
| 816 | void ReleaseStoreAcquire(ThreadState *thr, uptr pc, uptr addr); | ||
| 817 | void ReleaseStore(ThreadState *thr, uptr pc, uptr addr); | ||
| 818 | void AfterSleep(ThreadState *thr, uptr pc); | ||
| 819 | void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c); | ||
| 820 | void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c); | ||
| 821 | void ReleaseStoreAcquireImpl(ThreadState *thr, uptr pc, SyncClock *c); | ||
| 822 | void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c); | ||
| 823 | void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c); | ||
| 824 | |||
| 825 | // The hacky call uses custom calling convention and an assembly thunk. | ||
| 826 | // It is considerably faster that a normal call for the caller | ||
| 827 | // if it is not executed (it is intended for slow paths from hot functions). | ||
| 828 | // The trick is that the call preserves all registers and the compiler | ||
| 829 | // does not treat it as a call. | ||
| 830 | // If it does not work for you, use normal call. | ||
| 831 | #if !SANITIZER_DEBUG && defined(__x86_64__) && !SANITIZER_MAC | ||
| 832 | // The caller may not create the stack frame for itself at all, | ||
| 833 | // so we create a reserve stack frame for it (1024b must be enough). | ||
| 834 | #define HACKY_CALL(f) \ | ||
| 835 | __asm__ __volatile__("sub $1024, %%rsp;" \ | ||
| 836 | CFI_INL_ADJUST_CFA_OFFSET(1024) \ | ||
| 837 | ".hidden " #f "_thunk;" \ | ||
| 838 | "call " #f "_thunk;" \ | ||
| 839 | "add $1024, %%rsp;" \ | ||
| 840 | CFI_INL_ADJUST_CFA_OFFSET(-1024) \ | ||
| 841 | ::: "memory", "cc"); | ||
| 842 | #else | ||
| 843 | #define HACKY_CALL(f) f() | ||
| 844 | #endif | ||
| 845 | |||
| 846 | void TraceSwitch(ThreadState *thr); | ||
| 847 | uptr TraceTopPC(ThreadState *thr); | ||
| 848 | uptr TraceSize(); | ||
| 849 | uptr TraceParts(); | ||
| 850 | Trace *ThreadTrace(int tid); | ||
| 851 | |||
| 852 | extern "C" void __tsan_trace_switch(); | ||
| 853 | void ALWAYS_INLINE TraceAddEvent(ThreadState *thr, FastState fs, | ||
| 854 | EventType typ, u64 addr) { | ||
| 855 | if (!kCollectHistory) | ||
| 856 | return; | ||
| 857 | DCHECK_GE((int)typ, 0); | ||
| 858 | DCHECK_LE((int)typ, 7); | ||
| 859 | DCHECK_EQ(GetLsb(addr, kEventPCBits), addr); | ||
| 860 | StatInc(thr, StatEvents); | ||
| 861 | u64 pos = fs.GetTracePos(); | ||
| 862 | if (UNLIKELY((pos % kTracePartSize) == 0)) { | ||
| 863 | #if !SANITIZER_GO | ||
| 864 | HACKY_CALL(__tsan_trace_switch); | ||
| 865 | #else | ||
| 866 | TraceSwitch(thr); | ||
| 867 | #endif | ||
| 868 | } | ||
| 869 | Event *trace = (Event*)GetThreadTrace(fs.tid()); | ||
| 870 | Event *evp = &trace[pos]; | ||
| 871 | Event ev = (u64)addr | ((u64)typ << kEventPCBits); | ||
| 872 | *evp = ev; | ||
| 873 | } | ||
| 874 | |||
| 875 | #if !SANITIZER_GO | ||
| 876 | uptr ALWAYS_INLINE HeapEnd() { | ||
| 877 | return HeapMemEnd() + PrimaryAllocator::AdditionalSize(); | ||
| 878 | } | ||
| 879 | #endif | ||
| 880 | |||
| 881 | ThreadState *FiberCreate(ThreadState *thr, uptr pc, unsigned flags); | ||
| 882 | void FiberDestroy(ThreadState *thr, uptr pc, ThreadState *fiber); | ||
| 883 | void FiberSwitch(ThreadState *thr, uptr pc, ThreadState *fiber, unsigned flags); | ||
| 884 | |||
| 885 | // These need to match __tsan_switch_to_fiber_* flags defined in | ||
| 886 | // tsan_interface.h. See documentation there as well. | ||
| 887 | enum FiberSwitchFlags { | ||
| 888 | FiberSwitchFlagNoSync = 1 << 0, // __tsan_switch_to_fiber_no_sync | ||
| 889 | }; | ||
| 890 | |||
| 891 | } // namespace __tsan | ||
| 892 | |||
| 893 | #endif // TSAN_RTL_H | ||
lib/tsan/tsan_rtl_mutex.cpp created+562| ... | @@ -0,0 +1,562 @@ | ||
| 1 | //===-- tsan_rtl_mutex.cpp ------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include <sanitizer_common/sanitizer_deadlock_detector_interface.h> | ||
| 14 | #include <sanitizer_common/sanitizer_stackdepot.h> | ||
| 15 | |||
| 16 | #include "tsan_rtl.h" | ||
| 17 | #include "tsan_flags.h" | ||
| 18 | #include "tsan_sync.h" | ||
| 19 | #include "tsan_report.h" | ||
| 20 | #include "tsan_symbolize.h" | ||
| 21 | #include "tsan_platform.h" | ||
| 22 | |||
| 23 | namespace __tsan { | ||
| 24 | |||
| 25 | void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r); | ||
| 26 | |||
| 27 | struct Callback : DDCallback { | ||
| 28 | ThreadState *thr; | ||
| 29 | uptr pc; | ||
| 30 | |||
| 31 | Callback(ThreadState *thr, uptr pc) | ||
| 32 | : thr(thr) | ||
| 33 | , pc(pc) { | ||
| 34 | DDCallback::pt = thr->proc()->dd_pt; | ||
| 35 | DDCallback::lt = thr->dd_lt; | ||
| 36 | } | ||
| 37 | |||
| 38 | u32 Unwind() override { return CurrentStackId(thr, pc); } | ||
| 39 | int UniqueTid() override { return thr->unique_id; } | ||
| 40 | }; | ||
| 41 | |||
| 42 | void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s) { | ||
| 43 | Callback cb(thr, pc); | ||
| 44 | ctx->dd->MutexInit(&cb, &s->dd); | ||
| 45 | s->dd.ctx = s->GetId(); | ||
| 46 | } | ||
| 47 | |||
| 48 | static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ, | ||
| 49 | uptr addr, u64 mid) { | ||
| 50 | // In Go, these misuses are either impossible, or detected by std lib, | ||
| 51 | // or false positives (e.g. unlock in a different thread). | ||
| 52 | if (SANITIZER_GO) | ||
| 53 | return; | ||
| 54 | ThreadRegistryLock l(ctx->thread_registry); | ||
| 55 | ScopedReport rep(typ); | ||
| 56 | rep.AddMutex(mid); | ||
| 57 | VarSizeStackTrace trace; | ||
| 58 | ObtainCurrentStack(thr, pc, &trace); | ||
| 59 | rep.AddStack(trace, true); | ||
| 60 | rep.AddLocation(addr, 1); | ||
| 61 | OutputReport(thr, rep); | ||
| 62 | } | ||
| 63 | |||
| 64 | void MutexCreate(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { | ||
| 65 | DPrintf("#%d: MutexCreate %zx flagz=0x%x\n", thr->tid, addr, flagz); | ||
| 66 | StatInc(thr, StatMutexCreate); | ||
| 67 | if (!(flagz & MutexFlagLinkerInit) && IsAppMem(addr)) { | ||
| 68 | CHECK(!thr->is_freeing); | ||
| 69 | thr->is_freeing = true; | ||
| 70 | MemoryWrite(thr, pc, addr, kSizeLog1); | ||
| 71 | thr->is_freeing = false; | ||
| 72 | } | ||
| 73 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); | ||
| 74 | s->SetFlags(flagz & MutexCreationFlagMask); | ||
| 75 | if (!SANITIZER_GO && s->creation_stack_id == 0) | ||
| 76 | s->creation_stack_id = CurrentStackId(thr, pc); | ||
| 77 | s->mtx.Unlock(); | ||
| 78 | } | ||
| 79 | |||
| 80 | void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { | ||
| 81 | DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr); | ||
| 82 | StatInc(thr, StatMutexDestroy); | ||
| 83 | SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true); | ||
| 84 | if (s == 0) | ||
| 85 | return; | ||
| 86 | if ((flagz & MutexFlagLinkerInit) | ||
| 87 | || s->IsFlagSet(MutexFlagLinkerInit) | ||
| 88 | || ((flagz & MutexFlagNotStatic) && !s->IsFlagSet(MutexFlagNotStatic))) { | ||
| 89 | // Destroy is no-op for linker-initialized mutexes. | ||
| 90 | s->mtx.Unlock(); | ||
| 91 | return; | ||
| 92 | } | ||
| 93 | if (common_flags()->detect_deadlocks) { | ||
| 94 | Callback cb(thr, pc); | ||
| 95 | ctx->dd->MutexDestroy(&cb, &s->dd); | ||
| 96 | ctx->dd->MutexInit(&cb, &s->dd); | ||
| 97 | } | ||
| 98 | bool unlock_locked = false; | ||
| 99 | if (flags()->report_destroy_locked | ||
| 100 | && s->owner_tid != SyncVar::kInvalidTid | ||
| 101 | && !s->IsFlagSet(MutexFlagBroken)) { | ||
| 102 | s->SetFlags(MutexFlagBroken); | ||
| 103 | unlock_locked = true; | ||
| 104 | } | ||
| 105 | u64 mid = s->GetId(); | ||
| 106 | u64 last_lock = s->last_lock; | ||
| 107 | if (!unlock_locked) | ||
| 108 | s->Reset(thr->proc()); // must not reset it before the report is printed | ||
| 109 | s->mtx.Unlock(); | ||
| 110 | if (unlock_locked) { | ||
| 111 | ThreadRegistryLock l(ctx->thread_registry); | ||
| 112 | ScopedReport rep(ReportTypeMutexDestroyLocked); | ||
| 113 | rep.AddMutex(mid); | ||
| 114 | VarSizeStackTrace trace; | ||
| 115 | ObtainCurrentStack(thr, pc, &trace); | ||
| 116 | rep.AddStack(trace, true); | ||
| 117 | FastState last(last_lock); | ||
| 118 | RestoreStack(last.tid(), last.epoch(), &trace, 0); | ||
| 119 | rep.AddStack(trace, true); | ||
| 120 | rep.AddLocation(addr, 1); | ||
| 121 | OutputReport(thr, rep); | ||
| 122 | |||
| 123 | SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true); | ||
| 124 | if (s != 0) { | ||
| 125 | s->Reset(thr->proc()); | ||
| 126 | s->mtx.Unlock(); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | thr->mset.Remove(mid); | ||
| 130 | // Imitate a memory write to catch unlock-destroy races. | ||
| 131 | // Do this outside of sync mutex, because it can report a race which locks | ||
| 132 | // sync mutexes. | ||
| 133 | if (IsAppMem(addr)) { | ||
| 134 | CHECK(!thr->is_freeing); | ||
| 135 | thr->is_freeing = true; | ||
| 136 | MemoryWrite(thr, pc, addr, kSizeLog1); | ||
| 137 | thr->is_freeing = false; | ||
| 138 | } | ||
| 139 | // s will be destroyed and freed in MetaMap::FreeBlock. | ||
| 140 | } | ||
| 141 | |||
| 142 | void MutexPreLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { | ||
| 143 | DPrintf("#%d: MutexPreLock %zx flagz=0x%x\n", thr->tid, addr, flagz); | ||
| 144 | if (!(flagz & MutexFlagTryLock) && common_flags()->detect_deadlocks) { | ||
| 145 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false); | ||
| 146 | s->UpdateFlags(flagz); | ||
| 147 | if (s->owner_tid != thr->tid) { | ||
| 148 | Callback cb(thr, pc); | ||
| 149 | ctx->dd->MutexBeforeLock(&cb, &s->dd, true); | ||
| 150 | s->mtx.ReadUnlock(); | ||
| 151 | ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); | ||
| 152 | } else { | ||
| 153 | s->mtx.ReadUnlock(); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz, int rec) { | ||
| 159 | DPrintf("#%d: MutexPostLock %zx flag=0x%x rec=%d\n", | ||
| 160 | thr->tid, addr, flagz, rec); | ||
| 161 | if (flagz & MutexFlagRecursiveLock) | ||
| 162 | CHECK_GT(rec, 0); | ||
| 163 | else | ||
| 164 | rec = 1; | ||
| 165 | if (IsAppMem(addr)) | ||
| 166 | MemoryReadAtomic(thr, pc, addr, kSizeLog1); | ||
| 167 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); | ||
| 168 | s->UpdateFlags(flagz); | ||
| 169 | thr->fast_state.IncrementEpoch(); | ||
| 170 | TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId()); | ||
| 171 | bool report_double_lock = false; | ||
| 172 | if (s->owner_tid == SyncVar::kInvalidTid) { | ||
| 173 | CHECK_EQ(s->recursion, 0); | ||
| 174 | s->owner_tid = thr->tid; | ||
| 175 | s->last_lock = thr->fast_state.raw(); | ||
| 176 | } else if (s->owner_tid == thr->tid) { | ||
| 177 | CHECK_GT(s->recursion, 0); | ||
| 178 | } else if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { | ||
| 179 | s->SetFlags(MutexFlagBroken); | ||
| 180 | report_double_lock = true; | ||
| 181 | } | ||
| 182 | const bool first = s->recursion == 0; | ||
| 183 | s->recursion += rec; | ||
| 184 | if (first) { | ||
| 185 | StatInc(thr, StatMutexLock); | ||
| 186 | AcquireImpl(thr, pc, &s->clock); | ||
| 187 | AcquireImpl(thr, pc, &s->read_clock); | ||
| 188 | } else if (!s->IsFlagSet(MutexFlagWriteReentrant)) { | ||
| 189 | StatInc(thr, StatMutexRecLock); | ||
| 190 | } | ||
| 191 | thr->mset.Add(s->GetId(), true, thr->fast_state.epoch()); | ||
| 192 | bool pre_lock = false; | ||
| 193 | if (first && common_flags()->detect_deadlocks) { | ||
| 194 | pre_lock = (flagz & MutexFlagDoPreLockOnPostLock) && | ||
| 195 | !(flagz & MutexFlagTryLock); | ||
| 196 | Callback cb(thr, pc); | ||
| 197 | if (pre_lock) | ||
| 198 | ctx->dd->MutexBeforeLock(&cb, &s->dd, true); | ||
| 199 | ctx->dd->MutexAfterLock(&cb, &s->dd, true, flagz & MutexFlagTryLock); | ||
| 200 | } | ||
| 201 | u64 mid = s->GetId(); | ||
| 202 | s->mtx.Unlock(); | ||
| 203 | // Can't touch s after this point. | ||
| 204 | s = 0; | ||
| 205 | if (report_double_lock) | ||
| 206 | ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid); | ||
| 207 | if (first && pre_lock && common_flags()->detect_deadlocks) { | ||
| 208 | Callback cb(thr, pc); | ||
| 209 | ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { | ||
| 214 | DPrintf("#%d: MutexUnlock %zx flagz=0x%x\n", thr->tid, addr, flagz); | ||
| 215 | if (IsAppMem(addr)) | ||
| 216 | MemoryReadAtomic(thr, pc, addr, kSizeLog1); | ||
| 217 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); | ||
| 218 | thr->fast_state.IncrementEpoch(); | ||
| 219 | TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId()); | ||
| 220 | int rec = 0; | ||
| 221 | bool report_bad_unlock = false; | ||
| 222 | if (!SANITIZER_GO && (s->recursion == 0 || s->owner_tid != thr->tid)) { | ||
| 223 | if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { | ||
| 224 | s->SetFlags(MutexFlagBroken); | ||
| 225 | report_bad_unlock = true; | ||
| 226 | } | ||
| 227 | } else { | ||
| 228 | rec = (flagz & MutexFlagRecursiveUnlock) ? s->recursion : 1; | ||
| 229 | s->recursion -= rec; | ||
| 230 | if (s->recursion == 0) { | ||
| 231 | StatInc(thr, StatMutexUnlock); | ||
| 232 | s->owner_tid = SyncVar::kInvalidTid; | ||
| 233 | ReleaseStoreImpl(thr, pc, &s->clock); | ||
| 234 | } else { | ||
| 235 | StatInc(thr, StatMutexRecUnlock); | ||
| 236 | } | ||
| 237 | } | ||
| 238 | thr->mset.Del(s->GetId(), true); | ||
| 239 | if (common_flags()->detect_deadlocks && s->recursion == 0 && | ||
| 240 | !report_bad_unlock) { | ||
| 241 | Callback cb(thr, pc); | ||
| 242 | ctx->dd->MutexBeforeUnlock(&cb, &s->dd, true); | ||
| 243 | } | ||
| 244 | u64 mid = s->GetId(); | ||
| 245 | s->mtx.Unlock(); | ||
| 246 | // Can't touch s after this point. | ||
| 247 | if (report_bad_unlock) | ||
| 248 | ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid); | ||
| 249 | if (common_flags()->detect_deadlocks && !report_bad_unlock) { | ||
| 250 | Callback cb(thr, pc); | ||
| 251 | ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); | ||
| 252 | } | ||
| 253 | return rec; | ||
| 254 | } | ||
| 255 | |||
| 256 | void MutexPreReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { | ||
| 257 | DPrintf("#%d: MutexPreReadLock %zx flagz=0x%x\n", thr->tid, addr, flagz); | ||
| 258 | if (!(flagz & MutexFlagTryLock) && common_flags()->detect_deadlocks) { | ||
| 259 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false); | ||
| 260 | s->UpdateFlags(flagz); | ||
| 261 | Callback cb(thr, pc); | ||
| 262 | ctx->dd->MutexBeforeLock(&cb, &s->dd, false); | ||
| 263 | s->mtx.ReadUnlock(); | ||
| 264 | ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | void MutexPostReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { | ||
| 269 | DPrintf("#%d: MutexPostReadLock %zx flagz=0x%x\n", thr->tid, addr, flagz); | ||
| 270 | StatInc(thr, StatMutexReadLock); | ||
| 271 | if (IsAppMem(addr)) | ||
| 272 | MemoryReadAtomic(thr, pc, addr, kSizeLog1); | ||
| 273 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false); | ||
| 274 | s->UpdateFlags(flagz); | ||
| 275 | thr->fast_state.IncrementEpoch(); | ||
| 276 | TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId()); | ||
| 277 | bool report_bad_lock = false; | ||
| 278 | if (s->owner_tid != SyncVar::kInvalidTid) { | ||
| 279 | if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { | ||
| 280 | s->SetFlags(MutexFlagBroken); | ||
| 281 | report_bad_lock = true; | ||
| 282 | } | ||
| 283 | } | ||
| 284 | AcquireImpl(thr, pc, &s->clock); | ||
| 285 | s->last_lock = thr->fast_state.raw(); | ||
| 286 | thr->mset.Add(s->GetId(), false, thr->fast_state.epoch()); | ||
| 287 | bool pre_lock = false; | ||
| 288 | if (common_flags()->detect_deadlocks) { | ||
| 289 | pre_lock = (flagz & MutexFlagDoPreLockOnPostLock) && | ||
| 290 | !(flagz & MutexFlagTryLock); | ||
| 291 | Callback cb(thr, pc); | ||
| 292 | if (pre_lock) | ||
| 293 | ctx->dd->MutexBeforeLock(&cb, &s->dd, false); | ||
| 294 | ctx->dd->MutexAfterLock(&cb, &s->dd, false, flagz & MutexFlagTryLock); | ||
| 295 | } | ||
| 296 | u64 mid = s->GetId(); | ||
| 297 | s->mtx.ReadUnlock(); | ||
| 298 | // Can't touch s after this point. | ||
| 299 | s = 0; | ||
| 300 | if (report_bad_lock) | ||
| 301 | ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid); | ||
| 302 | if (pre_lock && common_flags()->detect_deadlocks) { | ||
| 303 | Callback cb(thr, pc); | ||
| 304 | ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) { | ||
| 309 | DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr); | ||
| 310 | StatInc(thr, StatMutexReadUnlock); | ||
| 311 | if (IsAppMem(addr)) | ||
| 312 | MemoryReadAtomic(thr, pc, addr, kSizeLog1); | ||
| 313 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); | ||
| 314 | thr->fast_state.IncrementEpoch(); | ||
| 315 | TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId()); | ||
| 316 | bool report_bad_unlock = false; | ||
| 317 | if (s->owner_tid != SyncVar::kInvalidTid) { | ||
| 318 | if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { | ||
| 319 | s->SetFlags(MutexFlagBroken); | ||
| 320 | report_bad_unlock = true; | ||
| 321 | } | ||
| 322 | } | ||
| 323 | ReleaseImpl(thr, pc, &s->read_clock); | ||
| 324 | if (common_flags()->detect_deadlocks && s->recursion == 0) { | ||
| 325 | Callback cb(thr, pc); | ||
| 326 | ctx->dd->MutexBeforeUnlock(&cb, &s->dd, false); | ||
| 327 | } | ||
| 328 | u64 mid = s->GetId(); | ||
| 329 | s->mtx.Unlock(); | ||
| 330 | // Can't touch s after this point. | ||
| 331 | thr->mset.Del(mid, false); | ||
| 332 | if (report_bad_unlock) | ||
| 333 | ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadUnlock, addr, mid); | ||
| 334 | if (common_flags()->detect_deadlocks) { | ||
| 335 | Callback cb(thr, pc); | ||
| 336 | ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); | ||
| 337 | } | ||
| 338 | } | ||
| 339 | |||
| 340 | void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) { | ||
| 341 | DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr); | ||
| 342 | if (IsAppMem(addr)) | ||
| 343 | MemoryReadAtomic(thr, pc, addr, kSizeLog1); | ||
| 344 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); | ||
| 345 | bool write = true; | ||
| 346 | bool report_bad_unlock = false; | ||
| 347 | if (s->owner_tid == SyncVar::kInvalidTid) { | ||
| 348 | // Seems to be read unlock. | ||
| 349 | write = false; | ||
| 350 | StatInc(thr, StatMutexReadUnlock); | ||
| 351 | thr->fast_state.IncrementEpoch(); | ||
| 352 | TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId()); | ||
| 353 | ReleaseImpl(thr, pc, &s->read_clock); | ||
| 354 | } else if (s->owner_tid == thr->tid) { | ||
| 355 | // Seems to be write unlock. | ||
| 356 | thr->fast_state.IncrementEpoch(); | ||
| 357 | TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId()); | ||
| 358 | CHECK_GT(s->recursion, 0); | ||
| 359 | s->recursion--; | ||
| 360 | if (s->recursion == 0) { | ||
| 361 | StatInc(thr, StatMutexUnlock); | ||
| 362 | s->owner_tid = SyncVar::kInvalidTid; | ||
| 363 | ReleaseStoreImpl(thr, pc, &s->clock); | ||
| 364 | } else { | ||
| 365 | StatInc(thr, StatMutexRecUnlock); | ||
| 366 | } | ||
| 367 | } else if (!s->IsFlagSet(MutexFlagBroken)) { | ||
| 368 | s->SetFlags(MutexFlagBroken); | ||
| 369 | report_bad_unlock = true; | ||
| 370 | } | ||
| 371 | thr->mset.Del(s->GetId(), write); | ||
| 372 | if (common_flags()->detect_deadlocks && s->recursion == 0) { | ||
| 373 | Callback cb(thr, pc); | ||
| 374 | ctx->dd->MutexBeforeUnlock(&cb, &s->dd, write); | ||
| 375 | } | ||
| 376 | u64 mid = s->GetId(); | ||
| 377 | s->mtx.Unlock(); | ||
| 378 | // Can't touch s after this point. | ||
| 379 | if (report_bad_unlock) | ||
| 380 | ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid); | ||
| 381 | if (common_flags()->detect_deadlocks) { | ||
| 382 | Callback cb(thr, pc); | ||
| 383 | ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 | void MutexRepair(ThreadState *thr, uptr pc, uptr addr) { | ||
| 388 | DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr); | ||
| 389 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); | ||
| 390 | s->owner_tid = SyncVar::kInvalidTid; | ||
| 391 | s->recursion = 0; | ||
| 392 | s->mtx.Unlock(); | ||
| 393 | } | ||
| 394 | |||
| 395 | void MutexInvalidAccess(ThreadState *thr, uptr pc, uptr addr) { | ||
| 396 | DPrintf("#%d: MutexInvalidAccess %zx\n", thr->tid, addr); | ||
| 397 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); | ||
| 398 | u64 mid = s->GetId(); | ||
| 399 | s->mtx.Unlock(); | ||
| 400 | ReportMutexMisuse(thr, pc, ReportTypeMutexInvalidAccess, addr, mid); | ||
| 401 | } | ||
| 402 | |||
| 403 | void Acquire(ThreadState *thr, uptr pc, uptr addr) { | ||
| 404 | DPrintf("#%d: Acquire %zx\n", thr->tid, addr); | ||
| 405 | if (thr->ignore_sync) | ||
| 406 | return; | ||
| 407 | SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, false); | ||
| 408 | if (!s) | ||
| 409 | return; | ||
| 410 | AcquireImpl(thr, pc, &s->clock); | ||
| 411 | s->mtx.ReadUnlock(); | ||
| 412 | } | ||
| 413 | |||
| 414 | static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) { | ||
| 415 | ThreadState *thr = reinterpret_cast<ThreadState*>(arg); | ||
| 416 | ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base); | ||
| 417 | u64 epoch = tctx->epoch1; | ||
| 418 | if (tctx->status == ThreadStatusRunning) { | ||
| 419 | epoch = tctx->thr->fast_state.epoch(); | ||
| 420 | tctx->thr->clock.NoteGlobalAcquire(epoch); | ||
| 421 | } | ||
| 422 | thr->clock.set(&thr->proc()->clock_cache, tctx->tid, epoch); | ||
| 423 | } | ||
| 424 | |||
| 425 | void AcquireGlobal(ThreadState *thr, uptr pc) { | ||
| 426 | DPrintf("#%d: AcquireGlobal\n", thr->tid); | ||
| 427 | if (thr->ignore_sync) | ||
| 428 | return; | ||
| 429 | ThreadRegistryLock l(ctx->thread_registry); | ||
| 430 | ctx->thread_registry->RunCallbackForEachThreadLocked( | ||
| 431 | UpdateClockCallback, thr); | ||
| 432 | } | ||
| 433 | |||
| 434 | void ReleaseStoreAcquire(ThreadState *thr, uptr pc, uptr addr) { | ||
| 435 | DPrintf("#%d: ReleaseStoreAcquire %zx\n", thr->tid, addr); | ||
| 436 | if (thr->ignore_sync) | ||
| 437 | return; | ||
| 438 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); | ||
| 439 | thr->fast_state.IncrementEpoch(); | ||
| 440 | // Can't increment epoch w/o writing to the trace as well. | ||
| 441 | TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); | ||
| 442 | ReleaseStoreAcquireImpl(thr, pc, &s->clock); | ||
| 443 | s->mtx.Unlock(); | ||
| 444 | } | ||
| 445 | |||
| 446 | void Release(ThreadState *thr, uptr pc, uptr addr) { | ||
| 447 | DPrintf("#%d: Release %zx\n", thr->tid, addr); | ||
| 448 | if (thr->ignore_sync) | ||
| 449 | return; | ||
| 450 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); | ||
| 451 | thr->fast_state.IncrementEpoch(); | ||
| 452 | // Can't increment epoch w/o writing to the trace as well. | ||
| 453 | TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); | ||
| 454 | ReleaseImpl(thr, pc, &s->clock); | ||
| 455 | s->mtx.Unlock(); | ||
| 456 | } | ||
| 457 | |||
| 458 | void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) { | ||
| 459 | DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr); | ||
| 460 | if (thr->ignore_sync) | ||
| 461 | return; | ||
| 462 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); | ||
| 463 | thr->fast_state.IncrementEpoch(); | ||
| 464 | // Can't increment epoch w/o writing to the trace as well. | ||
| 465 | TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); | ||
| 466 | ReleaseStoreImpl(thr, pc, &s->clock); | ||
| 467 | s->mtx.Unlock(); | ||
| 468 | } | ||
| 469 | |||
| 470 | #if !SANITIZER_GO | ||
| 471 | static void UpdateSleepClockCallback(ThreadContextBase *tctx_base, void *arg) { | ||
| 472 | ThreadState *thr = reinterpret_cast<ThreadState*>(arg); | ||
| 473 | ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base); | ||
| 474 | u64 epoch = tctx->epoch1; | ||
| 475 | if (tctx->status == ThreadStatusRunning) | ||
| 476 | epoch = tctx->thr->fast_state.epoch(); | ||
| 477 | thr->last_sleep_clock.set(&thr->proc()->clock_cache, tctx->tid, epoch); | ||
| 478 | } | ||
| 479 | |||
| 480 | void AfterSleep(ThreadState *thr, uptr pc) { | ||
| 481 | DPrintf("#%d: AfterSleep %zx\n", thr->tid); | ||
| 482 | if (thr->ignore_sync) | ||
| 483 | return; | ||
| 484 | thr->last_sleep_stack_id = CurrentStackId(thr, pc); | ||
| 485 | ThreadRegistryLock l(ctx->thread_registry); | ||
| 486 | ctx->thread_registry->RunCallbackForEachThreadLocked( | ||
| 487 | UpdateSleepClockCallback, thr); | ||
| 488 | } | ||
| 489 | #endif | ||
| 490 | |||
| 491 | void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) { | ||
| 492 | if (thr->ignore_sync) | ||
| 493 | return; | ||
| 494 | thr->clock.set(thr->fast_state.epoch()); | ||
| 495 | thr->clock.acquire(&thr->proc()->clock_cache, c); | ||
| 496 | StatInc(thr, StatSyncAcquire); | ||
| 497 | } | ||
| 498 | |||
| 499 | void ReleaseStoreAcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) { | ||
| 500 | if (thr->ignore_sync) | ||
| 501 | return; | ||
| 502 | thr->clock.set(thr->fast_state.epoch()); | ||
| 503 | thr->fast_synch_epoch = thr->fast_state.epoch(); | ||
| 504 | thr->clock.releaseStoreAcquire(&thr->proc()->clock_cache, c); | ||
| 505 | StatInc(thr, StatSyncReleaseStoreAcquire); | ||
| 506 | } | ||
| 507 | |||
| 508 | void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { | ||
| 509 | if (thr->ignore_sync) | ||
| 510 | return; | ||
| 511 | thr->clock.set(thr->fast_state.epoch()); | ||
| 512 | thr->fast_synch_epoch = thr->fast_state.epoch(); | ||
| 513 | thr->clock.release(&thr->proc()->clock_cache, c); | ||
| 514 | StatInc(thr, StatSyncRelease); | ||
| 515 | } | ||
| 516 | |||
| 517 | void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c) { | ||
| 518 | if (thr->ignore_sync) | ||
| 519 | return; | ||
| 520 | thr->clock.set(thr->fast_state.epoch()); | ||
| 521 | thr->fast_synch_epoch = thr->fast_state.epoch(); | ||
| 522 | thr->clock.ReleaseStore(&thr->proc()->clock_cache, c); | ||
| 523 | StatInc(thr, StatSyncRelease); | ||
| 524 | } | ||
| 525 | |||
| 526 | void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { | ||
| 527 | if (thr->ignore_sync) | ||
| 528 | return; | ||
| 529 | thr->clock.set(thr->fast_state.epoch()); | ||
| 530 | thr->fast_synch_epoch = thr->fast_state.epoch(); | ||
| 531 | thr->clock.acq_rel(&thr->proc()->clock_cache, c); | ||
| 532 | StatInc(thr, StatSyncAcquire); | ||
| 533 | StatInc(thr, StatSyncRelease); | ||
| 534 | } | ||
| 535 | |||
| 536 | void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) { | ||
| 537 | if (r == 0) | ||
| 538 | return; | ||
| 539 | ThreadRegistryLock l(ctx->thread_registry); | ||
| 540 | ScopedReport rep(ReportTypeDeadlock); | ||
| 541 | for (int i = 0; i < r->n; i++) { | ||
| 542 | rep.AddMutex(r->loop[i].mtx_ctx0); | ||
| 543 | rep.AddUniqueTid((int)r->loop[i].thr_ctx); | ||
| 544 | rep.AddThread((int)r->loop[i].thr_ctx); | ||
| 545 | } | ||
| 546 | uptr dummy_pc = 0x42; | ||
| 547 | for (int i = 0; i < r->n; i++) { | ||
| 548 | for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) { | ||
| 549 | u32 stk = r->loop[i].stk[j]; | ||
| 550 | if (stk && stk != 0xffffffff) { | ||
| 551 | rep.AddStack(StackDepotGet(stk), true); | ||
| 552 | } else { | ||
| 553 | // Sometimes we fail to extract the stack trace (FIXME: investigate), | ||
| 554 | // but we should still produce some stack trace in the report. | ||
| 555 | rep.AddStack(StackTrace(&dummy_pc, 1), true); | ||
| 556 | } | ||
| 557 | } | ||
| 558 | } | ||
| 559 | OutputReport(thr, rep); | ||
| 560 | } | ||
| 561 | |||
| 562 | } // namespace __tsan | ||
lib/tsan/tsan_rtl_proc.cpp created+60| ... | @@ -0,0 +1,60 @@ | ||
| 1 | //===-- tsan_rtl_proc.cpp -----------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_common/sanitizer_placement_new.h" | ||
| 14 | #include "tsan_rtl.h" | ||
| 15 | #include "tsan_mman.h" | ||
| 16 | #include "tsan_flags.h" | ||
| 17 | |||
| 18 | namespace __tsan { | ||
| 19 | |||
| 20 | Processor *ProcCreate() { | ||
| 21 | void *mem = InternalAlloc(sizeof(Processor)); | ||
| 22 | internal_memset(mem, 0, sizeof(Processor)); | ||
| 23 | Processor *proc = new(mem) Processor; | ||
| 24 | proc->thr = nullptr; | ||
| 25 | #if !SANITIZER_GO | ||
| 26 | AllocatorProcStart(proc); | ||
| 27 | #endif | ||
| 28 | if (common_flags()->detect_deadlocks) | ||
| 29 | proc->dd_pt = ctx->dd->CreatePhysicalThread(); | ||
| 30 | return proc; | ||
| 31 | } | ||
| 32 | |||
| 33 | void ProcDestroy(Processor *proc) { | ||
| 34 | CHECK_EQ(proc->thr, nullptr); | ||
| 35 | #if !SANITIZER_GO | ||
| 36 | AllocatorProcFinish(proc); | ||
| 37 | #endif | ||
| 38 | ctx->clock_alloc.FlushCache(&proc->clock_cache); | ||
| 39 | ctx->metamap.OnProcIdle(proc); | ||
| 40 | if (common_flags()->detect_deadlocks) | ||
| 41 | ctx->dd->DestroyPhysicalThread(proc->dd_pt); | ||
| 42 | proc->~Processor(); | ||
| 43 | InternalFree(proc); | ||
| 44 | } | ||
| 45 | |||
| 46 | void ProcWire(Processor *proc, ThreadState *thr) { | ||
| 47 | CHECK_EQ(thr->proc1, nullptr); | ||
| 48 | CHECK_EQ(proc->thr, nullptr); | ||
| 49 | thr->proc1 = proc; | ||
| 50 | proc->thr = thr; | ||
| 51 | } | ||
| 52 | |||
| 53 | void ProcUnwire(Processor *proc, ThreadState *thr) { | ||
| 54 | CHECK_EQ(thr->proc1, proc); | ||
| 55 | CHECK_EQ(proc->thr, thr); | ||
| 56 | thr->proc1 = nullptr; | ||
| 57 | proc->thr = nullptr; | ||
| 58 | } | ||
| 59 | |||
| 60 | } // namespace __tsan | ||
lib/tsan/tsan_rtl_report.cpp created+754| ... | @@ -0,0 +1,754 @@ | ||
| 1 | //===-- tsan_rtl_report.cpp -----------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_common/sanitizer_libc.h" | ||
| 14 | #include "sanitizer_common/sanitizer_placement_new.h" | ||
| 15 | #include "sanitizer_common/sanitizer_stackdepot.h" | ||
| 16 | #include "sanitizer_common/sanitizer_common.h" | ||
| 17 | #include "sanitizer_common/sanitizer_stacktrace.h" | ||
| 18 | #include "tsan_platform.h" | ||
| 19 | #include "tsan_rtl.h" | ||
| 20 | #include "tsan_suppressions.h" | ||
| 21 | #include "tsan_symbolize.h" | ||
| 22 | #include "tsan_report.h" | ||
| 23 | #include "tsan_sync.h" | ||
| 24 | #include "tsan_mman.h" | ||
| 25 | #include "tsan_flags.h" | ||
| 26 | #include "tsan_fd.h" | ||
| 27 | |||
| 28 | namespace __tsan { | ||
| 29 | |||
| 30 | using namespace __sanitizer; | ||
| 31 | |||
| 32 | static ReportStack *SymbolizeStack(StackTrace trace); | ||
| 33 | |||
| 34 | void TsanCheckFailed(const char *file, int line, const char *cond, | ||
| 35 | u64 v1, u64 v2) { | ||
| 36 | // There is high probability that interceptors will check-fail as well, | ||
| 37 | // on the other hand there is no sense in processing interceptors | ||
| 38 | // since we are going to die soon. | ||
| 39 | ScopedIgnoreInterceptors ignore; | ||
| 40 | #if !SANITIZER_GO | ||
| 41 | cur_thread()->ignore_sync++; | ||
| 42 | cur_thread()->ignore_reads_and_writes++; | ||
| 43 | #endif | ||
| 44 | Printf("FATAL: ThreadSanitizer CHECK failed: " | ||
| 45 | "%s:%d \"%s\" (0x%zx, 0x%zx)\n", | ||
| 46 | file, line, cond, (uptr)v1, (uptr)v2); | ||
| 47 | PrintCurrentStackSlow(StackTrace::GetCurrentPc()); | ||
| 48 | Die(); | ||
| 49 | } | ||
| 50 | |||
| 51 | // Can be overriden by an application/test to intercept reports. | ||
| 52 | #ifdef TSAN_EXTERNAL_HOOKS | ||
| 53 | bool OnReport(const ReportDesc *rep, bool suppressed); | ||
| 54 | #else | ||
| 55 | SANITIZER_WEAK_CXX_DEFAULT_IMPL | ||
| 56 | bool OnReport(const ReportDesc *rep, bool suppressed) { | ||
| 57 | (void)rep; | ||
| 58 | return suppressed; | ||
| 59 | } | ||
| 60 | #endif | ||
| 61 | |||
| 62 | SANITIZER_WEAK_DEFAULT_IMPL | ||
| 63 | void __tsan_on_report(const ReportDesc *rep) { | ||
| 64 | (void)rep; | ||
| 65 | } | ||
| 66 | |||
| 67 | static void StackStripMain(SymbolizedStack *frames) { | ||
| 68 | SymbolizedStack *last_frame = nullptr; | ||
| 69 | SymbolizedStack *last_frame2 = nullptr; | ||
| 70 | for (SymbolizedStack *cur = frames; cur; cur = cur->next) { | ||
| 71 | last_frame2 = last_frame; | ||
| 72 | last_frame = cur; | ||
| 73 | } | ||
| 74 | |||
| 75 | if (last_frame2 == 0) | ||
| 76 | return; | ||
| 77 | #if !SANITIZER_GO | ||
| 78 | const char *last = last_frame->info.function; | ||
| 79 | const char *last2 = last_frame2->info.function; | ||
| 80 | // Strip frame above 'main' | ||
| 81 | if (last2 && 0 == internal_strcmp(last2, "main")) { | ||
| 82 | last_frame->ClearAll(); | ||
| 83 | last_frame2->next = nullptr; | ||
| 84 | // Strip our internal thread start routine. | ||
| 85 | } else if (last && 0 == internal_strcmp(last, "__tsan_thread_start_func")) { | ||
| 86 | last_frame->ClearAll(); | ||
| 87 | last_frame2->next = nullptr; | ||
| 88 | // Strip global ctors init. | ||
| 89 | } else if (last && 0 == internal_strcmp(last, "__do_global_ctors_aux")) { | ||
| 90 | last_frame->ClearAll(); | ||
| 91 | last_frame2->next = nullptr; | ||
| 92 | // If both are 0, then we probably just failed to symbolize. | ||
| 93 | } else if (last || last2) { | ||
| 94 | // Ensure that we recovered stack completely. Trimmed stack | ||
| 95 | // can actually happen if we do not instrument some code, | ||
| 96 | // so it's only a debug print. However we must try hard to not miss it | ||
| 97 | // due to our fault. | ||
| 98 | DPrintf("Bottom stack frame is missed\n"); | ||
| 99 | } | ||
| 100 | #else | ||
| 101 | // The last frame always point into runtime (gosched0, goexit0, runtime.main). | ||
| 102 | last_frame->ClearAll(); | ||
| 103 | last_frame2->next = nullptr; | ||
| 104 | #endif | ||
| 105 | } | ||
| 106 | |||
| 107 | ReportStack *SymbolizeStackId(u32 stack_id) { | ||
| 108 | if (stack_id == 0) | ||
| 109 | return 0; | ||
| 110 | StackTrace stack = StackDepotGet(stack_id); | ||
| 111 | if (stack.trace == nullptr) | ||
| 112 | return nullptr; | ||
| 113 | return SymbolizeStack(stack); | ||
| 114 | } | ||
| 115 | |||
| 116 | static ReportStack *SymbolizeStack(StackTrace trace) { | ||
| 117 | if (trace.size == 0) | ||
| 118 | return 0; | ||
| 119 | SymbolizedStack *top = nullptr; | ||
| 120 | for (uptr si = 0; si < trace.size; si++) { | ||
| 121 | const uptr pc = trace.trace[si]; | ||
| 122 | uptr pc1 = pc; | ||
| 123 | // We obtain the return address, but we're interested in the previous | ||
| 124 | // instruction. | ||
| 125 | if ((pc & kExternalPCBit) == 0) | ||
| 126 | pc1 = StackTrace::GetPreviousInstructionPc(pc); | ||
| 127 | SymbolizedStack *ent = SymbolizeCode(pc1); | ||
| 128 | CHECK_NE(ent, 0); | ||
| 129 | SymbolizedStack *last = ent; | ||
| 130 | while (last->next) { | ||
| 131 | last->info.address = pc; // restore original pc for report | ||
| 132 | last = last->next; | ||
| 133 | } | ||
| 134 | last->info.address = pc; // restore original pc for report | ||
| 135 | last->next = top; | ||
| 136 | top = ent; | ||
| 137 | } | ||
| 138 | StackStripMain(top); | ||
| 139 | |||
| 140 | ReportStack *stack = ReportStack::New(); | ||
| 141 | stack->frames = top; | ||
| 142 | return stack; | ||
| 143 | } | ||
| 144 | |||
| 145 | ScopedReportBase::ScopedReportBase(ReportType typ, uptr tag) { | ||
| 146 | ctx->thread_registry->CheckLocked(); | ||
| 147 | void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc)); | ||
| 148 | rep_ = new(mem) ReportDesc; | ||
| 149 | rep_->typ = typ; | ||
| 150 | rep_->tag = tag; | ||
| 151 | ctx->report_mtx.Lock(); | ||
| 152 | } | ||
| 153 | |||
| 154 | ScopedReportBase::~ScopedReportBase() { | ||
| 155 | ctx->report_mtx.Unlock(); | ||
| 156 | DestroyAndFree(rep_); | ||
| 157 | rep_ = nullptr; | ||
| 158 | } | ||
| 159 | |||
| 160 | void ScopedReportBase::AddStack(StackTrace stack, bool suppressable) { | ||
| 161 | ReportStack **rs = rep_->stacks.PushBack(); | ||
| 162 | *rs = SymbolizeStack(stack); | ||
| 163 | (*rs)->suppressable = suppressable; | ||
| 164 | } | ||
| 165 | |||
| 166 | void ScopedReportBase::AddMemoryAccess(uptr addr, uptr external_tag, Shadow s, | ||
| 167 | StackTrace stack, const MutexSet *mset) { | ||
| 168 | void *mem = internal_alloc(MBlockReportMop, sizeof(ReportMop)); | ||
| 169 | ReportMop *mop = new(mem) ReportMop; | ||
| 170 | rep_->mops.PushBack(mop); | ||
| 171 | mop->tid = s.tid(); | ||
| 172 | mop->addr = addr + s.addr0(); | ||
| 173 | mop->size = s.size(); | ||
| 174 | mop->write = s.IsWrite(); | ||
| 175 | mop->atomic = s.IsAtomic(); | ||
| 176 | mop->stack = SymbolizeStack(stack); | ||
| 177 | mop->external_tag = external_tag; | ||
| 178 | if (mop->stack) | ||
| 179 | mop->stack->suppressable = true; | ||
| 180 | for (uptr i = 0; i < mset->Size(); i++) { | ||
| 181 | MutexSet::Desc d = mset->Get(i); | ||
| 182 | u64 mid = this->AddMutex(d.id); | ||
| 183 | ReportMopMutex mtx = {mid, d.write}; | ||
| 184 | mop->mset.PushBack(mtx); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | void ScopedReportBase::AddUniqueTid(int unique_tid) { | ||
| 189 | rep_->unique_tids.PushBack(unique_tid); | ||
| 190 | } | ||
| 191 | |||
| 192 | void ScopedReportBase::AddThread(const ThreadContext *tctx, bool suppressable) { | ||
| 193 | for (uptr i = 0; i < rep_->threads.Size(); i++) { | ||
| 194 | if ((u32)rep_->threads[i]->id == tctx->tid) | ||
| 195 | return; | ||
| 196 | } | ||
| 197 | void *mem = internal_alloc(MBlockReportThread, sizeof(ReportThread)); | ||
| 198 | ReportThread *rt = new(mem) ReportThread; | ||
| 199 | rep_->threads.PushBack(rt); | ||
| 200 | rt->id = tctx->tid; | ||
| 201 | rt->os_id = tctx->os_id; | ||
| 202 | rt->running = (tctx->status == ThreadStatusRunning); | ||
| 203 | rt->name = internal_strdup(tctx->name); | ||
| 204 | rt->parent_tid = tctx->parent_tid; | ||
| 205 | rt->thread_type = tctx->thread_type; | ||
| 206 | rt->stack = 0; | ||
| 207 | rt->stack = SymbolizeStackId(tctx->creation_stack_id); | ||
| 208 | if (rt->stack) | ||
| 209 | rt->stack->suppressable = suppressable; | ||
| 210 | } | ||
| 211 | |||
| 212 | #if !SANITIZER_GO | ||
| 213 | static bool FindThreadByUidLockedCallback(ThreadContextBase *tctx, void *arg) { | ||
| 214 | int unique_id = *(int *)arg; | ||
| 215 | return tctx->unique_id == (u32)unique_id; | ||
| 216 | } | ||
| 217 | |||
| 218 | static ThreadContext *FindThreadByUidLocked(int unique_id) { | ||
| 219 | ctx->thread_registry->CheckLocked(); | ||
| 220 | return static_cast<ThreadContext *>( | ||
| 221 | ctx->thread_registry->FindThreadContextLocked( | ||
| 222 | FindThreadByUidLockedCallback, &unique_id)); | ||
| 223 | } | ||
| 224 | |||
| 225 | static ThreadContext *FindThreadByTidLocked(int tid) { | ||
| 226 | ctx->thread_registry->CheckLocked(); | ||
| 227 | return static_cast<ThreadContext*>( | ||
| 228 | ctx->thread_registry->GetThreadLocked(tid)); | ||
| 229 | } | ||
| 230 | |||
| 231 | static bool IsInStackOrTls(ThreadContextBase *tctx_base, void *arg) { | ||
| 232 | uptr addr = (uptr)arg; | ||
| 233 | ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base); | ||
| 234 | if (tctx->status != ThreadStatusRunning) | ||
| 235 | return false; | ||
| 236 | ThreadState *thr = tctx->thr; | ||
| 237 | CHECK(thr); | ||
| 238 | return ((addr >= thr->stk_addr && addr < thr->stk_addr + thr->stk_size) || | ||
| 239 | (addr >= thr->tls_addr && addr < thr->tls_addr + thr->tls_size)); | ||
| 240 | } | ||
| 241 | |||
| 242 | ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack) { | ||
| 243 | ctx->thread_registry->CheckLocked(); | ||
| 244 | ThreadContext *tctx = static_cast<ThreadContext*>( | ||
| 245 | ctx->thread_registry->FindThreadContextLocked(IsInStackOrTls, | ||
| 246 | (void*)addr)); | ||
| 247 | if (!tctx) | ||
| 248 | return 0; | ||
| 249 | ThreadState *thr = tctx->thr; | ||
| 250 | CHECK(thr); | ||
| 251 | *is_stack = (addr >= thr->stk_addr && addr < thr->stk_addr + thr->stk_size); | ||
| 252 | return tctx; | ||
| 253 | } | ||
| 254 | #endif | ||
| 255 | |||
| 256 | void ScopedReportBase::AddThread(int unique_tid, bool suppressable) { | ||
| 257 | #if !SANITIZER_GO | ||
| 258 | if (const ThreadContext *tctx = FindThreadByUidLocked(unique_tid)) | ||
| 259 | AddThread(tctx, suppressable); | ||
| 260 | #endif | ||
| 261 | } | ||
| 262 | |||
| 263 | void ScopedReportBase::AddMutex(const SyncVar *s) { | ||
| 264 | for (uptr i = 0; i < rep_->mutexes.Size(); i++) { | ||
| 265 | if (rep_->mutexes[i]->id == s->uid) | ||
| 266 | return; | ||
| 267 | } | ||
| 268 | void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex)); | ||
| 269 | ReportMutex *rm = new(mem) ReportMutex; | ||
| 270 | rep_->mutexes.PushBack(rm); | ||
| 271 | rm->id = s->uid; | ||
| 272 | rm->addr = s->addr; | ||
| 273 | rm->destroyed = false; | ||
| 274 | rm->stack = SymbolizeStackId(s->creation_stack_id); | ||
| 275 | } | ||
| 276 | |||
| 277 | u64 ScopedReportBase::AddMutex(u64 id) { | ||
| 278 | u64 uid = 0; | ||
| 279 | u64 mid = id; | ||
| 280 | uptr addr = SyncVar::SplitId(id, &uid); | ||
| 281 | SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true); | ||
| 282 | // Check that the mutex is still alive. | ||
| 283 | // Another mutex can be created at the same address, | ||
| 284 | // so check uid as well. | ||
| 285 | if (s && s->CheckId(uid)) { | ||
| 286 | mid = s->uid; | ||
| 287 | AddMutex(s); | ||
| 288 | } else { | ||
| 289 | AddDeadMutex(id); | ||
| 290 | } | ||
| 291 | if (s) | ||
| 292 | s->mtx.Unlock(); | ||
| 293 | return mid; | ||
| 294 | } | ||
| 295 | |||
| 296 | void ScopedReportBase::AddDeadMutex(u64 id) { | ||
| 297 | for (uptr i = 0; i < rep_->mutexes.Size(); i++) { | ||
| 298 | if (rep_->mutexes[i]->id == id) | ||
| 299 | return; | ||
| 300 | } | ||
| 301 | void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex)); | ||
| 302 | ReportMutex *rm = new(mem) ReportMutex; | ||
| 303 | rep_->mutexes.PushBack(rm); | ||
| 304 | rm->id = id; | ||
| 305 | rm->addr = 0; | ||
| 306 | rm->destroyed = true; | ||
| 307 | rm->stack = 0; | ||
| 308 | } | ||
| 309 | |||
| 310 | void ScopedReportBase::AddLocation(uptr addr, uptr size) { | ||
| 311 | if (addr == 0) | ||
| 312 | return; | ||
| 313 | #if !SANITIZER_GO | ||
| 314 | int fd = -1; | ||
| 315 | int creat_tid = kInvalidTid; | ||
| 316 | u32 creat_stack = 0; | ||
| 317 | if (FdLocation(addr, &fd, &creat_tid, &creat_stack)) { | ||
| 318 | ReportLocation *loc = ReportLocation::New(ReportLocationFD); | ||
| 319 | loc->fd = fd; | ||
| 320 | loc->tid = creat_tid; | ||
| 321 | loc->stack = SymbolizeStackId(creat_stack); | ||
| 322 | rep_->locs.PushBack(loc); | ||
| 323 | ThreadContext *tctx = FindThreadByUidLocked(creat_tid); | ||
| 324 | if (tctx) | ||
| 325 | AddThread(tctx); | ||
| 326 | return; | ||
| 327 | } | ||
| 328 | MBlock *b = 0; | ||
| 329 | Allocator *a = allocator(); | ||
| 330 | if (a->PointerIsMine((void*)addr)) { | ||
| 331 | void *block_begin = a->GetBlockBegin((void*)addr); | ||
| 332 | if (block_begin) | ||
| 333 | b = ctx->metamap.GetBlock((uptr)block_begin); | ||
| 334 | } | ||
| 335 | if (b != 0) { | ||
| 336 | ThreadContext *tctx = FindThreadByTidLocked(b->tid); | ||
| 337 | ReportLocation *loc = ReportLocation::New(ReportLocationHeap); | ||
| 338 | loc->heap_chunk_start = (uptr)allocator()->GetBlockBegin((void *)addr); | ||
| 339 | loc->heap_chunk_size = b->siz; | ||
| 340 | loc->external_tag = b->tag; | ||
| 341 | loc->tid = tctx ? tctx->tid : b->tid; | ||
| 342 | loc->stack = SymbolizeStackId(b->stk); | ||
| 343 | rep_->locs.PushBack(loc); | ||
| 344 | if (tctx) | ||
| 345 | AddThread(tctx); | ||
| 346 | return; | ||
| 347 | } | ||
| 348 | bool is_stack = false; | ||
| 349 | if (ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack)) { | ||
| 350 | ReportLocation *loc = | ||
| 351 | ReportLocation::New(is_stack ? ReportLocationStack : ReportLocationTLS); | ||
| 352 | loc->tid = tctx->tid; | ||
| 353 | rep_->locs.PushBack(loc); | ||
| 354 | AddThread(tctx); | ||
| 355 | } | ||
| 356 | #endif | ||
| 357 | if (ReportLocation *loc = SymbolizeData(addr)) { | ||
| 358 | loc->suppressable = true; | ||
| 359 | rep_->locs.PushBack(loc); | ||
| 360 | return; | ||
| 361 | } | ||
| 362 | } | ||
| 363 | |||
| 364 | #if !SANITIZER_GO | ||
| 365 | void ScopedReportBase::AddSleep(u32 stack_id) { | ||
| 366 | rep_->sleep = SymbolizeStackId(stack_id); | ||
| 367 | } | ||
| 368 | #endif | ||
| 369 | |||
| 370 | void ScopedReportBase::SetCount(int count) { rep_->count = count; } | ||
| 371 | |||
| 372 | const ReportDesc *ScopedReportBase::GetReport() const { return rep_; } | ||
| 373 | |||
| 374 | ScopedReport::ScopedReport(ReportType typ, uptr tag) | ||
| 375 | : ScopedReportBase(typ, tag) {} | ||
| 376 | |||
| 377 | ScopedReport::~ScopedReport() {} | ||
| 378 | |||
| 379 | void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk, | ||
| 380 | MutexSet *mset, uptr *tag) { | ||
| 381 | // This function restores stack trace and mutex set for the thread/epoch. | ||
| 382 | // It does so by getting stack trace and mutex set at the beginning of | ||
| 383 | // trace part, and then replaying the trace till the given epoch. | ||
| 384 | Trace* trace = ThreadTrace(tid); | ||
| 385 | ReadLock l(&trace->mtx); | ||
| 386 | const int partidx = (epoch / kTracePartSize) % TraceParts(); | ||
| 387 | TraceHeader* hdr = &trace->headers[partidx]; | ||
| 388 | if (epoch < hdr->epoch0 || epoch >= hdr->epoch0 + kTracePartSize) | ||
| 389 | return; | ||
| 390 | CHECK_EQ(RoundDown(epoch, kTracePartSize), hdr->epoch0); | ||
| 391 | const u64 epoch0 = RoundDown(epoch, TraceSize()); | ||
| 392 | const u64 eend = epoch % TraceSize(); | ||
| 393 | const u64 ebegin = RoundDown(eend, kTracePartSize); | ||
| 394 | DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n", | ||
| 395 | tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx); | ||
| 396 | Vector<uptr> stack; | ||
| 397 | stack.Resize(hdr->stack0.size + 64); | ||
| 398 | for (uptr i = 0; i < hdr->stack0.size; i++) { | ||
| 399 | stack[i] = hdr->stack0.trace[i]; | ||
| 400 | DPrintf2(" #%02zu: pc=%zx\n", i, stack[i]); | ||
| 401 | } | ||
| 402 | if (mset) | ||
| 403 | *mset = hdr->mset0; | ||
| 404 | uptr pos = hdr->stack0.size; | ||
| 405 | Event *events = (Event*)GetThreadTrace(tid); | ||
| 406 | for (uptr i = ebegin; i <= eend; i++) { | ||
| 407 | Event ev = events[i]; | ||
| 408 | EventType typ = (EventType)(ev >> kEventPCBits); | ||
| 409 | uptr pc = (uptr)(ev & ((1ull << kEventPCBits) - 1)); | ||
| 410 | DPrintf2(" %zu typ=%d pc=%zx\n", i, typ, pc); | ||
| 411 | if (typ == EventTypeMop) { | ||
| 412 | stack[pos] = pc; | ||
| 413 | } else if (typ == EventTypeFuncEnter) { | ||
| 414 | if (stack.Size() < pos + 2) | ||
| 415 | stack.Resize(pos + 2); | ||
| 416 | stack[pos++] = pc; | ||
| 417 | } else if (typ == EventTypeFuncExit) { | ||
| 418 | if (pos > 0) | ||
| 419 | pos--; | ||
| 420 | } | ||
| 421 | if (mset) { | ||
| 422 | if (typ == EventTypeLock) { | ||
| 423 | mset->Add(pc, true, epoch0 + i); | ||
| 424 | } else if (typ == EventTypeUnlock) { | ||
| 425 | mset->Del(pc, true); | ||
| 426 | } else if (typ == EventTypeRLock) { | ||
| 427 | mset->Add(pc, false, epoch0 + i); | ||
| 428 | } else if (typ == EventTypeRUnlock) { | ||
| 429 | mset->Del(pc, false); | ||
| 430 | } | ||
| 431 | } | ||
| 432 | for (uptr j = 0; j <= pos; j++) | ||
| 433 | DPrintf2(" #%zu: %zx\n", j, stack[j]); | ||
| 434 | } | ||
| 435 | if (pos == 0 && stack[0] == 0) | ||
| 436 | return; | ||
| 437 | pos++; | ||
| 438 | stk->Init(&stack[0], pos); | ||
| 439 | ExtractTagFromStack(stk, tag); | ||
| 440 | } | ||
| 441 | |||
| 442 | static bool FindRacyStacks(const RacyStacks &hash) { | ||
| 443 | for (uptr i = 0; i < ctx->racy_stacks.Size(); i++) { | ||
| 444 | if (hash == ctx->racy_stacks[i]) { | ||
| 445 | VPrintf(2, "ThreadSanitizer: suppressing report as doubled (stack)\n"); | ||
| 446 | return true; | ||
| 447 | } | ||
| 448 | } | ||
| 449 | return false; | ||
| 450 | } | ||
| 451 | |||
| 452 | static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2]) { | ||
| 453 | if (!flags()->suppress_equal_stacks) | ||
| 454 | return false; | ||
| 455 | RacyStacks hash; | ||
| 456 | hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr)); | ||
| 457 | hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr)); | ||
| 458 | { | ||
| 459 | ReadLock lock(&ctx->racy_mtx); | ||
| 460 | if (FindRacyStacks(hash)) | ||
| 461 | return true; | ||
| 462 | } | ||
| 463 | Lock lock(&ctx->racy_mtx); | ||
| 464 | if (FindRacyStacks(hash)) | ||
| 465 | return true; | ||
| 466 | ctx->racy_stacks.PushBack(hash); | ||
| 467 | return false; | ||
| 468 | } | ||
| 469 | |||
| 470 | static bool FindRacyAddress(const RacyAddress &ra0) { | ||
| 471 | for (uptr i = 0; i < ctx->racy_addresses.Size(); i++) { | ||
| 472 | RacyAddress ra2 = ctx->racy_addresses[i]; | ||
| 473 | uptr maxbeg = max(ra0.addr_min, ra2.addr_min); | ||
| 474 | uptr minend = min(ra0.addr_max, ra2.addr_max); | ||
| 475 | if (maxbeg < minend) { | ||
| 476 | VPrintf(2, "ThreadSanitizer: suppressing report as doubled (addr)\n"); | ||
| 477 | return true; | ||
| 478 | } | ||
| 479 | } | ||
| 480 | return false; | ||
| 481 | } | ||
| 482 | |||
| 483 | static bool HandleRacyAddress(ThreadState *thr, uptr addr_min, uptr addr_max) { | ||
| 484 | if (!flags()->suppress_equal_addresses) | ||
| 485 | return false; | ||
| 486 | RacyAddress ra0 = {addr_min, addr_max}; | ||
| 487 | { | ||
| 488 | ReadLock lock(&ctx->racy_mtx); | ||
| 489 | if (FindRacyAddress(ra0)) | ||
| 490 | return true; | ||
| 491 | } | ||
| 492 | Lock lock(&ctx->racy_mtx); | ||
| 493 | if (FindRacyAddress(ra0)) | ||
| 494 | return true; | ||
| 495 | ctx->racy_addresses.PushBack(ra0); | ||
| 496 | return false; | ||
| 497 | } | ||
| 498 | |||
| 499 | bool OutputReport(ThreadState *thr, const ScopedReport &srep) { | ||
| 500 | if (!flags()->report_bugs || thr->suppress_reports) | ||
| 501 | return false; | ||
| 502 | atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime()); | ||
| 503 | const ReportDesc *rep = srep.GetReport(); | ||
| 504 | CHECK_EQ(thr->current_report, nullptr); | ||
| 505 | thr->current_report = rep; | ||
| 506 | Suppression *supp = 0; | ||
| 507 | uptr pc_or_addr = 0; | ||
| 508 | for (uptr i = 0; pc_or_addr == 0 && i < rep->mops.Size(); i++) | ||
| 509 | pc_or_addr = IsSuppressed(rep->typ, rep->mops[i]->stack, &supp); | ||
| 510 | for (uptr i = 0; pc_or_addr == 0 && i < rep->stacks.Size(); i++) | ||
| 511 | pc_or_addr = IsSuppressed(rep->typ, rep->stacks[i], &supp); | ||
| 512 | for (uptr i = 0; pc_or_addr == 0 && i < rep->threads.Size(); i++) | ||
| 513 | pc_or_addr = IsSuppressed(rep->typ, rep->threads[i]->stack, &supp); | ||
| 514 | for (uptr i = 0; pc_or_addr == 0 && i < rep->locs.Size(); i++) | ||
| 515 | pc_or_addr = IsSuppressed(rep->typ, rep->locs[i], &supp); | ||
| 516 | if (pc_or_addr != 0) { | ||
| 517 | Lock lock(&ctx->fired_suppressions_mtx); | ||
| 518 | FiredSuppression s = {srep.GetReport()->typ, pc_or_addr, supp}; | ||
| 519 | ctx->fired_suppressions.push_back(s); | ||
| 520 | } | ||
| 521 | { | ||
| 522 | bool old_is_freeing = thr->is_freeing; | ||
| 523 | thr->is_freeing = false; | ||
| 524 | bool suppressed = OnReport(rep, pc_or_addr != 0); | ||
| 525 | thr->is_freeing = old_is_freeing; | ||
| 526 | if (suppressed) { | ||
| 527 | thr->current_report = nullptr; | ||
| 528 | return false; | ||
| 529 | } | ||
| 530 | } | ||
| 531 | PrintReport(rep); | ||
| 532 | __tsan_on_report(rep); | ||
| 533 | ctx->nreported++; | ||
| 534 | if (flags()->halt_on_error) | ||
| 535 | Die(); | ||
| 536 | thr->current_report = nullptr; | ||
| 537 | return true; | ||
| 538 | } | ||
| 539 | |||
| 540 | bool IsFiredSuppression(Context *ctx, ReportType type, StackTrace trace) { | ||
| 541 | ReadLock lock(&ctx->fired_suppressions_mtx); | ||
| 542 | for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) { | ||
| 543 | if (ctx->fired_suppressions[k].type != type) | ||
| 544 | continue; | ||
| 545 | for (uptr j = 0; j < trace.size; j++) { | ||
| 546 | FiredSuppression *s = &ctx->fired_suppressions[k]; | ||
| 547 | if (trace.trace[j] == s->pc_or_addr) { | ||
| 548 | if (s->supp) | ||
| 549 | atomic_fetch_add(&s->supp->hit_count, 1, memory_order_relaxed); | ||
| 550 | return true; | ||
| 551 | } | ||
| 552 | } | ||
| 553 | } | ||
| 554 | return false; | ||
| 555 | } | ||
| 556 | |||
| 557 | static bool IsFiredSuppression(Context *ctx, ReportType type, uptr addr) { | ||
| 558 | ReadLock lock(&ctx->fired_suppressions_mtx); | ||
| 559 | for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) { | ||
| 560 | if (ctx->fired_suppressions[k].type != type) | ||
| 561 | continue; | ||
| 562 | FiredSuppression *s = &ctx->fired_suppressions[k]; | ||
| 563 | if (addr == s->pc_or_addr) { | ||
| 564 | if (s->supp) | ||
| 565 | atomic_fetch_add(&s->supp->hit_count, 1, memory_order_relaxed); | ||
| 566 | return true; | ||
| 567 | } | ||
| 568 | } | ||
| 569 | return false; | ||
| 570 | } | ||
| 571 | |||
| 572 | static bool RaceBetweenAtomicAndFree(ThreadState *thr) { | ||
| 573 | Shadow s0(thr->racy_state[0]); | ||
| 574 | Shadow s1(thr->racy_state[1]); | ||
| 575 | CHECK(!(s0.IsAtomic() && s1.IsAtomic())); | ||
| 576 | if (!s0.IsAtomic() && !s1.IsAtomic()) | ||
| 577 | return true; | ||
| 578 | if (s0.IsAtomic() && s1.IsFreed()) | ||
| 579 | return true; | ||
| 580 | if (s1.IsAtomic() && thr->is_freeing) | ||
| 581 | return true; | ||
| 582 | return false; | ||
| 583 | } | ||
| 584 | |||
| 585 | void ReportRace(ThreadState *thr) { | ||
| 586 | CheckNoLocks(thr); | ||
| 587 | |||
| 588 | // Symbolizer makes lots of intercepted calls. If we try to process them, | ||
| 589 | // at best it will cause deadlocks on internal mutexes. | ||
| 590 | ScopedIgnoreInterceptors ignore; | ||
| 591 | |||
| 592 | if (!flags()->report_bugs) | ||
| 593 | return; | ||
| 594 | if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr)) | ||
| 595 | return; | ||
| 596 | |||
| 597 | bool freed = false; | ||
| 598 | { | ||
| 599 | Shadow s(thr->racy_state[1]); | ||
| 600 | freed = s.GetFreedAndReset(); | ||
| 601 | thr->racy_state[1] = s.raw(); | ||
| 602 | } | ||
| 603 | |||
| 604 | uptr addr = ShadowToMem((uptr)thr->racy_shadow_addr); | ||
| 605 | uptr addr_min = 0; | ||
| 606 | uptr addr_max = 0; | ||
| 607 | { | ||
| 608 | uptr a0 = addr + Shadow(thr->racy_state[0]).addr0(); | ||
| 609 | uptr a1 = addr + Shadow(thr->racy_state[1]).addr0(); | ||
| 610 | uptr e0 = a0 + Shadow(thr->racy_state[0]).size(); | ||
| 611 | uptr e1 = a1 + Shadow(thr->racy_state[1]).size(); | ||
| 612 | addr_min = min(a0, a1); | ||
| 613 | addr_max = max(e0, e1); | ||
| 614 | if (IsExpectedReport(addr_min, addr_max - addr_min)) | ||
| 615 | return; | ||
| 616 | } | ||
| 617 | if (HandleRacyAddress(thr, addr_min, addr_max)) | ||
| 618 | return; | ||
| 619 | |||
| 620 | ReportType typ = ReportTypeRace; | ||
| 621 | if (thr->is_vptr_access && freed) | ||
| 622 | typ = ReportTypeVptrUseAfterFree; | ||
| 623 | else if (thr->is_vptr_access) | ||
| 624 | typ = ReportTypeVptrRace; | ||
| 625 | else if (freed) | ||
| 626 | typ = ReportTypeUseAfterFree; | ||
| 627 | |||
| 628 | if (IsFiredSuppression(ctx, typ, addr)) | ||
| 629 | return; | ||
| 630 | |||
| 631 | const uptr kMop = 2; | ||
| 632 | VarSizeStackTrace traces[kMop]; | ||
| 633 | uptr tags[kMop] = {kExternalTagNone}; | ||
| 634 | uptr toppc = TraceTopPC(thr); | ||
| 635 | if (toppc >> kEventPCBits) { | ||
| 636 | // This is a work-around for a known issue. | ||
| 637 | // The scenario where this happens is rather elaborate and requires | ||
| 638 | // an instrumented __sanitizer_report_error_summary callback and | ||
| 639 | // a __tsan_symbolize_external callback and a race during a range memory | ||
| 640 | // access larger than 8 bytes. MemoryAccessRange adds the current PC to | ||
| 641 | // the trace and starts processing memory accesses. A first memory access | ||
| 642 | // triggers a race, we report it and call the instrumented | ||
| 643 | // __sanitizer_report_error_summary, which adds more stuff to the trace | ||
| 644 | // since it is intrumented. Then a second memory access in MemoryAccessRange | ||
| 645 | // also triggers a race and we get here and call TraceTopPC to get the | ||
| 646 | // current PC, however now it contains some unrelated events from the | ||
| 647 | // callback. Most likely, TraceTopPC will now return a EventTypeFuncExit | ||
| 648 | // event. Later we subtract -1 from it (in GetPreviousInstructionPc) | ||
| 649 | // and the resulting PC has kExternalPCBit set, so we pass it to | ||
| 650 | // __tsan_symbolize_external_ex. __tsan_symbolize_external_ex is within its | ||
| 651 | // rights to crash since the PC is completely bogus. | ||
| 652 | // test/tsan/double_race.cpp contains a test case for this. | ||
| 653 | toppc = 0; | ||
| 654 | } | ||
| 655 | ObtainCurrentStack(thr, toppc, &traces[0], &tags[0]); | ||
| 656 | if (IsFiredSuppression(ctx, typ, traces[0])) | ||
| 657 | return; | ||
| 658 | |||
| 659 | // MutexSet is too large to live on stack. | ||
| 660 | Vector<u64> mset_buffer; | ||
| 661 | mset_buffer.Resize(sizeof(MutexSet) / sizeof(u64) + 1); | ||
| 662 | MutexSet *mset2 = new(&mset_buffer[0]) MutexSet(); | ||
| 663 | |||
| 664 | Shadow s2(thr->racy_state[1]); | ||
| 665 | RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2, &tags[1]); | ||
| 666 | if (IsFiredSuppression(ctx, typ, traces[1])) | ||
| 667 | return; | ||
| 668 | |||
| 669 | if (HandleRacyStacks(thr, traces)) | ||
| 670 | return; | ||
| 671 | |||
| 672 | // If any of the accesses has a tag, treat this as an "external" race. | ||
| 673 | uptr tag = kExternalTagNone; | ||
| 674 | for (uptr i = 0; i < kMop; i++) { | ||
| 675 | if (tags[i] != kExternalTagNone) { | ||
| 676 | typ = ReportTypeExternalRace; | ||
| 677 | tag = tags[i]; | ||
| 678 | break; | ||
| 679 | } | ||
| 680 | } | ||
| 681 | |||
| 682 | ThreadRegistryLock l0(ctx->thread_registry); | ||
| 683 | ScopedReport rep(typ, tag); | ||
| 684 | for (uptr i = 0; i < kMop; i++) { | ||
| 685 | Shadow s(thr->racy_state[i]); | ||
| 686 | rep.AddMemoryAccess(addr, tags[i], s, traces[i], | ||
| 687 | i == 0 ? &thr->mset : mset2); | ||
| 688 | } | ||
| 689 | |||
| 690 | for (uptr i = 0; i < kMop; i++) { | ||
| 691 | FastState s(thr->racy_state[i]); | ||
| 692 | ThreadContext *tctx = static_cast<ThreadContext*>( | ||
| 693 | ctx->thread_registry->GetThreadLocked(s.tid())); | ||
| 694 | if (s.epoch() < tctx->epoch0 || s.epoch() > tctx->epoch1) | ||
| 695 | continue; | ||
| 696 | rep.AddThread(tctx); | ||
| 697 | } | ||
| 698 | |||
| 699 | rep.AddLocation(addr_min, addr_max - addr_min); | ||
| 700 | |||
| 701 | #if !SANITIZER_GO | ||
| 702 | { | ||
| 703 | Shadow s(thr->racy_state[1]); | ||
| 704 | if (s.epoch() <= thr->last_sleep_clock.get(s.tid())) | ||
| 705 | rep.AddSleep(thr->last_sleep_stack_id); | ||
| 706 | } | ||
| 707 | #endif | ||
| 708 | |||
| 709 | if (!OutputReport(thr, rep)) | ||
| 710 | return; | ||
| 711 | |||
| 712 | } | ||
| 713 | |||
| 714 | void PrintCurrentStack(ThreadState *thr, uptr pc) { | ||
| 715 | VarSizeStackTrace trace; | ||
| 716 | ObtainCurrentStack(thr, pc, &trace); | ||
| 717 | PrintStack(SymbolizeStack(trace)); | ||
| 718 | } | ||
| 719 | |||
| 720 | // Always inlining PrintCurrentStackSlow, because LocatePcInTrace assumes | ||
| 721 | // __sanitizer_print_stack_trace exists in the actual unwinded stack, but | ||
| 722 | // tail-call to PrintCurrentStackSlow breaks this assumption because | ||
| 723 | // __sanitizer_print_stack_trace disappears after tail-call. | ||
| 724 | // However, this solution is not reliable enough, please see dvyukov's comment | ||
| 725 | // http://reviews.llvm.org/D19148#406208 | ||
| 726 | // Also see PR27280 comment 2 and 3 for breaking examples and analysis. | ||
| 727 | ALWAYS_INLINE | ||
| 728 | void PrintCurrentStackSlow(uptr pc) { | ||
| 729 | #if !SANITIZER_GO | ||
| 730 | uptr bp = GET_CURRENT_FRAME(); | ||
| 731 | BufferedStackTrace *ptrace = | ||
| 732 | new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace))) | ||
| 733 | BufferedStackTrace(); | ||
| 734 | ptrace->Unwind(pc, bp, nullptr, false); | ||
| 735 | |||
| 736 | for (uptr i = 0; i < ptrace->size / 2; i++) { | ||
| 737 | uptr tmp = ptrace->trace_buffer[i]; | ||
| 738 | ptrace->trace_buffer[i] = ptrace->trace_buffer[ptrace->size - i - 1]; | ||
| 739 | ptrace->trace_buffer[ptrace->size - i - 1] = tmp; | ||
| 740 | } | ||
| 741 | PrintStack(SymbolizeStack(*ptrace)); | ||
| 742 | #endif | ||
| 743 | } | ||
| 744 | |||
| 745 | } // namespace __tsan | ||
| 746 | |||
| 747 | using namespace __tsan; | ||
| 748 | |||
| 749 | extern "C" { | ||
| 750 | SANITIZER_INTERFACE_ATTRIBUTE | ||
| 751 | void __sanitizer_print_stack_trace() { | ||
| 752 | PrintCurrentStackSlow(StackTrace::GetCurrentPc()); | ||
| 753 | } | ||
| 754 | } // extern "C" | ||
lib/tsan/tsan_rtl_thread.cpp created+462| ... | @@ -0,0 +1,462 @@ | ||
| 1 | //===-- tsan_rtl_thread.cpp -----------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_common/sanitizer_placement_new.h" | ||
| 14 | #include "tsan_rtl.h" | ||
| 15 | #include "tsan_mman.h" | ||
| 16 | #include "tsan_platform.h" | ||
| 17 | #include "tsan_report.h" | ||
| 18 | #include "tsan_sync.h" | ||
| 19 | |||
| 20 | namespace __tsan { | ||
| 21 | |||
| 22 | // ThreadContext implementation. | ||
| 23 | |||
| 24 | ThreadContext::ThreadContext(int tid) | ||
| 25 | : ThreadContextBase(tid) | ||
| 26 | , thr() | ||
| 27 | , sync() | ||
| 28 | , epoch0() | ||
| 29 | , epoch1() { | ||
| 30 | } | ||
| 31 | |||
| 32 | #if !SANITIZER_GO | ||
| 33 | ThreadContext::~ThreadContext() { | ||
| 34 | } | ||
| 35 | #endif | ||
| 36 | |||
| 37 | void ThreadContext::OnDead() { | ||
| 38 | CHECK_EQ(sync.size(), 0); | ||
| 39 | } | ||
| 40 | |||
| 41 | void ThreadContext::OnJoined(void *arg) { | ||
| 42 | ThreadState *caller_thr = static_cast<ThreadState *>(arg); | ||
| 43 | AcquireImpl(caller_thr, 0, &sync); | ||
| 44 | sync.Reset(&caller_thr->proc()->clock_cache); | ||
| 45 | } | ||
| 46 | |||
| 47 | struct OnCreatedArgs { | ||
| 48 | ThreadState *thr; | ||
| 49 | uptr pc; | ||
| 50 | }; | ||
| 51 | |||
| 52 | void ThreadContext::OnCreated(void *arg) { | ||
| 53 | thr = 0; | ||
| 54 | if (tid == 0) | ||
| 55 | return; | ||
| 56 | OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg); | ||
| 57 | if (!args->thr) // GCD workers don't have a parent thread. | ||
| 58 | return; | ||
| 59 | args->thr->fast_state.IncrementEpoch(); | ||
| 60 | // Can't increment epoch w/o writing to the trace as well. | ||
| 61 | TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0); | ||
| 62 | ReleaseImpl(args->thr, 0, &sync); | ||
| 63 | creation_stack_id = CurrentStackId(args->thr, args->pc); | ||
| 64 | if (reuse_count == 0) | ||
| 65 | StatInc(args->thr, StatThreadMaxTid); | ||
| 66 | } | ||
| 67 | |||
| 68 | void ThreadContext::OnReset() { | ||
| 69 | CHECK_EQ(sync.size(), 0); | ||
| 70 | uptr trace_p = GetThreadTrace(tid); | ||
| 71 | ReleaseMemoryPagesToOS(trace_p, trace_p + TraceSize() * sizeof(Event)); | ||
| 72 | //!!! ReleaseMemoryToOS(GetThreadTraceHeader(tid), sizeof(Trace)); | ||
| 73 | } | ||
| 74 | |||
| 75 | void ThreadContext::OnDetached(void *arg) { | ||
| 76 | ThreadState *thr1 = static_cast<ThreadState*>(arg); | ||
| 77 | sync.Reset(&thr1->proc()->clock_cache); | ||
| 78 | } | ||
| 79 | |||
| 80 | struct OnStartedArgs { | ||
| 81 | ThreadState *thr; | ||
| 82 | uptr stk_addr; | ||
| 83 | uptr stk_size; | ||
| 84 | uptr tls_addr; | ||
| 85 | uptr tls_size; | ||
| 86 | }; | ||
| 87 | |||
| 88 | void ThreadContext::OnStarted(void *arg) { | ||
| 89 | OnStartedArgs *args = static_cast<OnStartedArgs*>(arg); | ||
| 90 | thr = args->thr; | ||
| 91 | // RoundUp so that one trace part does not contain events | ||
| 92 | // from different threads. | ||
| 93 | epoch0 = RoundUp(epoch1 + 1, kTracePartSize); | ||
| 94 | epoch1 = (u64)-1; | ||
| 95 | new(thr) ThreadState(ctx, tid, unique_id, epoch0, reuse_count, | ||
| 96 | args->stk_addr, args->stk_size, args->tls_addr, args->tls_size); | ||
| 97 | #if !SANITIZER_GO | ||
| 98 | thr->shadow_stack = &ThreadTrace(thr->tid)->shadow_stack[0]; | ||
| 99 | thr->shadow_stack_pos = thr->shadow_stack; | ||
| 100 | thr->shadow_stack_end = thr->shadow_stack + kShadowStackSize; | ||
| 101 | #else | ||
| 102 | // Setup dynamic shadow stack. | ||
| 103 | const int kInitStackSize = 8; | ||
| 104 | thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack, | ||
| 105 | kInitStackSize * sizeof(uptr)); | ||
| 106 | thr->shadow_stack_pos = thr->shadow_stack; | ||
| 107 | thr->shadow_stack_end = thr->shadow_stack + kInitStackSize; | ||
| 108 | #endif | ||
| 109 | if (common_flags()->detect_deadlocks) | ||
| 110 | thr->dd_lt = ctx->dd->CreateLogicalThread(unique_id); | ||
| 111 | thr->fast_state.SetHistorySize(flags()->history_size); | ||
| 112 | // Commit switch to the new part of the trace. | ||
| 113 | // TraceAddEvent will reset stack0/mset0 in the new part for us. | ||
| 114 | TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); | ||
| 115 | |||
| 116 | thr->fast_synch_epoch = epoch0; | ||
| 117 | AcquireImpl(thr, 0, &sync); | ||
| 118 | StatInc(thr, StatSyncAcquire); | ||
| 119 | sync.Reset(&thr->proc()->clock_cache); | ||
| 120 | thr->is_inited = true; | ||
| 121 | DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx " | ||
| 122 | "tls_addr=%zx tls_size=%zx\n", | ||
| 123 | tid, (uptr)epoch0, args->stk_addr, args->stk_size, | ||
| 124 | args->tls_addr, args->tls_size); | ||
| 125 | } | ||
| 126 | |||
| 127 | void ThreadContext::OnFinished() { | ||
| 128 | #if SANITIZER_GO | ||
| 129 | internal_free(thr->shadow_stack); | ||
| 130 | thr->shadow_stack = nullptr; | ||
| 131 | thr->shadow_stack_pos = nullptr; | ||
| 132 | thr->shadow_stack_end = nullptr; | ||
| 133 | #endif | ||
| 134 | if (!detached) { | ||
| 135 | thr->fast_state.IncrementEpoch(); | ||
| 136 | // Can't increment epoch w/o writing to the trace as well. | ||
| 137 | TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); | ||
| 138 | ReleaseImpl(thr, 0, &sync); | ||
| 139 | } | ||
| 140 | epoch1 = thr->fast_state.epoch(); | ||
| 141 | |||
| 142 | if (common_flags()->detect_deadlocks) | ||
| 143 | ctx->dd->DestroyLogicalThread(thr->dd_lt); | ||
| 144 | thr->clock.ResetCached(&thr->proc()->clock_cache); | ||
| 145 | #if !SANITIZER_GO | ||
| 146 | thr->last_sleep_clock.ResetCached(&thr->proc()->clock_cache); | ||
| 147 | #endif | ||
| 148 | #if !SANITIZER_GO | ||
| 149 | PlatformCleanUpThreadState(thr); | ||
| 150 | #endif | ||
| 151 | thr->~ThreadState(); | ||
| 152 | #if TSAN_COLLECT_STATS | ||
| 153 | StatAggregate(ctx->stat, thr->stat); | ||
| 154 | #endif | ||
| 155 | thr = 0; | ||
| 156 | } | ||
| 157 | |||
| 158 | #if !SANITIZER_GO | ||
| 159 | struct ThreadLeak { | ||
| 160 | ThreadContext *tctx; | ||
| 161 | int count; | ||
| 162 | }; | ||
| 163 | |||
| 164 | static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) { | ||
| 165 | Vector<ThreadLeak> &leaks = *(Vector<ThreadLeak>*)arg; | ||
| 166 | ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base); | ||
| 167 | if (tctx->detached || tctx->status != ThreadStatusFinished) | ||
| 168 | return; | ||
| 169 | for (uptr i = 0; i < leaks.Size(); i++) { | ||
| 170 | if (leaks[i].tctx->creation_stack_id == tctx->creation_stack_id) { | ||
| 171 | leaks[i].count++; | ||
| 172 | return; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | ThreadLeak leak = {tctx, 1}; | ||
| 176 | leaks.PushBack(leak); | ||
| 177 | } | ||
| 178 | #endif | ||
| 179 | |||
| 180 | #if !SANITIZER_GO | ||
| 181 | static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) { | ||
| 182 | if (tctx->tid == 0) { | ||
| 183 | Printf("ThreadSanitizer: main thread finished with ignores enabled\n"); | ||
| 184 | } else { | ||
| 185 | Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled," | ||
| 186 | " created at:\n", tctx->tid, tctx->name); | ||
| 187 | PrintStack(SymbolizeStackId(tctx->creation_stack_id)); | ||
| 188 | } | ||
| 189 | Printf(" One of the following ignores was not ended" | ||
| 190 | " (in order of probability)\n"); | ||
| 191 | for (uptr i = 0; i < set->Size(); i++) { | ||
| 192 | Printf(" Ignore was enabled at:\n"); | ||
| 193 | PrintStack(SymbolizeStackId(set->At(i))); | ||
| 194 | } | ||
| 195 | Die(); | ||
| 196 | } | ||
| 197 | |||
| 198 | static void ThreadCheckIgnore(ThreadState *thr) { | ||
| 199 | if (ctx->after_multithreaded_fork) | ||
| 200 | return; | ||
| 201 | if (thr->ignore_reads_and_writes) | ||
| 202 | ReportIgnoresEnabled(thr->tctx, &thr->mop_ignore_set); | ||
| 203 | if (thr->ignore_sync) | ||
| 204 | ReportIgnoresEnabled(thr->tctx, &thr->sync_ignore_set); | ||
| 205 | } | ||
| 206 | #else | ||
| 207 | static void ThreadCheckIgnore(ThreadState *thr) {} | ||
| 208 | #endif | ||
| 209 | |||
| 210 | void ThreadFinalize(ThreadState *thr) { | ||
| 211 | ThreadCheckIgnore(thr); | ||
| 212 | #if !SANITIZER_GO | ||
| 213 | if (!flags()->report_thread_leaks) | ||
| 214 | return; | ||
| 215 | ThreadRegistryLock l(ctx->thread_registry); | ||
| 216 | Vector<ThreadLeak> leaks; | ||
| 217 | ctx->thread_registry->RunCallbackForEachThreadLocked( | ||
| 218 | MaybeReportThreadLeak, &leaks); | ||
| 219 | for (uptr i = 0; i < leaks.Size(); i++) { | ||
| 220 | ScopedReport rep(ReportTypeThreadLeak); | ||
| 221 | rep.AddThread(leaks[i].tctx, true); | ||
| 222 | rep.SetCount(leaks[i].count); | ||
| 223 | OutputReport(thr, rep); | ||
| 224 | } | ||
| 225 | #endif | ||
| 226 | } | ||
| 227 | |||
| 228 | int ThreadCount(ThreadState *thr) { | ||
| 229 | uptr result; | ||
| 230 | ctx->thread_registry->GetNumberOfThreads(0, 0, &result); | ||
| 231 | return (int)result; | ||
| 232 | } | ||
| 233 | |||
| 234 | int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) { | ||
| 235 | StatInc(thr, StatThreadCreate); | ||
| 236 | OnCreatedArgs args = { thr, pc }; | ||
| 237 | u32 parent_tid = thr ? thr->tid : kInvalidTid; // No parent for GCD workers. | ||
| 238 | int tid = | ||
| 239 | ctx->thread_registry->CreateThread(uid, detached, parent_tid, &args); | ||
| 240 | DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", parent_tid, tid, uid); | ||
| 241 | StatSet(thr, StatThreadMaxAlive, ctx->thread_registry->GetMaxAliveThreads()); | ||
| 242 | return tid; | ||
| 243 | } | ||
| 244 | |||
| 245 | void ThreadStart(ThreadState *thr, int tid, tid_t os_id, | ||
| 246 | ThreadType thread_type) { | ||
| 247 | uptr stk_addr = 0; | ||
| 248 | uptr stk_size = 0; | ||
| 249 | uptr tls_addr = 0; | ||
| 250 | uptr tls_size = 0; | ||
| 251 | #if !SANITIZER_GO | ||
| 252 | if (thread_type != ThreadType::Fiber) | ||
| 253 | GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size); | ||
| 254 | |||
| 255 | if (tid) { | ||
| 256 | if (stk_addr && stk_size) | ||
| 257 | MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size); | ||
| 258 | |||
| 259 | if (tls_addr && tls_size) ImitateTlsWrite(thr, tls_addr, tls_size); | ||
| 260 | } | ||
| 261 | #endif | ||
| 262 | |||
| 263 | ThreadRegistry *tr = ctx->thread_registry; | ||
| 264 | OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size }; | ||
| 265 | tr->StartThread(tid, os_id, thread_type, &args); | ||
| 266 | |||
| 267 | tr->Lock(); | ||
| 268 | thr->tctx = (ThreadContext*)tr->GetThreadLocked(tid); | ||
| 269 | tr->Unlock(); | ||
| 270 | |||
| 271 | #if !SANITIZER_GO | ||
| 272 | if (ctx->after_multithreaded_fork) { | ||
| 273 | thr->ignore_interceptors++; | ||
| 274 | ThreadIgnoreBegin(thr, 0); | ||
| 275 | ThreadIgnoreSyncBegin(thr, 0); | ||
| 276 | } | ||
| 277 | #endif | ||
| 278 | } | ||
| 279 | |||
| 280 | void ThreadFinish(ThreadState *thr) { | ||
| 281 | ThreadCheckIgnore(thr); | ||
| 282 | StatInc(thr, StatThreadFinish); | ||
| 283 | if (thr->stk_addr && thr->stk_size) | ||
| 284 | DontNeedShadowFor(thr->stk_addr, thr->stk_size); | ||
| 285 | if (thr->tls_addr && thr->tls_size) | ||
| 286 | DontNeedShadowFor(thr->tls_addr, thr->tls_size); | ||
| 287 | thr->is_dead = true; | ||
| 288 | ctx->thread_registry->FinishThread(thr->tid); | ||
| 289 | } | ||
| 290 | |||
| 291 | struct ConsumeThreadContext { | ||
| 292 | uptr uid; | ||
| 293 | ThreadContextBase *tctx; | ||
| 294 | }; | ||
| 295 | |||
| 296 | static bool ConsumeThreadByUid(ThreadContextBase *tctx, void *arg) { | ||
| 297 | ConsumeThreadContext *findCtx = (ConsumeThreadContext *)arg; | ||
| 298 | if (tctx->user_id == findCtx->uid && tctx->status != ThreadStatusInvalid) { | ||
| 299 | if (findCtx->tctx) { | ||
| 300 | // Ensure that user_id is unique. If it's not the case we are screwed. | ||
| 301 | // Something went wrong before, but now there is no way to recover. | ||
| 302 | // Returning a wrong thread is not an option, it may lead to very hard | ||
| 303 | // to debug false positives (e.g. if we join a wrong thread). | ||
| 304 | Report("ThreadSanitizer: dup thread with used id 0x%zx\n", findCtx->uid); | ||
| 305 | Die(); | ||
| 306 | } | ||
| 307 | findCtx->tctx = tctx; | ||
| 308 | tctx->user_id = 0; | ||
| 309 | } | ||
| 310 | return false; | ||
| 311 | } | ||
| 312 | |||
| 313 | int ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid) { | ||
| 314 | ConsumeThreadContext findCtx = {uid, nullptr}; | ||
| 315 | ctx->thread_registry->FindThread(ConsumeThreadByUid, &findCtx); | ||
| 316 | int tid = findCtx.tctx ? findCtx.tctx->tid : ThreadRegistry::kUnknownTid; | ||
| 317 | DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, tid); | ||
| 318 | return tid; | ||
| 319 | } | ||
| 320 | |||
| 321 | void ThreadJoin(ThreadState *thr, uptr pc, int tid) { | ||
| 322 | CHECK_GT(tid, 0); | ||
| 323 | CHECK_LT(tid, kMaxTid); | ||
| 324 | DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid); | ||
| 325 | ctx->thread_registry->JoinThread(tid, thr); | ||
| 326 | } | ||
| 327 | |||
| 328 | void ThreadDetach(ThreadState *thr, uptr pc, int tid) { | ||
| 329 | CHECK_GT(tid, 0); | ||
| 330 | CHECK_LT(tid, kMaxTid); | ||
| 331 | ctx->thread_registry->DetachThread(tid, thr); | ||
| 332 | } | ||
| 333 | |||
| 334 | void ThreadNotJoined(ThreadState *thr, uptr pc, int tid, uptr uid) { | ||
| 335 | CHECK_GT(tid, 0); | ||
| 336 | CHECK_LT(tid, kMaxTid); | ||
| 337 | ctx->thread_registry->SetThreadUserId(tid, uid); | ||
| 338 | } | ||
| 339 | |||
| 340 | void ThreadSetName(ThreadState *thr, const char *name) { | ||
| 341 | ctx->thread_registry->SetThreadName(thr->tid, name); | ||
| 342 | } | ||
| 343 | |||
| 344 | void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, | ||
| 345 | uptr size, bool is_write) { | ||
| 346 | if (size == 0) | ||
| 347 | return; | ||
| 348 | |||
| 349 | u64 *shadow_mem = (u64*)MemToShadow(addr); | ||
| 350 | DPrintf2("#%d: MemoryAccessRange: @%p %p size=%d is_write=%d\n", | ||
| 351 | thr->tid, (void*)pc, (void*)addr, | ||
| 352 | (int)size, is_write); | ||
| 353 | |||
| 354 | #if SANITIZER_DEBUG | ||
| 355 | if (!IsAppMem(addr)) { | ||
| 356 | Printf("Access to non app mem %zx\n", addr); | ||
| 357 | DCHECK(IsAppMem(addr)); | ||
| 358 | } | ||
| 359 | if (!IsAppMem(addr + size - 1)) { | ||
| 360 | Printf("Access to non app mem %zx\n", addr + size - 1); | ||
| 361 | DCHECK(IsAppMem(addr + size - 1)); | ||
| 362 | } | ||
| 363 | if (!IsShadowMem((uptr)shadow_mem)) { | ||
| 364 | Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr); | ||
| 365 | DCHECK(IsShadowMem((uptr)shadow_mem)); | ||
| 366 | } | ||
| 367 | if (!IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1))) { | ||
| 368 | Printf("Bad shadow addr %p (%zx)\n", | ||
| 369 | shadow_mem + size * kShadowCnt / 8 - 1, addr + size - 1); | ||
| 370 | DCHECK(IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1))); | ||
| 371 | } | ||
| 372 | #endif | ||
| 373 | |||
| 374 | StatInc(thr, StatMopRange); | ||
| 375 | |||
| 376 | if (*shadow_mem == kShadowRodata) { | ||
| 377 | DCHECK(!is_write); | ||
| 378 | // Access to .rodata section, no races here. | ||
| 379 | // Measurements show that it can be 10-20% of all memory accesses. | ||
| 380 | StatInc(thr, StatMopRangeRodata); | ||
| 381 | return; | ||
| 382 | } | ||
| 383 | |||
| 384 | FastState fast_state = thr->fast_state; | ||
| 385 | if (fast_state.GetIgnoreBit()) | ||
| 386 | return; | ||
| 387 | |||
| 388 | fast_state.IncrementEpoch(); | ||
| 389 | thr->fast_state = fast_state; | ||
| 390 | TraceAddEvent(thr, fast_state, EventTypeMop, pc); | ||
| 391 | |||
| 392 | bool unaligned = (addr % kShadowCell) != 0; | ||
| 393 | |||
| 394 | // Handle unaligned beginning, if any. | ||
| 395 | for (; addr % kShadowCell && size; addr++, size--) { | ||
| 396 | int const kAccessSizeLog = 0; | ||
| 397 | Shadow cur(fast_state); | ||
| 398 | cur.SetWrite(is_write); | ||
| 399 | cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog); | ||
| 400 | MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false, | ||
| 401 | shadow_mem, cur); | ||
| 402 | } | ||
| 403 | if (unaligned) | ||
| 404 | shadow_mem += kShadowCnt; | ||
| 405 | // Handle middle part, if any. | ||
| 406 | for (; size >= kShadowCell; addr += kShadowCell, size -= kShadowCell) { | ||
| 407 | int const kAccessSizeLog = 3; | ||
| 408 | Shadow cur(fast_state); | ||
| 409 | cur.SetWrite(is_write); | ||
| 410 | cur.SetAddr0AndSizeLog(0, kAccessSizeLog); | ||
| 411 | MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false, | ||
| 412 | shadow_mem, cur); | ||
| 413 | shadow_mem += kShadowCnt; | ||
| 414 | } | ||
| 415 | // Handle ending, if any. | ||
| 416 | for (; size; addr++, size--) { | ||
| 417 | int const kAccessSizeLog = 0; | ||
| 418 | Shadow cur(fast_state); | ||
| 419 | cur.SetWrite(is_write); | ||
| 420 | cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog); | ||
| 421 | MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false, | ||
| 422 | shadow_mem, cur); | ||
| 423 | } | ||
| 424 | } | ||
| 425 | |||
| 426 | #if !SANITIZER_GO | ||
| 427 | void FiberSwitchImpl(ThreadState *from, ThreadState *to) { | ||
| 428 | Processor *proc = from->proc(); | ||
| 429 | ProcUnwire(proc, from); | ||
| 430 | ProcWire(proc, to); | ||
| 431 | set_cur_thread(to); | ||
| 432 | } | ||
| 433 | |||
| 434 | ThreadState *FiberCreate(ThreadState *thr, uptr pc, unsigned flags) { | ||
| 435 | void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadState)); | ||
| 436 | ThreadState *fiber = static_cast<ThreadState *>(mem); | ||
| 437 | internal_memset(fiber, 0, sizeof(*fiber)); | ||
| 438 | int tid = ThreadCreate(thr, pc, 0, true); | ||
| 439 | FiberSwitchImpl(thr, fiber); | ||
| 440 | ThreadStart(fiber, tid, 0, ThreadType::Fiber); | ||
| 441 | FiberSwitchImpl(fiber, thr); | ||
| 442 | return fiber; | ||
| 443 | } | ||
| 444 | |||
| 445 | void FiberDestroy(ThreadState *thr, uptr pc, ThreadState *fiber) { | ||
| 446 | FiberSwitchImpl(thr, fiber); | ||
| 447 | ThreadFinish(fiber); | ||
| 448 | FiberSwitchImpl(fiber, thr); | ||
| 449 | internal_free(fiber); | ||
| 450 | } | ||
| 451 | |||
| 452 | void FiberSwitch(ThreadState *thr, uptr pc, | ||
| 453 | ThreadState *fiber, unsigned flags) { | ||
| 454 | if (!(flags & FiberSwitchFlagNoSync)) | ||
| 455 | Release(thr, pc, (uptr)fiber); | ||
| 456 | FiberSwitchImpl(thr, fiber); | ||
| 457 | if (!(flags & FiberSwitchFlagNoSync)) | ||
| 458 | Acquire(fiber, pc, (uptr)fiber); | ||
| 459 | } | ||
| 460 | #endif | ||
| 461 | |||
| 462 | } // namespace __tsan | ||
lib/tsan/tsan_stack_trace.cpp created+63| ... | @@ -0,0 +1,63 @@ | ||
| 1 | //===-- tsan_stack_trace.cpp ----------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #include "tsan_stack_trace.h" | ||
| 13 | #include "tsan_rtl.h" | ||
| 14 | #include "tsan_mman.h" | ||
| 15 | |||
| 16 | namespace __tsan { | ||
| 17 | |||
| 18 | VarSizeStackTrace::VarSizeStackTrace() | ||
| 19 | : StackTrace(nullptr, 0), trace_buffer(nullptr) {} | ||
| 20 | |||
| 21 | VarSizeStackTrace::~VarSizeStackTrace() { | ||
| 22 | ResizeBuffer(0); | ||
| 23 | } | ||
| 24 | |||
| 25 | void VarSizeStackTrace::ResizeBuffer(uptr new_size) { | ||
| 26 | if (trace_buffer) { | ||
| 27 | internal_free(trace_buffer); | ||
| 28 | } | ||
| 29 | trace_buffer = | ||
| 30 | (new_size > 0) | ||
| 31 | ? (uptr *)internal_alloc(MBlockStackTrace, | ||
| 32 | new_size * sizeof(trace_buffer[0])) | ||
| 33 | : nullptr; | ||
| 34 | trace = trace_buffer; | ||
| 35 | size = new_size; | ||
| 36 | } | ||
| 37 | |||
| 38 | void VarSizeStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) { | ||
| 39 | ResizeBuffer(cnt + !!extra_top_pc); | ||
| 40 | internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0])); | ||
| 41 | if (extra_top_pc) | ||
| 42 | trace_buffer[cnt] = extra_top_pc; | ||
| 43 | } | ||
| 44 | |||
| 45 | void VarSizeStackTrace::ReverseOrder() { | ||
| 46 | for (u32 i = 0; i < (size >> 1); i++) | ||
| 47 | Swap(trace_buffer[i], trace_buffer[size - 1 - i]); | ||
| 48 | } | ||
| 49 | |||
| 50 | } // namespace __tsan | ||
| 51 | |||
| 52 | #if !SANITIZER_GO | ||
| 53 | void __sanitizer::BufferedStackTrace::UnwindImpl( | ||
| 54 | uptr pc, uptr bp, void *context, bool request_fast, u32 max_depth) { | ||
| 55 | uptr top = 0; | ||
| 56 | uptr bottom = 0; | ||
| 57 | if (StackTrace::WillUseFastUnwind(request_fast)) { | ||
| 58 | GetThreadStackTopAndBottom(false, &top, &bottom); | ||
| 59 | Unwind(max_depth, pc, bp, nullptr, top, bottom, true); | ||
| 60 | } else | ||
| 61 | Unwind(max_depth, pc, 0, context, 0, 0, false); | ||
| 62 | } | ||
| 63 | #endif // SANITIZER_GO | ||
lib/tsan/tsan_stack_trace.h created+42| ... | @@ -0,0 +1,42 @@ | ||
| 1 | //===-- tsan_stack_trace.h --------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef TSAN_STACK_TRACE_H | ||
| 13 | #define TSAN_STACK_TRACE_H | ||
| 14 | |||
| 15 | #include "sanitizer_common/sanitizer_stacktrace.h" | ||
| 16 | #include "tsan_defs.h" | ||
| 17 | |||
| 18 | namespace __tsan { | ||
| 19 | |||
| 20 | // StackTrace which calls malloc/free to allocate the buffer for | ||
| 21 | // addresses in stack traces. | ||
| 22 | struct VarSizeStackTrace : public StackTrace { | ||
| 23 | uptr *trace_buffer; // Owned. | ||
| 24 | |||
| 25 | VarSizeStackTrace(); | ||
| 26 | ~VarSizeStackTrace(); | ||
| 27 | void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0); | ||
| 28 | |||
| 29 | // Reverses the current stack trace order, the top frame goes to the bottom, | ||
| 30 | // the last frame goes to the top. | ||
| 31 | void ReverseOrder(); | ||
| 32 | |||
| 33 | private: | ||
| 34 | void ResizeBuffer(uptr new_size); | ||
| 35 | |||
| 36 | VarSizeStackTrace(const VarSizeStackTrace &); | ||
| 37 | void operator=(const VarSizeStackTrace &); | ||
| 38 | }; | ||
| 39 | |||
| 40 | } // namespace __tsan | ||
| 41 | |||
| 42 | #endif // TSAN_STACK_TRACE_H | ||
lib/tsan/tsan_stat.cpp created+186| ... | @@ -0,0 +1,186 @@ | ||
| 1 | //===-- tsan_stat.cpp -----------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #include "tsan_stat.h" | ||
| 13 | #include "tsan_rtl.h" | ||
| 14 | |||
| 15 | namespace __tsan { | ||
| 16 | |||
| 17 | #if TSAN_COLLECT_STATS | ||
| 18 | |||
| 19 | void StatAggregate(u64 *dst, u64 *src) { | ||
| 20 | for (int i = 0; i < StatCnt; i++) | ||
| 21 | dst[i] += src[i]; | ||
| 22 | } | ||
| 23 | |||
| 24 | void StatOutput(u64 *stat) { | ||
| 25 | stat[StatShadowNonZero] = stat[StatShadowProcessed] - stat[StatShadowZero]; | ||
| 26 | |||
| 27 | static const char *name[StatCnt] = {}; | ||
| 28 | name[StatMop] = "Memory accesses "; | ||
| 29 | name[StatMopRead] = " Including reads "; | ||
| 30 | name[StatMopWrite] = " writes "; | ||
| 31 | name[StatMop1] = " Including size 1 "; | ||
| 32 | name[StatMop2] = " size 2 "; | ||
| 33 | name[StatMop4] = " size 4 "; | ||
| 34 | name[StatMop8] = " size 8 "; | ||
| 35 | name[StatMopSame] = " Including same "; | ||
| 36 | name[StatMopIgnored] = " Including ignored "; | ||
| 37 | name[StatMopRange] = " Including range "; | ||
| 38 | name[StatMopRodata] = " Including .rodata "; | ||
| 39 | name[StatMopRangeRodata] = " Including .rodata range "; | ||
| 40 | name[StatShadowProcessed] = "Shadow processed "; | ||
| 41 | name[StatShadowZero] = " Including empty "; | ||
| 42 | name[StatShadowNonZero] = " Including non empty "; | ||
| 43 | name[StatShadowSameSize] = " Including same size "; | ||
| 44 | name[StatShadowIntersect] = " intersect "; | ||
| 45 | name[StatShadowNotIntersect] = " not intersect "; | ||
| 46 | name[StatShadowSameThread] = " Including same thread "; | ||
| 47 | name[StatShadowAnotherThread] = " another thread "; | ||
| 48 | name[StatShadowReplace] = " Including evicted "; | ||
| 49 | |||
| 50 | name[StatFuncEnter] = "Function entries "; | ||
| 51 | name[StatFuncExit] = "Function exits "; | ||
| 52 | name[StatEvents] = "Events collected "; | ||
| 53 | |||
| 54 | name[StatThreadCreate] = "Total threads created "; | ||
| 55 | name[StatThreadFinish] = " threads finished "; | ||
| 56 | name[StatThreadReuse] = " threads reused "; | ||
| 57 | name[StatThreadMaxTid] = " max tid "; | ||
| 58 | name[StatThreadMaxAlive] = " max alive threads "; | ||
| 59 | |||
| 60 | name[StatMutexCreate] = "Mutexes created "; | ||
| 61 | name[StatMutexDestroy] = " destroyed "; | ||
| 62 | name[StatMutexLock] = " lock "; | ||
| 63 | name[StatMutexUnlock] = " unlock "; | ||
| 64 | name[StatMutexRecLock] = " recursive lock "; | ||
| 65 | name[StatMutexRecUnlock] = " recursive unlock "; | ||
| 66 | name[StatMutexReadLock] = " read lock "; | ||
| 67 | name[StatMutexReadUnlock] = " read unlock "; | ||
| 68 | |||
| 69 | name[StatSyncCreated] = "Sync objects created "; | ||
| 70 | name[StatSyncDestroyed] = " destroyed "; | ||
| 71 | name[StatSyncAcquire] = " acquired "; | ||
| 72 | name[StatSyncRelease] = " released "; | ||
| 73 | |||
| 74 | name[StatClockAcquire] = "Clock acquire "; | ||
| 75 | name[StatClockAcquireEmpty] = " empty clock "; | ||
| 76 | name[StatClockAcquireFastRelease] = " fast from release-store "; | ||
| 77 | name[StatClockAcquireFull] = " full (slow) "; | ||
| 78 | name[StatClockAcquiredSomething] = " acquired something "; | ||
| 79 | name[StatClockRelease] = "Clock release "; | ||
| 80 | name[StatClockReleaseResize] = " resize "; | ||
| 81 | name[StatClockReleaseFast] = " fast "; | ||
| 82 | name[StatClockReleaseSlow] = " dirty overflow (slow) "; | ||
| 83 | name[StatClockReleaseFull] = " full (slow) "; | ||
| 84 | name[StatClockReleaseAcquired] = " was acquired "; | ||
| 85 | name[StatClockReleaseClearTail] = " clear tail "; | ||
| 86 | name[StatClockStore] = "Clock release store "; | ||
| 87 | name[StatClockStoreResize] = " resize "; | ||
| 88 | name[StatClockStoreFast] = " fast "; | ||
| 89 | name[StatClockStoreFull] = " slow "; | ||
| 90 | name[StatClockStoreTail] = " clear tail "; | ||
| 91 | name[StatClockAcquireRelease] = "Clock acquire-release "; | ||
| 92 | |||
| 93 | name[StatAtomic] = "Atomic operations "; | ||
| 94 | name[StatAtomicLoad] = " Including load "; | ||
| 95 | name[StatAtomicStore] = " store "; | ||
| 96 | name[StatAtomicExchange] = " exchange "; | ||
| 97 | name[StatAtomicFetchAdd] = " fetch_add "; | ||
| 98 | name[StatAtomicFetchSub] = " fetch_sub "; | ||
| 99 | name[StatAtomicFetchAnd] = " fetch_and "; | ||
| 100 | name[StatAtomicFetchOr] = " fetch_or "; | ||
| 101 | name[StatAtomicFetchXor] = " fetch_xor "; | ||
| 102 | name[StatAtomicFetchNand] = " fetch_nand "; | ||
| 103 | name[StatAtomicCAS] = " compare_exchange "; | ||
| 104 | name[StatAtomicFence] = " fence "; | ||
| 105 | name[StatAtomicRelaxed] = " Including relaxed "; | ||
| 106 | name[StatAtomicConsume] = " consume "; | ||
| 107 | name[StatAtomicAcquire] = " acquire "; | ||
| 108 | name[StatAtomicRelease] = " release "; | ||
| 109 | name[StatAtomicAcq_Rel] = " acq_rel "; | ||
| 110 | name[StatAtomicSeq_Cst] = " seq_cst "; | ||
| 111 | name[StatAtomic1] = " Including size 1 "; | ||
| 112 | name[StatAtomic2] = " size 2 "; | ||
| 113 | name[StatAtomic4] = " size 4 "; | ||
| 114 | name[StatAtomic8] = " size 8 "; | ||
| 115 | name[StatAtomic16] = " size 16 "; | ||
| 116 | |||
| 117 | name[StatAnnotation] = "Dynamic annotations "; | ||
| 118 | name[StatAnnotateHappensBefore] = " HappensBefore "; | ||
| 119 | name[StatAnnotateHappensAfter] = " HappensAfter "; | ||
| 120 | name[StatAnnotateCondVarSignal] = " CondVarSignal "; | ||
| 121 | name[StatAnnotateCondVarSignalAll] = " CondVarSignalAll "; | ||
| 122 | name[StatAnnotateMutexIsNotPHB] = " MutexIsNotPHB "; | ||
| 123 | name[StatAnnotateCondVarWait] = " CondVarWait "; | ||
| 124 | name[StatAnnotateRWLockCreate] = " RWLockCreate "; | ||
| 125 | name[StatAnnotateRWLockCreateStatic] = " StatAnnotateRWLockCreateStatic "; | ||
| 126 | name[StatAnnotateRWLockDestroy] = " RWLockDestroy "; | ||
| 127 | name[StatAnnotateRWLockAcquired] = " RWLockAcquired "; | ||
| 128 | name[StatAnnotateRWLockReleased] = " RWLockReleased "; | ||
| 129 | name[StatAnnotateTraceMemory] = " TraceMemory "; | ||
| 130 | name[StatAnnotateFlushState] = " FlushState "; | ||
| 131 | name[StatAnnotateNewMemory] = " NewMemory "; | ||
| 132 | name[StatAnnotateNoOp] = " NoOp "; | ||
| 133 | name[StatAnnotateFlushExpectedRaces] = " FlushExpectedRaces "; | ||
| 134 | name[StatAnnotateEnableRaceDetection] = " EnableRaceDetection "; | ||
| 135 | name[StatAnnotateMutexIsUsedAsCondVar] = " MutexIsUsedAsCondVar "; | ||
| 136 | name[StatAnnotatePCQGet] = " PCQGet "; | ||
| 137 | name[StatAnnotatePCQPut] = " PCQPut "; | ||
| 138 | name[StatAnnotatePCQDestroy] = " PCQDestroy "; | ||
| 139 | name[StatAnnotatePCQCreate] = " PCQCreate "; | ||
| 140 | name[StatAnnotateExpectRace] = " ExpectRace "; | ||
| 141 | name[StatAnnotateBenignRaceSized] = " BenignRaceSized "; | ||
| 142 | name[StatAnnotateBenignRace] = " BenignRace "; | ||
| 143 | name[StatAnnotateIgnoreReadsBegin] = " IgnoreReadsBegin "; | ||
| 144 | name[StatAnnotateIgnoreReadsEnd] = " IgnoreReadsEnd "; | ||
| 145 | name[StatAnnotateIgnoreWritesBegin] = " IgnoreWritesBegin "; | ||
| 146 | name[StatAnnotateIgnoreWritesEnd] = " IgnoreWritesEnd "; | ||
| 147 | name[StatAnnotateIgnoreSyncBegin] = " IgnoreSyncBegin "; | ||
| 148 | name[StatAnnotateIgnoreSyncEnd] = " IgnoreSyncEnd "; | ||
| 149 | name[StatAnnotatePublishMemoryRange] = " PublishMemoryRange "; | ||
| 150 | name[StatAnnotateUnpublishMemoryRange] = " UnpublishMemoryRange "; | ||
| 151 | name[StatAnnotateThreadName] = " ThreadName "; | ||
| 152 | name[Stat__tsan_mutex_create] = " __tsan_mutex_create "; | ||
| 153 | name[Stat__tsan_mutex_destroy] = " __tsan_mutex_destroy "; | ||
| 154 | name[Stat__tsan_mutex_pre_lock] = " __tsan_mutex_pre_lock "; | ||
| 155 | name[Stat__tsan_mutex_post_lock] = " __tsan_mutex_post_lock "; | ||
| 156 | name[Stat__tsan_mutex_pre_unlock] = " __tsan_mutex_pre_unlock "; | ||
| 157 | name[Stat__tsan_mutex_post_unlock] = " __tsan_mutex_post_unlock "; | ||
| 158 | name[Stat__tsan_mutex_pre_signal] = " __tsan_mutex_pre_signal "; | ||
| 159 | name[Stat__tsan_mutex_post_signal] = " __tsan_mutex_post_signal "; | ||
| 160 | name[Stat__tsan_mutex_pre_divert] = " __tsan_mutex_pre_divert "; | ||
| 161 | name[Stat__tsan_mutex_post_divert] = " __tsan_mutex_post_divert "; | ||
| 162 | |||
| 163 | name[StatMtxTotal] = "Contentionz "; | ||
| 164 | name[StatMtxTrace] = " Trace "; | ||
| 165 | name[StatMtxThreads] = " Threads "; | ||
| 166 | name[StatMtxReport] = " Report "; | ||
| 167 | name[StatMtxSyncVar] = " SyncVar "; | ||
| 168 | name[StatMtxSyncTab] = " SyncTab "; | ||
| 169 | name[StatMtxSlab] = " Slab "; | ||
| 170 | name[StatMtxAtExit] = " Atexit "; | ||
| 171 | name[StatMtxAnnotations] = " Annotations "; | ||
| 172 | name[StatMtxMBlock] = " MBlock "; | ||
| 173 | name[StatMtxDeadlockDetector] = " DeadlockDetector "; | ||
| 174 | name[StatMtxFired] = " FiredSuppressions "; | ||
| 175 | name[StatMtxRacy] = " RacyStacks "; | ||
| 176 | name[StatMtxFD] = " FD "; | ||
| 177 | name[StatMtxGlobalProc] = " GlobalProc "; | ||
| 178 | |||
| 179 | Printf("Statistics:\n"); | ||
| 180 | for (int i = 0; i < StatCnt; i++) | ||
| 181 | Printf("%s: %16zu\n", name[i], (uptr)stat[i]); | ||
| 182 | } | ||
| 183 | |||
| 184 | #endif | ||
| 185 | |||
| 186 | } // namespace __tsan | ||
lib/tsan/tsan_stat.h created+191| ... | @@ -0,0 +1,191 @@ | ||
| 1 | //===-- tsan_stat.h ---------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #ifndef TSAN_STAT_H | ||
| 14 | #define TSAN_STAT_H | ||
| 15 | |||
| 16 | namespace __tsan { | ||
| 17 | |||
| 18 | enum StatType { | ||
| 19 | // Memory access processing related stuff. | ||
| 20 | StatMop, | ||
| 21 | StatMopRead, | ||
| 22 | StatMopWrite, | ||
| 23 | StatMop1, // These must be consequtive. | ||
| 24 | StatMop2, | ||
| 25 | StatMop4, | ||
| 26 | StatMop8, | ||
| 27 | StatMopSame, | ||
| 28 | StatMopIgnored, | ||
| 29 | StatMopRange, | ||
| 30 | StatMopRodata, | ||
| 31 | StatMopRangeRodata, | ||
| 32 | StatShadowProcessed, | ||
| 33 | StatShadowZero, | ||
| 34 | StatShadowNonZero, // Derived. | ||
| 35 | StatShadowSameSize, | ||
| 36 | StatShadowIntersect, | ||
| 37 | StatShadowNotIntersect, | ||
| 38 | StatShadowSameThread, | ||
| 39 | StatShadowAnotherThread, | ||
| 40 | StatShadowReplace, | ||
| 41 | |||
| 42 | // Func processing. | ||
| 43 | StatFuncEnter, | ||
| 44 | StatFuncExit, | ||
| 45 | |||
| 46 | // Trace processing. | ||
| 47 | StatEvents, | ||
| 48 | |||
| 49 | // Threads. | ||
| 50 | StatThreadCreate, | ||
| 51 | StatThreadFinish, | ||
| 52 | StatThreadReuse, | ||
| 53 | StatThreadMaxTid, | ||
| 54 | StatThreadMaxAlive, | ||
| 55 | |||
| 56 | // Mutexes. | ||
| 57 | StatMutexCreate, | ||
| 58 | StatMutexDestroy, | ||
| 59 | StatMutexLock, | ||
| 60 | StatMutexUnlock, | ||
| 61 | StatMutexRecLock, | ||
| 62 | StatMutexRecUnlock, | ||
| 63 | StatMutexReadLock, | ||
| 64 | StatMutexReadUnlock, | ||
| 65 | |||
| 66 | // Synchronization. | ||
| 67 | StatSyncCreated, | ||
| 68 | StatSyncDestroyed, | ||
| 69 | StatSyncAcquire, | ||
| 70 | StatSyncRelease, | ||
| 71 | StatSyncReleaseStoreAcquire, | ||
| 72 | |||
| 73 | // Clocks - acquire. | ||
| 74 | StatClockAcquire, | ||
| 75 | StatClockAcquireEmpty, | ||
| 76 | StatClockAcquireFastRelease, | ||
| 77 | StatClockAcquireFull, | ||
| 78 | StatClockAcquiredSomething, | ||
| 79 | // Clocks - release. | ||
| 80 | StatClockRelease, | ||
| 81 | StatClockReleaseResize, | ||
| 82 | StatClockReleaseFast, | ||
| 83 | StatClockReleaseSlow, | ||
| 84 | StatClockReleaseFull, | ||
| 85 | StatClockReleaseAcquired, | ||
| 86 | StatClockReleaseClearTail, | ||
| 87 | // Clocks - release store. | ||
| 88 | StatClockStore, | ||
| 89 | StatClockStoreResize, | ||
| 90 | StatClockStoreFast, | ||
| 91 | StatClockStoreFull, | ||
| 92 | StatClockStoreTail, | ||
| 93 | // Clocks - acquire-release. | ||
| 94 | StatClockAcquireRelease, | ||
| 95 | |||
| 96 | // Atomics. | ||
| 97 | StatAtomic, | ||
| 98 | StatAtomicLoad, | ||
| 99 | StatAtomicStore, | ||
| 100 | StatAtomicExchange, | ||
| 101 | StatAtomicFetchAdd, | ||
| 102 | StatAtomicFetchSub, | ||
| 103 | StatAtomicFetchAnd, | ||
| 104 | StatAtomicFetchOr, | ||
| 105 | StatAtomicFetchXor, | ||
| 106 | StatAtomicFetchNand, | ||
| 107 | StatAtomicCAS, | ||
| 108 | StatAtomicFence, | ||
| 109 | StatAtomicRelaxed, | ||
| 110 | StatAtomicConsume, | ||
| 111 | StatAtomicAcquire, | ||
| 112 | StatAtomicRelease, | ||
| 113 | StatAtomicAcq_Rel, | ||
| 114 | StatAtomicSeq_Cst, | ||
| 115 | StatAtomic1, | ||
| 116 | StatAtomic2, | ||
| 117 | StatAtomic4, | ||
| 118 | StatAtomic8, | ||
| 119 | StatAtomic16, | ||
| 120 | |||
| 121 | // Dynamic annotations. | ||
| 122 | StatAnnotation, | ||
| 123 | StatAnnotateHappensBefore, | ||
| 124 | StatAnnotateHappensAfter, | ||
| 125 | StatAnnotateCondVarSignal, | ||
| 126 | StatAnnotateCondVarSignalAll, | ||
| 127 | StatAnnotateMutexIsNotPHB, | ||
| 128 | StatAnnotateCondVarWait, | ||
| 129 | StatAnnotateRWLockCreate, | ||
| 130 | StatAnnotateRWLockCreateStatic, | ||
| 131 | StatAnnotateRWLockDestroy, | ||
| 132 | StatAnnotateRWLockAcquired, | ||
| 133 | StatAnnotateRWLockReleased, | ||
| 134 | StatAnnotateTraceMemory, | ||
| 135 | StatAnnotateFlushState, | ||
| 136 | StatAnnotateNewMemory, | ||
| 137 | StatAnnotateNoOp, | ||
| 138 | StatAnnotateFlushExpectedRaces, | ||
| 139 | StatAnnotateEnableRaceDetection, | ||
| 140 | StatAnnotateMutexIsUsedAsCondVar, | ||
| 141 | StatAnnotatePCQGet, | ||
| 142 | StatAnnotatePCQPut, | ||
| 143 | StatAnnotatePCQDestroy, | ||
| 144 | StatAnnotatePCQCreate, | ||
| 145 | StatAnnotateExpectRace, | ||
| 146 | StatAnnotateBenignRaceSized, | ||
| 147 | StatAnnotateBenignRace, | ||
| 148 | StatAnnotateIgnoreReadsBegin, | ||
| 149 | StatAnnotateIgnoreReadsEnd, | ||
| 150 | StatAnnotateIgnoreWritesBegin, | ||
| 151 | StatAnnotateIgnoreWritesEnd, | ||
| 152 | StatAnnotateIgnoreSyncBegin, | ||
| 153 | StatAnnotateIgnoreSyncEnd, | ||
| 154 | StatAnnotatePublishMemoryRange, | ||
| 155 | StatAnnotateUnpublishMemoryRange, | ||
| 156 | StatAnnotateThreadName, | ||
| 157 | Stat__tsan_mutex_create, | ||
| 158 | Stat__tsan_mutex_destroy, | ||
| 159 | Stat__tsan_mutex_pre_lock, | ||
| 160 | Stat__tsan_mutex_post_lock, | ||
| 161 | Stat__tsan_mutex_pre_unlock, | ||
| 162 | Stat__tsan_mutex_post_unlock, | ||
| 163 | Stat__tsan_mutex_pre_signal, | ||
| 164 | Stat__tsan_mutex_post_signal, | ||
| 165 | Stat__tsan_mutex_pre_divert, | ||
| 166 | Stat__tsan_mutex_post_divert, | ||
| 167 | |||
| 168 | // Internal mutex contentionz. | ||
| 169 | StatMtxTotal, | ||
| 170 | StatMtxTrace, | ||
| 171 | StatMtxThreads, | ||
| 172 | StatMtxReport, | ||
| 173 | StatMtxSyncVar, | ||
| 174 | StatMtxSyncTab, | ||
| 175 | StatMtxSlab, | ||
| 176 | StatMtxAnnotations, | ||
| 177 | StatMtxAtExit, | ||
| 178 | StatMtxMBlock, | ||
| 179 | StatMtxDeadlockDetector, | ||
| 180 | StatMtxFired, | ||
| 181 | StatMtxRacy, | ||
| 182 | StatMtxFD, | ||
| 183 | StatMtxGlobalProc, | ||
| 184 | |||
| 185 | // This must be the last. | ||
| 186 | StatCnt | ||
| 187 | }; | ||
| 188 | |||
| 189 | } // namespace __tsan | ||
| 190 | |||
| 191 | #endif // TSAN_STAT_H | ||
lib/tsan/tsan_suppressions.cpp created+161| ... | @@ -0,0 +1,161 @@ | ||
| 1 | //===-- tsan_suppressions.cpp ---------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "sanitizer_common/sanitizer_common.h" | ||
| 14 | #include "sanitizer_common/sanitizer_libc.h" | ||
| 15 | #include "sanitizer_common/sanitizer_placement_new.h" | ||
| 16 | #include "sanitizer_common/sanitizer_suppressions.h" | ||
| 17 | #include "tsan_suppressions.h" | ||
| 18 | #include "tsan_rtl.h" | ||
| 19 | #include "tsan_flags.h" | ||
| 20 | #include "tsan_mman.h" | ||
| 21 | #include "tsan_platform.h" | ||
| 22 | |||
| 23 | #if !SANITIZER_GO | ||
| 24 | // Suppressions for true/false positives in standard libraries. | ||
| 25 | static const char *const std_suppressions = | ||
| 26 | // Libstdc++ 4.4 has data races in std::string. | ||
| 27 | // See http://crbug.com/181502 for an example. | ||
| 28 | "race:^_M_rep$\n" | ||
| 29 | "race:^_M_is_leaked$\n" | ||
| 30 | // False positive when using std <thread>. | ||
| 31 | // Happens because we miss atomic synchronization in libstdc++. | ||
| 32 | // See http://llvm.org/bugs/show_bug.cgi?id=17066 for details. | ||
| 33 | "race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n"; | ||
| 34 | |||
| 35 | // Can be overriden in frontend. | ||
| 36 | SANITIZER_WEAK_DEFAULT_IMPL | ||
| 37 | const char *__tsan_default_suppressions() { | ||
| 38 | return 0; | ||
| 39 | } | ||
| 40 | #endif | ||
| 41 | |||
| 42 | namespace __tsan { | ||
| 43 | |||
| 44 | ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)]; | ||
| 45 | static SuppressionContext *suppression_ctx = nullptr; | ||
| 46 | static const char *kSuppressionTypes[] = { | ||
| 47 | kSuppressionRace, kSuppressionRaceTop, kSuppressionMutex, | ||
| 48 | kSuppressionThread, kSuppressionSignal, kSuppressionLib, | ||
| 49 | kSuppressionDeadlock}; | ||
| 50 | |||
| 51 | void InitializeSuppressions() { | ||
| 52 | CHECK_EQ(nullptr, suppression_ctx); | ||
| 53 | suppression_ctx = new (suppression_placeholder) | ||
| 54 | SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); | ||
| 55 | suppression_ctx->ParseFromFile(flags()->suppressions); | ||
| 56 | #if !SANITIZER_GO | ||
| 57 | suppression_ctx->Parse(__tsan_default_suppressions()); | ||
| 58 | suppression_ctx->Parse(std_suppressions); | ||
| 59 | #endif | ||
| 60 | } | ||
| 61 | |||
| 62 | SuppressionContext *Suppressions() { | ||
| 63 | CHECK(suppression_ctx); | ||
| 64 | return suppression_ctx; | ||
| 65 | } | ||
| 66 | |||
| 67 | static const char *conv(ReportType typ) { | ||
| 68 | switch (typ) { | ||
| 69 | case ReportTypeRace: | ||
| 70 | case ReportTypeVptrRace: | ||
| 71 | case ReportTypeUseAfterFree: | ||
| 72 | case ReportTypeVptrUseAfterFree: | ||
| 73 | case ReportTypeExternalRace: | ||
| 74 | return kSuppressionRace; | ||
| 75 | case ReportTypeThreadLeak: | ||
| 76 | return kSuppressionThread; | ||
| 77 | case ReportTypeMutexDestroyLocked: | ||
| 78 | case ReportTypeMutexDoubleLock: | ||
| 79 | case ReportTypeMutexInvalidAccess: | ||
| 80 | case ReportTypeMutexBadUnlock: | ||
| 81 | case ReportTypeMutexBadReadLock: | ||
| 82 | case ReportTypeMutexBadReadUnlock: | ||
| 83 | return kSuppressionMutex; | ||
| 84 | case ReportTypeSignalUnsafe: | ||
| 85 | case ReportTypeErrnoInSignal: | ||
| 86 | return kSuppressionSignal; | ||
| 87 | case ReportTypeDeadlock: | ||
| 88 | return kSuppressionDeadlock; | ||
| 89 | // No default case so compiler warns us if we miss one | ||
| 90 | } | ||
| 91 | UNREACHABLE("missing case"); | ||
| 92 | } | ||
| 93 | |||
| 94 | static uptr IsSuppressed(const char *stype, const AddressInfo &info, | ||
| 95 | Suppression **sp) { | ||
| 96 | if (suppression_ctx->Match(info.function, stype, sp) || | ||
| 97 | suppression_ctx->Match(info.file, stype, sp) || | ||
| 98 | suppression_ctx->Match(info.module, stype, sp)) { | ||
| 99 | VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", (*sp)->templ); | ||
| 100 | atomic_fetch_add(&(*sp)->hit_count, 1, memory_order_relaxed); | ||
| 101 | return info.address; | ||
| 102 | } | ||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) { | ||
| 107 | CHECK(suppression_ctx); | ||
| 108 | if (!suppression_ctx->SuppressionCount() || stack == 0 || | ||
| 109 | !stack->suppressable) | ||
| 110 | return 0; | ||
| 111 | const char *stype = conv(typ); | ||
| 112 | if (0 == internal_strcmp(stype, kSuppressionNone)) | ||
| 113 | return 0; | ||
| 114 | for (const SymbolizedStack *frame = stack->frames; frame; | ||
| 115 | frame = frame->next) { | ||
| 116 | uptr pc = IsSuppressed(stype, frame->info, sp); | ||
| 117 | if (pc != 0) | ||
| 118 | return pc; | ||
| 119 | } | ||
| 120 | if (0 == internal_strcmp(stype, kSuppressionRace) && stack->frames != nullptr) | ||
| 121 | return IsSuppressed(kSuppressionRaceTop, stack->frames->info, sp); | ||
| 122 | return 0; | ||
| 123 | } | ||
| 124 | |||
| 125 | uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) { | ||
| 126 | CHECK(suppression_ctx); | ||
| 127 | if (!suppression_ctx->SuppressionCount() || loc == 0 || | ||
| 128 | loc->type != ReportLocationGlobal || !loc->suppressable) | ||
| 129 | return 0; | ||
| 130 | const char *stype = conv(typ); | ||
| 131 | if (0 == internal_strcmp(stype, kSuppressionNone)) | ||
| 132 | return 0; | ||
| 133 | Suppression *s; | ||
| 134 | const DataInfo &global = loc->global; | ||
| 135 | if (suppression_ctx->Match(global.name, stype, &s) || | ||
| 136 | suppression_ctx->Match(global.module, stype, &s)) { | ||
| 137 | VPrintf(2, "ThreadSanitizer: matched suppression '%s'\n", s->templ); | ||
| 138 | atomic_fetch_add(&s->hit_count, 1, memory_order_relaxed); | ||
| 139 | *sp = s; | ||
| 140 | return global.start; | ||
| 141 | } | ||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | |||
| 145 | void PrintMatchedSuppressions() { | ||
| 146 | InternalMmapVector<Suppression *> matched; | ||
| 147 | CHECK(suppression_ctx); | ||
| 148 | suppression_ctx->GetMatched(&matched); | ||
| 149 | if (!matched.size()) | ||
| 150 | return; | ||
| 151 | int hit_count = 0; | ||
| 152 | for (uptr i = 0; i < matched.size(); i++) | ||
| 153 | hit_count += atomic_load_relaxed(&matched[i]->hit_count); | ||
| 154 | Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count, | ||
| 155 | (int)internal_getpid()); | ||
| 156 | for (uptr i = 0; i < matched.size(); i++) { | ||
| 157 | Printf("%d %s:%s\n", atomic_load_relaxed(&matched[i]->hit_count), | ||
| 158 | matched[i]->type, matched[i]->templ); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | } // namespace __tsan | ||
lib/tsan/tsan_suppressions.h created+37| ... | @@ -0,0 +1,37 @@ | ||
| 1 | //===-- tsan_suppressions.h -------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef TSAN_SUPPRESSIONS_H | ||
| 13 | #define TSAN_SUPPRESSIONS_H | ||
| 14 | |||
| 15 | #include "sanitizer_common/sanitizer_suppressions.h" | ||
| 16 | #include "tsan_report.h" | ||
| 17 | |||
| 18 | namespace __tsan { | ||
| 19 | |||
| 20 | const char kSuppressionNone[] = "none"; | ||
| 21 | const char kSuppressionRace[] = "race"; | ||
| 22 | const char kSuppressionRaceTop[] = "race_top"; | ||
| 23 | const char kSuppressionMutex[] = "mutex"; | ||
| 24 | const char kSuppressionThread[] = "thread"; | ||
| 25 | const char kSuppressionSignal[] = "signal"; | ||
| 26 | const char kSuppressionLib[] = "called_from_lib"; | ||
| 27 | const char kSuppressionDeadlock[] = "deadlock"; | ||
| 28 | |||
| 29 | void InitializeSuppressions(); | ||
| 30 | SuppressionContext *Suppressions(); | ||
| 31 | void PrintMatchedSuppressions(); | ||
| 32 | uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp); | ||
| 33 | uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp); | ||
| 34 | |||
| 35 | } // namespace __tsan | ||
| 36 | |||
| 37 | #endif // TSAN_SUPPRESSIONS_H | ||
lib/tsan/tsan_symbolize.cpp created+122| ... | @@ -0,0 +1,122 @@ | ||
| 1 | //===-- tsan_symbolize.cpp ------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | |||
| 13 | #include "tsan_symbolize.h" | ||
| 14 | |||
| 15 | #include "sanitizer_common/sanitizer_common.h" | ||
| 16 | #include "sanitizer_common/sanitizer_placement_new.h" | ||
| 17 | #include "sanitizer_common/sanitizer_symbolizer.h" | ||
| 18 | #include "tsan_flags.h" | ||
| 19 | #include "tsan_report.h" | ||
| 20 | #include "tsan_rtl.h" | ||
| 21 | |||
| 22 | namespace __tsan { | ||
| 23 | |||
| 24 | void EnterSymbolizer() { | ||
| 25 | ThreadState *thr = cur_thread(); | ||
| 26 | CHECK(!thr->in_symbolizer); | ||
| 27 | thr->in_symbolizer = true; | ||
| 28 | thr->ignore_interceptors++; | ||
| 29 | } | ||
| 30 | |||
| 31 | void ExitSymbolizer() { | ||
| 32 | ThreadState *thr = cur_thread(); | ||
| 33 | CHECK(thr->in_symbolizer); | ||
| 34 | thr->in_symbolizer = false; | ||
| 35 | thr->ignore_interceptors--; | ||
| 36 | } | ||
| 37 | |||
| 38 | // Legacy API. | ||
| 39 | // May be overriden by JIT/JAVA/etc, | ||
| 40 | // whatever produces PCs marked with kExternalPCBit. | ||
| 41 | SANITIZER_WEAK_DEFAULT_IMPL | ||
| 42 | bool __tsan_symbolize_external(uptr pc, char *func_buf, uptr func_siz, | ||
| 43 | char *file_buf, uptr file_siz, int *line, | ||
| 44 | int *col) { | ||
| 45 | return false; | ||
| 46 | } | ||
| 47 | |||
| 48 | // New API: call __tsan_symbolize_external_ex only when it exists. | ||
| 49 | // Once old clients are gone, provide dummy implementation. | ||
| 50 | SANITIZER_WEAK_DEFAULT_IMPL | ||
| 51 | void __tsan_symbolize_external_ex(uptr pc, | ||
| 52 | void (*add_frame)(void *, const char *, | ||
| 53 | const char *, int, int), | ||
| 54 | void *ctx) {} | ||
| 55 | |||
| 56 | struct SymbolizedStackBuilder { | ||
| 57 | SymbolizedStack *head; | ||
| 58 | SymbolizedStack *tail; | ||
| 59 | uptr addr; | ||
| 60 | }; | ||
| 61 | |||
| 62 | static void AddFrame(void *ctx, const char *function_name, const char *file, | ||
| 63 | int line, int column) { | ||
| 64 | SymbolizedStackBuilder *ssb = (struct SymbolizedStackBuilder *)ctx; | ||
| 65 | if (ssb->tail) { | ||
| 66 | ssb->tail->next = SymbolizedStack::New(ssb->addr); | ||
| 67 | ssb->tail = ssb->tail->next; | ||
| 68 | } else { | ||
| 69 | ssb->head = ssb->tail = SymbolizedStack::New(ssb->addr); | ||
| 70 | } | ||
| 71 | AddressInfo *info = &ssb->tail->info; | ||
| 72 | if (function_name) { | ||
| 73 | info->function = internal_strdup(function_name); | ||
| 74 | } | ||
| 75 | if (file) { | ||
| 76 | info->file = internal_strdup(file); | ||
| 77 | } | ||
| 78 | info->line = line; | ||
| 79 | info->column = column; | ||
| 80 | } | ||
| 81 | |||
| 82 | SymbolizedStack *SymbolizeCode(uptr addr) { | ||
| 83 | // Check if PC comes from non-native land. | ||
| 84 | if (addr & kExternalPCBit) { | ||
| 85 | SymbolizedStackBuilder ssb = {nullptr, nullptr, addr}; | ||
| 86 | __tsan_symbolize_external_ex(addr, AddFrame, &ssb); | ||
| 87 | if (ssb.head) | ||
| 88 | return ssb.head; | ||
| 89 | // Legacy code: remove along with the declaration above | ||
| 90 | // once all clients using this API are gone. | ||
| 91 | // Declare static to not consume too much stack space. | ||
| 92 | // We symbolize reports in a single thread, so this is fine. | ||
| 93 | static char func_buf[1024]; | ||
| 94 | static char file_buf[1024]; | ||
| 95 | int line, col; | ||
| 96 | SymbolizedStack *frame = SymbolizedStack::New(addr); | ||
| 97 | if (__tsan_symbolize_external(addr, func_buf, sizeof(func_buf), file_buf, | ||
| 98 | sizeof(file_buf), &line, &col)) { | ||
| 99 | frame->info.function = internal_strdup(func_buf); | ||
| 100 | frame->info.file = internal_strdup(file_buf); | ||
| 101 | frame->info.line = line; | ||
| 102 | frame->info.column = col; | ||
| 103 | } | ||
| 104 | return frame; | ||
| 105 | } | ||
| 106 | return Symbolizer::GetOrInit()->SymbolizePC(addr); | ||
| 107 | } | ||
| 108 | |||
| 109 | ReportLocation *SymbolizeData(uptr addr) { | ||
| 110 | DataInfo info; | ||
| 111 | if (!Symbolizer::GetOrInit()->SymbolizeData(addr, &info)) | ||
| 112 | return 0; | ||
| 113 | ReportLocation *ent = ReportLocation::New(ReportLocationGlobal); | ||
| 114 | internal_memcpy(&ent->global, &info, sizeof(info)); | ||
| 115 | return ent; | ||
| 116 | } | ||
| 117 | |||
| 118 | void SymbolizeFlush() { | ||
| 119 | Symbolizer::GetOrInit()->Flush(); | ||
| 120 | } | ||
| 121 | |||
| 122 | } // namespace __tsan | ||
lib/tsan/tsan_symbolize.h created+30| ... | @@ -0,0 +1,30 @@ | ||
| 1 | //===-- tsan_symbolize.h ----------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef TSAN_SYMBOLIZE_H | ||
| 13 | #define TSAN_SYMBOLIZE_H | ||
| 14 | |||
| 15 | #include "tsan_defs.h" | ||
| 16 | #include "tsan_report.h" | ||
| 17 | |||
| 18 | namespace __tsan { | ||
| 19 | |||
| 20 | void EnterSymbolizer(); | ||
| 21 | void ExitSymbolizer(); | ||
| 22 | SymbolizedStack *SymbolizeCode(uptr addr); | ||
| 23 | ReportLocation *SymbolizeData(uptr addr); | ||
| 24 | void SymbolizeFlush(); | ||
| 25 | |||
| 26 | ReportStack *NewReportStackEntry(uptr addr); | ||
| 27 | |||
| 28 | } // namespace __tsan | ||
| 29 | |||
| 30 | #endif // TSAN_SYMBOLIZE_H | ||
lib/tsan/tsan_sync.cpp created+296| ... | @@ -0,0 +1,296 @@ | ||
| 1 | //===-- tsan_sync.cpp -----------------------------------------------------===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #include "sanitizer_common/sanitizer_placement_new.h" | ||
| 13 | #include "tsan_sync.h" | ||
| 14 | #include "tsan_rtl.h" | ||
| 15 | #include "tsan_mman.h" | ||
| 16 | |||
| 17 | namespace __tsan { | ||
| 18 | |||
| 19 | void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s); | ||
| 20 | |||
| 21 | SyncVar::SyncVar() | ||
| 22 | : mtx(MutexTypeSyncVar, StatMtxSyncVar) { | ||
| 23 | Reset(0); | ||
| 24 | } | ||
| 25 | |||
| 26 | void SyncVar::Init(ThreadState *thr, uptr pc, uptr addr, u64 uid) { | ||
| 27 | this->addr = addr; | ||
| 28 | this->uid = uid; | ||
| 29 | this->next = 0; | ||
| 30 | |||
| 31 | creation_stack_id = 0; | ||
| 32 | if (!SANITIZER_GO) // Go does not use them | ||
| 33 | creation_stack_id = CurrentStackId(thr, pc); | ||
| 34 | if (common_flags()->detect_deadlocks) | ||
| 35 | DDMutexInit(thr, pc, this); | ||
| 36 | } | ||
| 37 | |||
| 38 | void SyncVar::Reset(Processor *proc) { | ||
| 39 | uid = 0; | ||
| 40 | creation_stack_id = 0; | ||
| 41 | owner_tid = kInvalidTid; | ||
| 42 | last_lock = 0; | ||
| 43 | recursion = 0; | ||
| 44 | atomic_store_relaxed(&flags, 0); | ||
| 45 | |||
| 46 | if (proc == 0) { | ||
| 47 | CHECK_EQ(clock.size(), 0); | ||
| 48 | CHECK_EQ(read_clock.size(), 0); | ||
| 49 | } else { | ||
| 50 | clock.Reset(&proc->clock_cache); | ||
| 51 | read_clock.Reset(&proc->clock_cache); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | MetaMap::MetaMap() | ||
| 56 | : block_alloc_("heap block allocator") | ||
| 57 | , sync_alloc_("sync allocator") { | ||
| 58 | atomic_store(&uid_gen_, 0, memory_order_relaxed); | ||
| 59 | } | ||
| 60 | |||
| 61 | void MetaMap::AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz) { | ||
| 62 | u32 idx = block_alloc_.Alloc(&thr->proc()->block_cache); | ||
| 63 | MBlock *b = block_alloc_.Map(idx); | ||
| 64 | b->siz = sz; | ||
| 65 | b->tag = 0; | ||
| 66 | b->tid = thr->tid; | ||
| 67 | b->stk = CurrentStackId(thr, pc); | ||
| 68 | u32 *meta = MemToMeta(p); | ||
| 69 | DCHECK_EQ(*meta, 0); | ||
| 70 | *meta = idx | kFlagBlock; | ||
| 71 | } | ||
| 72 | |||
| 73 | uptr MetaMap::FreeBlock(Processor *proc, uptr p) { | ||
| 74 | MBlock* b = GetBlock(p); | ||
| 75 | if (b == 0) | ||
| 76 | return 0; | ||
| 77 | uptr sz = RoundUpTo(b->siz, kMetaShadowCell); | ||
| 78 | FreeRange(proc, p, sz); | ||
| 79 | return sz; | ||
| 80 | } | ||
| 81 | |||
| 82 | bool MetaMap::FreeRange(Processor *proc, uptr p, uptr sz) { | ||
| 83 | bool has_something = false; | ||
| 84 | u32 *meta = MemToMeta(p); | ||
| 85 | u32 *end = MemToMeta(p + sz); | ||
| 86 | if (end == meta) | ||
| 87 | end++; | ||
| 88 | for (; meta < end; meta++) { | ||
| 89 | u32 idx = *meta; | ||
| 90 | if (idx == 0) { | ||
| 91 | // Note: don't write to meta in this case -- the block can be huge. | ||
| 92 | continue; | ||
| 93 | } | ||
| 94 | *meta = 0; | ||
| 95 | has_something = true; | ||
| 96 | while (idx != 0) { | ||
| 97 | if (idx & kFlagBlock) { | ||
| 98 | block_alloc_.Free(&proc->block_cache, idx & ~kFlagMask); | ||
| 99 | break; | ||
| 100 | } else if (idx & kFlagSync) { | ||
| 101 | DCHECK(idx & kFlagSync); | ||
| 102 | SyncVar *s = sync_alloc_.Map(idx & ~kFlagMask); | ||
| 103 | u32 next = s->next; | ||
| 104 | s->Reset(proc); | ||
| 105 | sync_alloc_.Free(&proc->sync_cache, idx & ~kFlagMask); | ||
| 106 | idx = next; | ||
| 107 | } else { | ||
| 108 | CHECK(0); | ||
| 109 | } | ||
| 110 | } | ||
| 111 | } | ||
| 112 | return has_something; | ||
| 113 | } | ||
| 114 | |||
| 115 | // ResetRange removes all meta objects from the range. | ||
| 116 | // It is called for large mmap-ed regions. The function is best-effort wrt | ||
| 117 | // freeing of meta objects, because we don't want to page in the whole range | ||
| 118 | // which can be huge. The function probes pages one-by-one until it finds a page | ||
| 119 | // without meta objects, at this point it stops freeing meta objects. Because | ||
| 120 | // thread stacks grow top-down, we do the same starting from end as well. | ||
| 121 | void MetaMap::ResetRange(Processor *proc, uptr p, uptr sz) { | ||
| 122 | if (SANITIZER_GO) { | ||
| 123 | // UnmapOrDie/MmapFixedNoReserve does not work on Windows, | ||
| 124 | // so we do the optimization only for C/C++. | ||
| 125 | FreeRange(proc, p, sz); | ||
| 126 | return; | ||
| 127 | } | ||
| 128 | const uptr kMetaRatio = kMetaShadowCell / kMetaShadowSize; | ||
| 129 | const uptr kPageSize = GetPageSizeCached() * kMetaRatio; | ||
| 130 | if (sz <= 4 * kPageSize) { | ||
| 131 | // If the range is small, just do the normal free procedure. | ||
| 132 | FreeRange(proc, p, sz); | ||
| 133 | return; | ||
| 134 | } | ||
| 135 | // First, round both ends of the range to page size. | ||
| 136 | uptr diff = RoundUp(p, kPageSize) - p; | ||
| 137 | if (diff != 0) { | ||
| 138 | FreeRange(proc, p, diff); | ||
| 139 | p += diff; | ||
| 140 | sz -= diff; | ||
| 141 | } | ||
| 142 | diff = p + sz - RoundDown(p + sz, kPageSize); | ||
| 143 | if (diff != 0) { | ||
| 144 | FreeRange(proc, p + sz - diff, diff); | ||
| 145 | sz -= diff; | ||
| 146 | } | ||
| 147 | // Now we must have a non-empty page-aligned range. | ||
| 148 | CHECK_GT(sz, 0); | ||
| 149 | CHECK_EQ(p, RoundUp(p, kPageSize)); | ||
| 150 | CHECK_EQ(sz, RoundUp(sz, kPageSize)); | ||
| 151 | const uptr p0 = p; | ||
| 152 | const uptr sz0 = sz; | ||
| 153 | // Probe start of the range. | ||
| 154 | for (uptr checked = 0; sz > 0; checked += kPageSize) { | ||
| 155 | bool has_something = FreeRange(proc, p, kPageSize); | ||
| 156 | p += kPageSize; | ||
| 157 | sz -= kPageSize; | ||
| 158 | if (!has_something && checked > (128 << 10)) | ||
| 159 | break; | ||
| 160 | } | ||
| 161 | // Probe end of the range. | ||
| 162 | for (uptr checked = 0; sz > 0; checked += kPageSize) { | ||
| 163 | bool has_something = FreeRange(proc, p + sz - kPageSize, kPageSize); | ||
| 164 | sz -= kPageSize; | ||
| 165 | // Stacks grow down, so sync object are most likely at the end of the region | ||
| 166 | // (if it is a stack). The very end of the stack is TLS and tsan increases | ||
| 167 | // TLS by at least 256K, so check at least 512K. | ||
| 168 | if (!has_something && checked > (512 << 10)) | ||
| 169 | break; | ||
| 170 | } | ||
| 171 | // Finally, page out the whole range (including the parts that we've just | ||
| 172 | // freed). Note: we can't simply madvise, because we need to leave a zeroed | ||
| 173 | // range (otherwise __tsan_java_move can crash if it encounters a left-over | ||
| 174 | // meta objects in java heap). | ||
| 175 | uptr metap = (uptr)MemToMeta(p0); | ||
| 176 | uptr metasz = sz0 / kMetaRatio; | ||
| 177 | UnmapOrDie((void*)metap, metasz); | ||
| 178 | if (!MmapFixedNoReserve(metap, metasz)) | ||
| 179 | Die(); | ||
| 180 | } | ||
| 181 | |||
| 182 | MBlock* MetaMap::GetBlock(uptr p) { | ||
| 183 | u32 *meta = MemToMeta(p); | ||
| 184 | u32 idx = *meta; | ||
| 185 | for (;;) { | ||
| 186 | if (idx == 0) | ||
| 187 | return 0; | ||
| 188 | if (idx & kFlagBlock) | ||
| 189 | return block_alloc_.Map(idx & ~kFlagMask); | ||
| 190 | DCHECK(idx & kFlagSync); | ||
| 191 | SyncVar * s = sync_alloc_.Map(idx & ~kFlagMask); | ||
| 192 | idx = s->next; | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | SyncVar* MetaMap::GetOrCreateAndLock(ThreadState *thr, uptr pc, | ||
| 197 | uptr addr, bool write_lock) { | ||
| 198 | return GetAndLock(thr, pc, addr, write_lock, true); | ||
| 199 | } | ||
| 200 | |||
| 201 | SyncVar* MetaMap::GetIfExistsAndLock(uptr addr, bool write_lock) { | ||
| 202 | return GetAndLock(0, 0, addr, write_lock, false); | ||
| 203 | } | ||
| 204 | |||
| 205 | SyncVar* MetaMap::GetAndLock(ThreadState *thr, uptr pc, | ||
| 206 | uptr addr, bool write_lock, bool create) { | ||
| 207 | u32 *meta = MemToMeta(addr); | ||
| 208 | u32 idx0 = *meta; | ||
| 209 | u32 myidx = 0; | ||
| 210 | SyncVar *mys = 0; | ||
| 211 | for (;;) { | ||
| 212 | u32 idx = idx0; | ||
| 213 | for (;;) { | ||
| 214 | if (idx == 0) | ||
| 215 | break; | ||
| 216 | if (idx & kFlagBlock) | ||
| 217 | break; | ||
| 218 | DCHECK(idx & kFlagSync); | ||
| 219 | SyncVar * s = sync_alloc_.Map(idx & ~kFlagMask); | ||
| 220 | if (s->addr == addr) { | ||
| 221 | if (myidx != 0) { | ||
| 222 | mys->Reset(thr->proc()); | ||
| 223 | sync_alloc_.Free(&thr->proc()->sync_cache, myidx); | ||
| 224 | } | ||
| 225 | if (write_lock) | ||
| 226 | s->mtx.Lock(); | ||
| 227 | else | ||
| 228 | s->mtx.ReadLock(); | ||
| 229 | return s; | ||
| 230 | } | ||
| 231 | idx = s->next; | ||
| 232 | } | ||
| 233 | if (!create) | ||
| 234 | return 0; | ||
| 235 | if (*meta != idx0) { | ||
| 236 | idx0 = *meta; | ||
| 237 | continue; | ||
| 238 | } | ||
| 239 | |||
| 240 | if (myidx == 0) { | ||
| 241 | const u64 uid = atomic_fetch_add(&uid_gen_, 1, memory_order_relaxed); | ||
| 242 | myidx = sync_alloc_.Alloc(&thr->proc()->sync_cache); | ||
| 243 | mys = sync_alloc_.Map(myidx); | ||
| 244 | mys->Init(thr, pc, addr, uid); | ||
| 245 | } | ||
| 246 | mys->next = idx0; | ||
| 247 | if (atomic_compare_exchange_strong((atomic_uint32_t*)meta, &idx0, | ||
| 248 | myidx | kFlagSync, memory_order_release)) { | ||
| 249 | if (write_lock) | ||
| 250 | mys->mtx.Lock(); | ||
| 251 | else | ||
| 252 | mys->mtx.ReadLock(); | ||
| 253 | return mys; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | } | ||
| 257 | |||
| 258 | void MetaMap::MoveMemory(uptr src, uptr dst, uptr sz) { | ||
| 259 | // src and dst can overlap, | ||
| 260 | // there are no concurrent accesses to the regions (e.g. stop-the-world). | ||
| 261 | CHECK_NE(src, dst); | ||
| 262 | CHECK_NE(sz, 0); | ||
| 263 | uptr diff = dst - src; | ||
| 264 | u32 *src_meta = MemToMeta(src); | ||
| 265 | u32 *dst_meta = MemToMeta(dst); | ||
| 266 | u32 *src_meta_end = MemToMeta(src + sz); | ||
| 267 | uptr inc = 1; | ||
| 268 | if (dst > src) { | ||
| 269 | src_meta = MemToMeta(src + sz) - 1; | ||
| 270 | dst_meta = MemToMeta(dst + sz) - 1; | ||
| 271 | src_meta_end = MemToMeta(src) - 1; | ||
| 272 | inc = -1; | ||
| 273 | } | ||
| 274 | for (; src_meta != src_meta_end; src_meta += inc, dst_meta += inc) { | ||
| 275 | CHECK_EQ(*dst_meta, 0); | ||
| 276 | u32 idx = *src_meta; | ||
| 277 | *src_meta = 0; | ||
| 278 | *dst_meta = idx; | ||
| 279 | // Patch the addresses in sync objects. | ||
| 280 | while (idx != 0) { | ||
| 281 | if (idx & kFlagBlock) | ||
| 282 | break; | ||
| 283 | CHECK(idx & kFlagSync); | ||
| 284 | SyncVar *s = sync_alloc_.Map(idx & ~kFlagMask); | ||
| 285 | s->addr += diff; | ||
| 286 | idx = s->next; | ||
| 287 | } | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 291 | void MetaMap::OnProcIdle(Processor *proc) { | ||
| 292 | block_alloc_.FlushCache(&proc->block_cache); | ||
| 293 | sync_alloc_.FlushCache(&proc->sync_cache); | ||
| 294 | } | ||
| 295 | |||
| 296 | } // namespace __tsan | ||
lib/tsan/tsan_sync.h created+145| ... | @@ -0,0 +1,145 @@ | ||
| 1 | //===-- tsan_sync.h ---------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef TSAN_SYNC_H | ||
| 13 | #define TSAN_SYNC_H | ||
| 14 | |||
| 15 | #include "sanitizer_common/sanitizer_atomic.h" | ||
| 16 | #include "sanitizer_common/sanitizer_common.h" | ||
| 17 | #include "sanitizer_common/sanitizer_deadlock_detector_interface.h" | ||
| 18 | #include "tsan_defs.h" | ||
| 19 | #include "tsan_clock.h" | ||
| 20 | #include "tsan_mutex.h" | ||
| 21 | #include "tsan_dense_alloc.h" | ||
| 22 | |||
| 23 | namespace __tsan { | ||
| 24 | |||
| 25 | // These need to match __tsan_mutex_* flags defined in tsan_interface.h. | ||
| 26 | // See documentation there as well. | ||
| 27 | enum MutexFlags { | ||
| 28 | MutexFlagLinkerInit = 1 << 0, // __tsan_mutex_linker_init | ||
| 29 | MutexFlagWriteReentrant = 1 << 1, // __tsan_mutex_write_reentrant | ||
| 30 | MutexFlagReadReentrant = 1 << 2, // __tsan_mutex_read_reentrant | ||
| 31 | MutexFlagReadLock = 1 << 3, // __tsan_mutex_read_lock | ||
| 32 | MutexFlagTryLock = 1 << 4, // __tsan_mutex_try_lock | ||
| 33 | MutexFlagTryLockFailed = 1 << 5, // __tsan_mutex_try_lock_failed | ||
| 34 | MutexFlagRecursiveLock = 1 << 6, // __tsan_mutex_recursive_lock | ||
| 35 | MutexFlagRecursiveUnlock = 1 << 7, // __tsan_mutex_recursive_unlock | ||
| 36 | MutexFlagNotStatic = 1 << 8, // __tsan_mutex_not_static | ||
| 37 | |||
| 38 | // The following flags are runtime private. | ||
| 39 | // Mutex API misuse was detected, so don't report any more. | ||
| 40 | MutexFlagBroken = 1 << 30, | ||
| 41 | // We did not intercept pre lock event, so handle it on post lock. | ||
| 42 | MutexFlagDoPreLockOnPostLock = 1 << 29, | ||
| 43 | // Must list all mutex creation flags. | ||
| 44 | MutexCreationFlagMask = MutexFlagLinkerInit | | ||
| 45 | MutexFlagWriteReentrant | | ||
| 46 | MutexFlagReadReentrant | | ||
| 47 | MutexFlagNotStatic, | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct SyncVar { | ||
| 51 | SyncVar(); | ||
| 52 | |||
| 53 | static const int kInvalidTid = -1; | ||
| 54 | |||
| 55 | uptr addr; // overwritten by DenseSlabAlloc freelist | ||
| 56 | Mutex mtx; | ||
| 57 | u64 uid; // Globally unique id. | ||
| 58 | u32 creation_stack_id; | ||
| 59 | int owner_tid; // Set only by exclusive owners. | ||
| 60 | u64 last_lock; | ||
| 61 | int recursion; | ||
| 62 | atomic_uint32_t flags; | ||
| 63 | u32 next; // in MetaMap | ||
| 64 | DDMutex dd; | ||
| 65 | SyncClock read_clock; // Used for rw mutexes only. | ||
| 66 | // The clock is placed last, so that it is situated on a different cache line | ||
| 67 | // with the mtx. This reduces contention for hot sync objects. | ||
| 68 | SyncClock clock; | ||
| 69 | |||
| 70 | void Init(ThreadState *thr, uptr pc, uptr addr, u64 uid); | ||
| 71 | void Reset(Processor *proc); | ||
| 72 | |||
| 73 | u64 GetId() const { | ||
| 74 | // 48 lsb is addr, then 14 bits is low part of uid, then 2 zero bits. | ||
| 75 | return GetLsb((u64)addr | (uid << 48), 60); | ||
| 76 | } | ||
| 77 | bool CheckId(u64 uid) const { | ||
| 78 | CHECK_EQ(uid, GetLsb(uid, 14)); | ||
| 79 | return GetLsb(this->uid, 14) == uid; | ||
| 80 | } | ||
| 81 | static uptr SplitId(u64 id, u64 *uid) { | ||
| 82 | *uid = id >> 48; | ||
| 83 | return (uptr)GetLsb(id, 48); | ||
| 84 | } | ||
| 85 | |||
| 86 | bool IsFlagSet(u32 f) const { | ||
| 87 | return atomic_load_relaxed(&flags) & f; | ||
| 88 | } | ||
| 89 | |||
| 90 | void SetFlags(u32 f) { | ||
| 91 | atomic_store_relaxed(&flags, atomic_load_relaxed(&flags) | f); | ||
| 92 | } | ||
| 93 | |||
| 94 | void UpdateFlags(u32 flagz) { | ||
| 95 | // Filter out operation flags. | ||
| 96 | if (!(flagz & MutexCreationFlagMask)) | ||
| 97 | return; | ||
| 98 | u32 current = atomic_load_relaxed(&flags); | ||
| 99 | if (current & MutexCreationFlagMask) | ||
| 100 | return; | ||
| 101 | // Note: this can be called from MutexPostReadLock which holds only read | ||
| 102 | // lock on the SyncVar. | ||
| 103 | atomic_store_relaxed(&flags, current | (flagz & MutexCreationFlagMask)); | ||
| 104 | } | ||
| 105 | }; | ||
| 106 | |||
| 107 | /* MetaMap allows to map arbitrary user pointers onto various descriptors. | ||
| 108 | Currently it maps pointers to heap block descriptors and sync var descs. | ||
| 109 | It uses 1/2 direct shadow, see tsan_platform.h. | ||
| 110 | */ | ||
| 111 | class MetaMap { | ||
| 112 | public: | ||
| 113 | MetaMap(); | ||
| 114 | |||
| 115 | void AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz); | ||
| 116 | uptr FreeBlock(Processor *proc, uptr p); | ||
| 117 | bool FreeRange(Processor *proc, uptr p, uptr sz); | ||
| 118 | void ResetRange(Processor *proc, uptr p, uptr sz); | ||
| 119 | MBlock* GetBlock(uptr p); | ||
| 120 | |||
| 121 | SyncVar* GetOrCreateAndLock(ThreadState *thr, uptr pc, | ||
| 122 | uptr addr, bool write_lock); | ||
| 123 | SyncVar* GetIfExistsAndLock(uptr addr, bool write_lock); | ||
| 124 | |||
| 125 | void MoveMemory(uptr src, uptr dst, uptr sz); | ||
| 126 | |||
| 127 | void OnProcIdle(Processor *proc); | ||
| 128 | |||
| 129 | private: | ||
| 130 | static const u32 kFlagMask = 3u << 30; | ||
| 131 | static const u32 kFlagBlock = 1u << 30; | ||
| 132 | static const u32 kFlagSync = 2u << 30; | ||
| 133 | typedef DenseSlabAlloc<MBlock, 1<<16, 1<<12> BlockAlloc; | ||
| 134 | typedef DenseSlabAlloc<SyncVar, 1<<16, 1<<10> SyncAlloc; | ||
| 135 | BlockAlloc block_alloc_; | ||
| 136 | SyncAlloc sync_alloc_; | ||
| 137 | atomic_uint64_t uid_gen_; | ||
| 138 | |||
| 139 | SyncVar* GetAndLock(ThreadState *thr, uptr pc, uptr addr, bool write_lock, | ||
| 140 | bool create); | ||
| 141 | }; | ||
| 142 | |||
| 143 | } // namespace __tsan | ||
| 144 | |||
| 145 | #endif // TSAN_SYNC_H | ||
lib/tsan/tsan_trace.h created+75| ... | @@ -0,0 +1,75 @@ | ||
| 1 | //===-- tsan_trace.h --------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef TSAN_TRACE_H | ||
| 13 | #define TSAN_TRACE_H | ||
| 14 | |||
| 15 | #include "tsan_defs.h" | ||
| 16 | #include "tsan_mutex.h" | ||
| 17 | #include "tsan_stack_trace.h" | ||
| 18 | #include "tsan_mutexset.h" | ||
| 19 | |||
| 20 | namespace __tsan { | ||
| 21 | |||
| 22 | const int kTracePartSizeBits = 13; | ||
| 23 | const int kTracePartSize = 1 << kTracePartSizeBits; | ||
| 24 | const int kTraceParts = 2 * 1024 * 1024 / kTracePartSize; | ||
| 25 | const int kTraceSize = kTracePartSize * kTraceParts; | ||
| 26 | |||
| 27 | // Must fit into 3 bits. | ||
| 28 | enum EventType { | ||
| 29 | EventTypeMop, | ||
| 30 | EventTypeFuncEnter, | ||
| 31 | EventTypeFuncExit, | ||
| 32 | EventTypeLock, | ||
| 33 | EventTypeUnlock, | ||
| 34 | EventTypeRLock, | ||
| 35 | EventTypeRUnlock | ||
| 36 | }; | ||
| 37 | |||
| 38 | // Represents a thread event (from most significant bit): | ||
| 39 | // u64 typ : 3; // EventType. | ||
| 40 | // u64 addr : 61; // Associated pc. | ||
| 41 | typedef u64 Event; | ||
| 42 | |||
| 43 | const uptr kEventPCBits = 61; | ||
| 44 | |||
| 45 | struct TraceHeader { | ||
| 46 | #if !SANITIZER_GO | ||
| 47 | BufferedStackTrace stack0; // Start stack for the trace. | ||
| 48 | #else | ||
| 49 | VarSizeStackTrace stack0; | ||
| 50 | #endif | ||
| 51 | u64 epoch0; // Start epoch for the trace. | ||
| 52 | MutexSet mset0; | ||
| 53 | |||
| 54 | TraceHeader() : stack0(), epoch0() {} | ||
| 55 | }; | ||
| 56 | |||
| 57 | struct Trace { | ||
| 58 | Mutex mtx; | ||
| 59 | #if !SANITIZER_GO | ||
| 60 | // Must be last to catch overflow as paging fault. | ||
| 61 | // Go shadow stack is dynamically allocated. | ||
| 62 | uptr shadow_stack[kShadowStackSize]; | ||
| 63 | #endif | ||
| 64 | // Must be the last field, because we unmap the unused part in | ||
| 65 | // CreateThreadContext. | ||
| 66 | TraceHeader headers[kTraceParts]; | ||
| 67 | |||
| 68 | Trace() | ||
| 69 | : mtx(MutexTypeTrace, StatMtxTrace) { | ||
| 70 | } | ||
| 71 | }; | ||
| 72 | |||
| 73 | } // namespace __tsan | ||
| 74 | |||
| 75 | #endif // TSAN_TRACE_H | ||
lib/tsan/tsan_update_shadow_word_inl.h created+69| ... | @@ -0,0 +1,69 @@ | ||
| 1 | //===-- tsan_update_shadow_word_inl.h ---------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // This file is a part of ThreadSanitizer (TSan), a race detector. | ||
| 10 | // | ||
| 11 | // Body of the hottest inner loop. | ||
| 12 | // If we wrap this body into a function, compilers (both gcc and clang) | ||
| 13 | // produce sligtly less efficient code. | ||
| 14 | //===----------------------------------------------------------------------===// | ||
| 15 | do { | ||
| 16 | StatInc(thr, StatShadowProcessed); | ||
| 17 | const unsigned kAccessSize = 1 << kAccessSizeLog; | ||
| 18 | u64 *sp = &shadow_mem[idx]; | ||
| 19 | old = LoadShadow(sp); | ||
| 20 | if (LIKELY(old.IsZero())) { | ||
| 21 | StatInc(thr, StatShadowZero); | ||
| 22 | if (!stored) { | ||
| 23 | StoreIfNotYetStored(sp, &store_word); | ||
| 24 | stored = true; | ||
| 25 | } | ||
| 26 | break; | ||
| 27 | } | ||
| 28 | // is the memory access equal to the previous? | ||
| 29 | if (LIKELY(Shadow::Addr0AndSizeAreEqual(cur, old))) { | ||
| 30 | StatInc(thr, StatShadowSameSize); | ||
| 31 | // same thread? | ||
| 32 | if (LIKELY(Shadow::TidsAreEqual(old, cur))) { | ||
| 33 | StatInc(thr, StatShadowSameThread); | ||
| 34 | if (LIKELY(old.IsRWWeakerOrEqual(kAccessIsWrite, kIsAtomic))) { | ||
| 35 | StoreIfNotYetStored(sp, &store_word); | ||
| 36 | stored = true; | ||
| 37 | } | ||
| 38 | break; | ||
| 39 | } | ||
| 40 | StatInc(thr, StatShadowAnotherThread); | ||
| 41 | if (HappensBefore(old, thr)) { | ||
| 42 | if (old.IsRWWeakerOrEqual(kAccessIsWrite, kIsAtomic)) { | ||
| 43 | StoreIfNotYetStored(sp, &store_word); | ||
| 44 | stored = true; | ||
| 45 | } | ||
| 46 | break; | ||
| 47 | } | ||
| 48 | if (LIKELY(old.IsBothReadsOrAtomic(kAccessIsWrite, kIsAtomic))) | ||
| 49 | break; | ||
| 50 | goto RACE; | ||
| 51 | } | ||
| 52 | // Do the memory access intersect? | ||
| 53 | if (Shadow::TwoRangesIntersect(old, cur, kAccessSize)) { | ||
| 54 | StatInc(thr, StatShadowIntersect); | ||
| 55 | if (Shadow::TidsAreEqual(old, cur)) { | ||
| 56 | StatInc(thr, StatShadowSameThread); | ||
| 57 | break; | ||
| 58 | } | ||
| 59 | StatInc(thr, StatShadowAnotherThread); | ||
| 60 | if (old.IsBothReadsOrAtomic(kAccessIsWrite, kIsAtomic)) | ||
| 61 | break; | ||
| 62 | if (LIKELY(HappensBefore(old, thr))) | ||
| 63 | break; | ||
| 64 | goto RACE; | ||
| 65 | } | ||
| 66 | // The accesses do not intersect. | ||
| 67 | StatInc(thr, StatShadowNotIntersect); | ||
| 68 | break; | ||
| 69 | } while (0); | ||
lib/tsan/ubsan/ubsan_flags.h created+48| ... | @@ -0,0 +1,48 @@ | ||
| 1 | //===-- ubsan_flags.h -------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Runtime flags for UndefinedBehaviorSanitizer. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef UBSAN_FLAGS_H | ||
| 13 | #define UBSAN_FLAGS_H | ||
| 14 | |||
| 15 | #include "sanitizer_common/sanitizer_internal_defs.h" | ||
| 16 | |||
| 17 | namespace __sanitizer { | ||
| 18 | class FlagParser; | ||
| 19 | } | ||
| 20 | |||
| 21 | namespace __ubsan { | ||
| 22 | |||
| 23 | struct Flags { | ||
| 24 | #define UBSAN_FLAG(Type, Name, DefaultValue, Description) Type Name; | ||
| 25 | #include "ubsan_flags.inc" | ||
| 26 | #undef UBSAN_FLAG | ||
| 27 | |||
| 28 | void SetDefaults(); | ||
| 29 | }; | ||
| 30 | |||
| 31 | extern Flags ubsan_flags; | ||
| 32 | inline Flags *flags() { return &ubsan_flags; } | ||
| 33 | |||
| 34 | void InitializeFlags(); | ||
| 35 | void RegisterUbsanFlags(FlagParser *parser, Flags *f); | ||
| 36 | |||
| 37 | const char *MaybeCallUbsanDefaultOptions(); | ||
| 38 | |||
| 39 | } // namespace __ubsan | ||
| 40 | |||
| 41 | extern "C" { | ||
| 42 | // Users may provide their own implementation of __ubsan_default_options to | ||
| 43 | // override the default flag values. | ||
| 44 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE | ||
| 45 | const char *__ubsan_default_options(); | ||
| 46 | } // extern "C" | ||
| 47 | |||
| 48 | #endif // UBSAN_FLAGS_H | ||
lib/tsan/ubsan/ubsan_flags.inc created+28| ... | @@ -0,0 +1,28 @@ | ||
| 1 | //===-- ubsan_flags.inc -----------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // UBSan runtime flags. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef UBSAN_FLAG | ||
| 13 | # error "Define UBSAN_FLAG prior to including this file!" | ||
| 14 | #endif | ||
| 15 | |||
| 16 | // UBSAN_FLAG(Type, Name, DefaultValue, Description) | ||
| 17 | // See COMMON_FLAG in sanitizer_flags.inc for more details. | ||
| 18 | |||
| 19 | UBSAN_FLAG(bool, halt_on_error, false, | ||
| 20 | "Crash the program after printing the first error report") | ||
| 21 | UBSAN_FLAG(bool, print_stacktrace, false, | ||
| 22 | "Include full stacktrace into an error report") | ||
| 23 | UBSAN_FLAG(const char *, suppressions, "", "Suppressions file name.") | ||
| 24 | UBSAN_FLAG(bool, report_error_type, false, | ||
| 25 | "Print specific error type instead of 'undefined-behavior' in summary.") | ||
| 26 | UBSAN_FLAG(bool, silence_unsigned_overflow, false, | ||
| 27 | "Do not print non-fatal error reports for unsigned integer overflow. " | ||
| 28 | "Used to provide fuzzing signal without blowing up logs.") | ||
lib/tsan/ubsan/ubsan_init.h created+33| ... | @@ -0,0 +1,33 @@ | ||
| 1 | //===-- ubsan_init.h --------------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Initialization function for UBSan runtime. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef UBSAN_INIT_H | ||
| 13 | #define UBSAN_INIT_H | ||
| 14 | |||
| 15 | namespace __ubsan { | ||
| 16 | |||
| 17 | // Get the full tool name for UBSan. | ||
| 18 | const char *GetSanititizerToolName(); | ||
| 19 | |||
| 20 | // Initialize UBSan as a standalone tool. Typically should be called early | ||
| 21 | // during initialization. | ||
| 22 | void InitAsStandalone(); | ||
| 23 | |||
| 24 | // Initialize UBSan as a standalone tool, if it hasn't been initialized before. | ||
| 25 | void InitAsStandaloneIfNecessary(); | ||
| 26 | |||
| 27 | // Initializes UBSan as a plugin tool. This function should be called once | ||
| 28 | // from "parent tool" (e.g. ASan) initialization. | ||
| 29 | void InitAsPlugin(); | ||
| 30 | |||
| 31 | } // namespace __ubsan | ||
| 32 | |||
| 33 | #endif // UBSAN_INIT_H | ||
lib/tsan/ubsan/ubsan_platform.h created+25| ... | @@ -0,0 +1,25 @@ | ||
| 1 | //===-- ubsan_platform.h ----------------------------------------*- C++ -*-===// | ||
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | // | ||
| 9 | // Defines the platforms which UBSan is supported at. | ||
| 10 | // | ||
| 11 | //===----------------------------------------------------------------------===// | ||
| 12 | #ifndef UBSAN_PLATFORM_H | ||
| 13 | #define UBSAN_PLATFORM_H | ||
| 14 | |||
| 15 | // Other platforms should be easy to add, and probably work as-is. | ||
| 16 | #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ | ||
| 17 | defined(__NetBSD__) || defined(__OpenBSD__) || \ | ||
| 18 | (defined(__sun__) && defined(__svr4__)) || \ | ||
| 19 | defined(_WIN32) || defined(__Fuchsia__) || defined(__rtems__) | ||
| 20 | # define CAN_SANITIZE_UB 1 | ||
| 21 | #else | ||
| 22 | # define CAN_SANITIZE_UB 0 | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #endif | ||
src/Compilation.zig+28-2| ... | @@ -30,6 +30,7 @@ const c_codegen = @import("codegen/c.zig"); | ... | @@ -30,6 +30,7 @@ const c_codegen = @import("codegen/c.zig"); |
| 30 | const c_link = @import("link/C.zig"); | 30 | const c_link = @import("link/C.zig"); |
| 31 | const ThreadPool = @import("ThreadPool.zig"); | 31 | const ThreadPool = @import("ThreadPool.zig"); |
| 32 | const WaitGroup = @import("WaitGroup.zig"); | 32 | const WaitGroup = @import("WaitGroup.zig"); |
| 33 | const libtsan = @import("libtsan.zig"); | ||
| 33 | 34 | ||
| 34 | /// General-purpose allocator. Used for both temporary and long-term storage. | 35 | /// General-purpose allocator. Used for both temporary and long-term storage. |
| 35 | gpa: *Allocator, | 36 | gpa: *Allocator, |
| ... | @@ -94,6 +95,9 @@ libcxxabi_static_lib: ?CRTFile = null, | ... | @@ -94,6 +95,9 @@ libcxxabi_static_lib: ?CRTFile = null, |
| 94 | /// Populated when we build the libunwind static library. A Job to build this is placed in the queue | 95 | /// Populated when we build the libunwind static library. A Job to build this is placed in the queue |
| 95 | /// and resolved before calling linker.flush(). | 96 | /// and resolved before calling linker.flush(). |
| 96 | libunwind_static_lib: ?CRTFile = null, | 97 | libunwind_static_lib: ?CRTFile = null, |
| 98 | /// Populated when we build the TSAN static library. A Job to build this is placed in the queue | ||
| 99 | /// and resolved before calling linker.flush(). | ||
| 100 | tsan_static_lib: ?CRTFile = null, | ||
| 97 | /// Populated when we build the libssp static library. A Job to build this is placed in the queue | 101 | /// Populated when we build the libssp static library. A Job to build this is placed in the queue |
| 98 | /// and resolved before calling linker.flush(). | 102 | /// and resolved before calling linker.flush(). |
| 99 | libssp_static_lib: ?CRTFile = null, | 103 | libssp_static_lib: ?CRTFile = null, |
| ... | @@ -179,6 +183,7 @@ const Job = union(enum) { | ... | @@ -179,6 +183,7 @@ const Job = union(enum) { |
| 179 | libunwind: void, | 183 | libunwind: void, |
| 180 | libcxx: void, | 184 | libcxx: void, |
| 181 | libcxxabi: void, | 185 | libcxxabi: void, |
| 186 | libtsan: void, | ||
| 182 | libssp: void, | 187 | libssp: void, |
| 183 | compiler_rt_lib: void, | 188 | compiler_rt_lib: void, |
| 184 | compiler_rt_obj: void, | 189 | compiler_rt_obj: void, |
| ... | @@ -388,6 +393,7 @@ pub const InitOptions = struct { | ... | @@ -388,6 +393,7 @@ pub const InitOptions = struct { |
| 388 | want_sanitize_c: ?bool = null, | 393 | want_sanitize_c: ?bool = null, |
| 389 | want_stack_check: ?bool = null, | 394 | want_stack_check: ?bool = null, |
| 390 | want_valgrind: ?bool = null, | 395 | want_valgrind: ?bool = null, |
| 396 | want_tsan: ?bool = null, | ||
| 391 | want_compiler_rt: ?bool = null, | 397 | want_compiler_rt: ?bool = null, |
| 392 | use_llvm: ?bool = null, | 398 | use_llvm: ?bool = null, |
| 393 | use_lld: ?bool = null, | 399 | use_lld: ?bool = null, |
| ... | @@ -644,13 +650,15 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -644,13 +650,15 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 644 | options.libc_installation, | 650 | options.libc_installation, |
| 645 | ); | 651 | ); |
| 646 | 652 | ||
| 653 | const tsan = options.want_tsan orelse false; | ||
| 654 | |||
| 647 | const must_pie = target_util.requiresPIE(options.target); | 655 | const must_pie = target_util.requiresPIE(options.target); |
| 648 | const pie = if (options.want_pie) |explicit| pie: { | 656 | const pie: bool = if (options.want_pie) |explicit| pie: { |
| 649 | if (!explicit and must_pie) { | 657 | if (!explicit and must_pie) { |
| 650 | return error.TargetRequiresPIE; | 658 | return error.TargetRequiresPIE; |
| 651 | } | 659 | } |
| 652 | break :pie explicit; | 660 | break :pie explicit; |
| 653 | } else must_pie; | 661 | } else must_pie or tsan; |
| 654 | 662 | ||
| 655 | const must_pic: bool = b: { | 663 | const must_pic: bool = b: { |
| 656 | if (target_util.requiresPIC(options.target, link_libc)) | 664 | if (target_util.requiresPIC(options.target, link_libc)) |
| ... | @@ -751,6 +759,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -751,6 +759,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 751 | cache.hash.add(ofmt); | 759 | cache.hash.add(ofmt); |
| 752 | cache.hash.add(pic); | 760 | cache.hash.add(pic); |
| 753 | cache.hash.add(pie); | 761 | cache.hash.add(pie); |
| 762 | cache.hash.add(tsan); | ||
| 754 | cache.hash.add(stack_check); | 763 | cache.hash.add(stack_check); |
| 755 | cache.hash.add(link_mode); | 764 | cache.hash.add(link_mode); |
| 756 | cache.hash.add(options.function_sections); | 765 | cache.hash.add(options.function_sections); |
| ... | @@ -953,6 +962,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -953,6 +962,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 953 | .pic = pic, | 962 | .pic = pic, |
| 954 | .pie = pie, | 963 | .pie = pie, |
| 955 | .valgrind = valgrind, | 964 | .valgrind = valgrind, |
| 965 | .tsan = tsan, | ||
| 956 | .stack_check = stack_check, | 966 | .stack_check = stack_check, |
| 957 | .single_threaded = single_threaded, | 967 | .single_threaded = single_threaded, |
| 958 | .verbose_link = options.verbose_link, | 968 | .verbose_link = options.verbose_link, |
| ... | @@ -1093,6 +1103,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -1093,6 +1103,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1093 | try comp.work_queue.writeItem(.libcxx); | 1103 | try comp.work_queue.writeItem(.libcxx); |
| 1094 | try comp.work_queue.writeItem(.libcxxabi); | 1104 | try comp.work_queue.writeItem(.libcxxabi); |
| 1095 | } | 1105 | } |
| 1106 | if (build_options.have_llvm and comp.bin_file.options.tsan) { | ||
| 1107 | try comp.work_queue.writeItem(.libtsan); | ||
| 1108 | } | ||
| 1096 | 1109 | ||
| 1097 | // The `is_stage1` condition is here only because stage2 cannot yet build compiler-rt. | 1110 | // The `is_stage1` condition is here only because stage2 cannot yet build compiler-rt. |
| 1098 | // Once it is capable this condition should be removed. | 1111 | // Once it is capable this condition should be removed. |
| ... | @@ -1569,6 +1582,12 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor | ... | @@ -1569,6 +1582,12 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 1569 | fatal("unable to build libcxxabi: {}", .{@errorName(err)}); | 1582 | fatal("unable to build libcxxabi: {}", .{@errorName(err)}); |
| 1570 | }; | 1583 | }; |
| 1571 | }, | 1584 | }, |
| 1585 | .libtsan => { | ||
| 1586 | libtsan.buildTsan(self) catch |err| { | ||
| 1587 | // TODO Expose this as a normal compile error rather than crashing here. | ||
| 1588 | fatal("unable to build TSAN library: {}", .{@errorName(err)}); | ||
| 1589 | }; | ||
| 1590 | }, | ||
| 1572 | .compiler_rt_lib => { | 1591 | .compiler_rt_lib => { |
| 1573 | self.buildOutputFromZig("compiler_rt.zig", .Lib, &self.compiler_rt_static_lib) catch |err| { | 1592 | self.buildOutputFromZig("compiler_rt.zig", .Lib, &self.compiler_rt_static_lib) catch |err| { |
| 1574 | // TODO Expose this as a normal compile error rather than crashing here. | 1593 | // TODO Expose this as a normal compile error rather than crashing here. |
| ... | @@ -2052,6 +2071,10 @@ pub fn addCCArgs( | ... | @@ -2052,6 +2071,10 @@ pub fn addCCArgs( |
| 2052 | try argv.append("-ffunction-sections"); | 2071 | try argv.append("-ffunction-sections"); |
| 2053 | } | 2072 | } |
| 2054 | 2073 | ||
| 2074 | if (comp.bin_file.options.tsan) { | ||
| 2075 | try argv.append("-fsanitize=thread"); | ||
| 2076 | } | ||
| 2077 | |||
| 2055 | try argv.ensureCapacity(argv.items.len + comp.bin_file.options.framework_dirs.len * 2); | 2078 | try argv.ensureCapacity(argv.items.len + comp.bin_file.options.framework_dirs.len * 2); |
| 2056 | for (comp.bin_file.options.framework_dirs) |framework_dir| { | 2079 | for (comp.bin_file.options.framework_dirs) |framework_dir| { |
| 2057 | argv.appendAssumeCapacity("-iframework"); | 2080 | argv.appendAssumeCapacity("-iframework"); |
| ... | @@ -2887,6 +2910,7 @@ fn buildOutputFromZig( | ... | @@ -2887,6 +2910,7 @@ fn buildOutputFromZig( |
| 2887 | .want_sanitize_c = false, | 2910 | .want_sanitize_c = false, |
| 2888 | .want_stack_check = false, | 2911 | .want_stack_check = false, |
| 2889 | .want_valgrind = false, | 2912 | .want_valgrind = false, |
| 2913 | .want_tsan = false, | ||
| 2890 | .want_pic = comp.bin_file.options.pic, | 2914 | .want_pic = comp.bin_file.options.pic, |
| 2891 | .want_pie = comp.bin_file.options.pie, | 2915 | .want_pie = comp.bin_file.options.pie, |
| 2892 | .emit_h = null, | 2916 | .emit_h = null, |
| ... | @@ -3115,6 +3139,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node | ... | @@ -3115,6 +3139,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node |
| 3115 | .dll_export_fns = comp.bin_file.options.dll_export_fns, | 3139 | .dll_export_fns = comp.bin_file.options.dll_export_fns, |
| 3116 | .link_mode_dynamic = comp.bin_file.options.link_mode == .Dynamic, | 3140 | .link_mode_dynamic = comp.bin_file.options.link_mode == .Dynamic, |
| 3117 | .valgrind_enabled = comp.bin_file.options.valgrind, | 3141 | .valgrind_enabled = comp.bin_file.options.valgrind, |
| 3142 | .tsan_enabled = comp.bin_file.options.tsan, | ||
| 3118 | .function_sections = comp.bin_file.options.function_sections, | 3143 | .function_sections = comp.bin_file.options.function_sections, |
| 3119 | .enable_stack_probing = comp.bin_file.options.stack_check, | 3144 | .enable_stack_probing = comp.bin_file.options.stack_check, |
| 3120 | .enable_time_report = comp.time_report, | 3145 | .enable_time_report = comp.time_report, |
| ... | @@ -3262,6 +3287,7 @@ pub fn build_crt_file( | ... | @@ -3262,6 +3287,7 @@ pub fn build_crt_file( |
| 3262 | .want_sanitize_c = false, | 3287 | .want_sanitize_c = false, |
| 3263 | .want_stack_check = false, | 3288 | .want_stack_check = false, |
| 3264 | .want_valgrind = false, | 3289 | .want_valgrind = false, |
| 3290 | .want_tsan = false, | ||
| 3265 | .want_pic = comp.bin_file.options.pic, | 3291 | .want_pic = comp.bin_file.options.pic, |
| 3266 | .want_pie = comp.bin_file.options.pie, | 3292 | .want_pie = comp.bin_file.options.pie, |
| 3267 | .emit_h = null, | 3293 | .emit_h = null, |
src/glibc.zig+1| ... | @@ -943,6 +943,7 @@ fn buildSharedLib( | ... | @@ -943,6 +943,7 @@ fn buildSharedLib( |
| 943 | .want_sanitize_c = false, | 943 | .want_sanitize_c = false, |
| 944 | .want_stack_check = false, | 944 | .want_stack_check = false, |
| 945 | .want_valgrind = false, | 945 | .want_valgrind = false, |
| 946 | .want_tsan = false, | ||
| 946 | .emit_h = null, | 947 | .emit_h = null, |
| 947 | .strip = comp.bin_file.options.strip, | 948 | .strip = comp.bin_file.options.strip, |
| 948 | .is_native_os = false, | 949 | .is_native_os = false, |
src/libcxx.zig+2-1| ... | @@ -139,7 +139,6 @@ pub fn buildLibCXX(comp: *Compilation) !void { | ... | @@ -139,7 +139,6 @@ pub fn buildLibCXX(comp: *Compilation) !void { |
| 139 | try cflags.append(cxxabi_include_path); | 139 | try cflags.append(cxxabi_include_path); |
| 140 | 140 | ||
| 141 | try cflags.append("-O3"); | 141 | try cflags.append("-O3"); |
| 142 | try cflags.append("-DNDEBUG"); | ||
| 143 | if (target_util.supports_fpic(target)) { | 142 | if (target_util.supports_fpic(target)) { |
| 144 | try cflags.append("-fPIC"); | 143 | try cflags.append("-fPIC"); |
| 145 | } | 144 | } |
| ... | @@ -170,6 +169,7 @@ pub fn buildLibCXX(comp: *Compilation) !void { | ... | @@ -170,6 +169,7 @@ pub fn buildLibCXX(comp: *Compilation) !void { |
| 170 | .want_sanitize_c = false, | 169 | .want_sanitize_c = false, |
| 171 | .want_stack_check = false, | 170 | .want_stack_check = false, |
| 172 | .want_valgrind = false, | 171 | .want_valgrind = false, |
| 172 | .want_tsan = comp.bin_file.options.tsan, | ||
| 173 | .want_pic = comp.bin_file.options.pic, | 173 | .want_pic = comp.bin_file.options.pic, |
| 174 | .want_pie = comp.bin_file.options.pie, | 174 | .want_pie = comp.bin_file.options.pie, |
| 175 | .emit_h = null, | 175 | .emit_h = null, |
| ... | @@ -289,6 +289,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void { | ... | @@ -289,6 +289,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void { |
| 289 | .want_sanitize_c = false, | 289 | .want_sanitize_c = false, |
| 290 | .want_stack_check = false, | 290 | .want_stack_check = false, |
| 291 | .want_valgrind = false, | 291 | .want_valgrind = false, |
| 292 | .want_tsan = comp.bin_file.options.tsan, | ||
| 292 | .want_pic = comp.bin_file.options.pic, | 293 | .want_pic = comp.bin_file.options.pic, |
| 293 | .want_pie = comp.bin_file.options.pie, | 294 | .want_pie = comp.bin_file.options.pie, |
| 294 | .emit_h = null, | 295 | .emit_h = null, |
src/libtsan.zig created+219| ... | @@ -0,0 +1,219 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | |||
| 4 | const Compilation = @import("Compilation.zig"); | ||
| 5 | const build_options = @import("build_options"); | ||
| 6 | const trace = @import("tracy.zig").trace; | ||
| 7 | |||
| 8 | pub fn buildTsan(comp: *Compilation) !void { | ||
| 9 | if (!build_options.have_llvm) { | ||
| 10 | return error.ZigCompilerNotBuiltWithLLVMExtensions; | ||
| 11 | } | ||
| 12 | |||
| 13 | const tracy = trace(@src()); | ||
| 14 | defer tracy.end(); | ||
| 15 | |||
| 16 | var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); | ||
| 17 | defer arena_allocator.deinit(); | ||
| 18 | const arena = &arena_allocator.allocator; | ||
| 19 | |||
| 20 | const root_name = "tsan"; | ||
| 21 | const output_mode = .Lib; | ||
| 22 | const link_mode = .Static; | ||
| 23 | const target = comp.getTarget(); | ||
| 24 | const basename = try std.zig.binNameAlloc(arena, .{ | ||
| 25 | .root_name = root_name, | ||
| 26 | .target = target, | ||
| 27 | .output_mode = output_mode, | ||
| 28 | .link_mode = link_mode, | ||
| 29 | }); | ||
| 30 | |||
| 31 | const emit_bin = Compilation.EmitLoc{ | ||
| 32 | .directory = null, // Put it in the cache directory. | ||
| 33 | .basename = basename, | ||
| 34 | }; | ||
| 35 | |||
| 36 | var c_source_files = std.ArrayList(Compilation.CSourceFile).init(arena); | ||
| 37 | try c_source_files.ensureCapacity(tsan_sources.len + sanitizer_common_sources.len); | ||
| 38 | |||
| 39 | const tsan_include_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"tsan"}); | ||
| 40 | for (tsan_sources) |tsan_src| { | ||
| 41 | var cflags = std.ArrayList([]const u8).init(arena); | ||
| 42 | |||
| 43 | try cflags.append("-I"); | ||
| 44 | try cflags.append(tsan_include_path); | ||
| 45 | |||
| 46 | try cflags.append("-O3"); | ||
| 47 | try cflags.append("-DNDEBUG"); | ||
| 48 | try cflags.append("-nostdinc++"); | ||
| 49 | try cflags.append("-fvisibility-inlines-hidden"); | ||
| 50 | try cflags.append("-std=c++14"); | ||
| 51 | |||
| 52 | c_source_files.appendAssumeCapacity(.{ | ||
| 53 | .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "tsan", tsan_src }), | ||
| 54 | .extra_flags = cflags.items, | ||
| 55 | }); | ||
| 56 | } | ||
| 57 | |||
| 58 | const sanitizer_common_include_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ | ||
| 59 | "tsan", "sanitizer_common", | ||
| 60 | }); | ||
| 61 | for (sanitizer_common_sources) |common_src| { | ||
| 62 | var cflags = std.ArrayList([]const u8).init(arena); | ||
| 63 | |||
| 64 | try cflags.append("-I"); | ||
| 65 | try cflags.append(sanitizer_common_include_path); | ||
| 66 | |||
| 67 | try cflags.append("-O3"); | ||
| 68 | try cflags.append("-DNDEBUG"); | ||
| 69 | try cflags.append("-nostdinc++"); | ||
| 70 | try cflags.append("-fvisibility-inlines-hidden"); | ||
| 71 | try cflags.append("-std=c++14"); | ||
| 72 | |||
| 73 | c_source_files.appendAssumeCapacity(.{ | ||
| 74 | .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ | ||
| 75 | "tsan", "sanitizer_common", common_src, | ||
| 76 | }), | ||
| 77 | .extra_flags = cflags.items, | ||
| 78 | }); | ||
| 79 | } | ||
| 80 | |||
| 81 | const sub_compilation = try Compilation.create(comp.gpa, .{ | ||
| 82 | .local_cache_directory = comp.global_cache_directory, | ||
| 83 | .global_cache_directory = comp.global_cache_directory, | ||
| 84 | .zig_lib_directory = comp.zig_lib_directory, | ||
| 85 | .target = target, | ||
| 86 | .root_name = root_name, | ||
| 87 | .root_pkg = null, | ||
| 88 | .output_mode = output_mode, | ||
| 89 | .thread_pool = comp.thread_pool, | ||
| 90 | .libc_installation = comp.bin_file.options.libc_installation, | ||
| 91 | .emit_bin = emit_bin, | ||
| 92 | .optimize_mode = comp.bin_file.options.optimize_mode, | ||
| 93 | .link_mode = link_mode, | ||
| 94 | .want_sanitize_c = false, | ||
| 95 | .want_stack_check = false, | ||
| 96 | .want_valgrind = false, | ||
| 97 | .want_tsan = false, | ||
| 98 | .want_pic = true, | ||
| 99 | .want_pie = true, | ||
| 100 | .emit_h = null, | ||
| 101 | .strip = comp.bin_file.options.strip, | ||
| 102 | .is_native_os = comp.bin_file.options.is_native_os, | ||
| 103 | .is_native_abi = comp.bin_file.options.is_native_abi, | ||
| 104 | .self_exe_path = comp.self_exe_path, | ||
| 105 | .c_source_files = c_source_files.items, | ||
| 106 | .verbose_cc = comp.verbose_cc, | ||
| 107 | .verbose_link = comp.bin_file.options.verbose_link, | ||
| 108 | .verbose_tokenize = comp.verbose_tokenize, | ||
| 109 | .verbose_ast = comp.verbose_ast, | ||
| 110 | .verbose_ir = comp.verbose_ir, | ||
| 111 | .verbose_llvm_ir = comp.verbose_llvm_ir, | ||
| 112 | .verbose_cimport = comp.verbose_cimport, | ||
| 113 | .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, | ||
| 114 | .clang_passthrough_mode = comp.clang_passthrough_mode, | ||
| 115 | .link_libc = true, | ||
| 116 | }); | ||
| 117 | defer sub_compilation.destroy(); | ||
| 118 | |||
| 119 | try sub_compilation.updateSubCompilation(); | ||
| 120 | |||
| 121 | assert(comp.tsan_static_lib == null); | ||
| 122 | comp.tsan_static_lib = Compilation.CRTFile{ | ||
| 123 | .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join( | ||
| 124 | comp.gpa, | ||
| 125 | &[_][]const u8{basename}, | ||
| 126 | ), | ||
| 127 | .lock = sub_compilation.bin_file.toOwnedLock(), | ||
| 128 | }; | ||
| 129 | } | ||
| 130 | |||
| 131 | const tsan_sources = [_][]const u8{ | ||
| 132 | "tsan_clock.cpp", | ||
| 133 | "tsan_debugging.cpp", | ||
| 134 | "tsan_external.cpp", | ||
| 135 | "tsan_fd.cpp", | ||
| 136 | "tsan_flags.cpp", | ||
| 137 | "tsan_ignoreset.cpp", | ||
| 138 | "tsan_interceptors_posix.cpp", | ||
| 139 | "tsan_interface.cpp", | ||
| 140 | "tsan_interface_ann.cpp", | ||
| 141 | "tsan_interface_atomic.cpp", | ||
| 142 | "tsan_interface_java.cpp", | ||
| 143 | "tsan_malloc_mac.cpp", | ||
| 144 | "tsan_md5.cpp", | ||
| 145 | "tsan_mman.cpp", | ||
| 146 | "tsan_mutex.cpp", | ||
| 147 | "tsan_mutexset.cpp", | ||
| 148 | "tsan_preinit.cpp", | ||
| 149 | "tsan_report.cpp", | ||
| 150 | "tsan_rtl.cpp", | ||
| 151 | "tsan_rtl_mutex.cpp", | ||
| 152 | "tsan_rtl_proc.cpp", | ||
| 153 | "tsan_rtl_report.cpp", | ||
| 154 | "tsan_rtl_thread.cpp", | ||
| 155 | "tsan_stack_trace.cpp", | ||
| 156 | "tsan_stat.cpp", | ||
| 157 | "tsan_suppressions.cpp", | ||
| 158 | "tsan_symbolize.cpp", | ||
| 159 | "tsan_sync.cpp", | ||
| 160 | }; | ||
| 161 | |||
| 162 | const sanitizer_common_sources = [_][]const u8{ | ||
| 163 | "sanitizer_allocator.cpp", | ||
| 164 | "sanitizer_common.cpp", | ||
| 165 | "sanitizer_deadlock_detector1.cpp", | ||
| 166 | "sanitizer_deadlock_detector2.cpp", | ||
| 167 | "sanitizer_errno.cpp", | ||
| 168 | "sanitizer_file.cpp", | ||
| 169 | "sanitizer_flags.cpp", | ||
| 170 | "sanitizer_flag_parser.cpp", | ||
| 171 | "sanitizer_fuchsia.cpp", | ||
| 172 | "sanitizer_libc.cpp", | ||
| 173 | "sanitizer_libignore.cpp", | ||
| 174 | "sanitizer_linux.cpp", | ||
| 175 | "sanitizer_linux_s390.cpp", | ||
| 176 | "sanitizer_mac.cpp", | ||
| 177 | "sanitizer_netbsd.cpp", | ||
| 178 | "sanitizer_openbsd.cpp", | ||
| 179 | "sanitizer_persistent_allocator.cpp", | ||
| 180 | "sanitizer_platform_limits_freebsd.cpp", | ||
| 181 | "sanitizer_platform_limits_linux.cpp", | ||
| 182 | "sanitizer_platform_limits_netbsd.cpp", | ||
| 183 | "sanitizer_platform_limits_openbsd.cpp", | ||
| 184 | "sanitizer_platform_limits_posix.cpp", | ||
| 185 | "sanitizer_platform_limits_solaris.cpp", | ||
| 186 | "sanitizer_posix.cpp", | ||
| 187 | "sanitizer_printf.cpp", | ||
| 188 | "sanitizer_procmaps_common.cpp", | ||
| 189 | "sanitizer_procmaps_bsd.cpp", | ||
| 190 | "sanitizer_procmaps_fuchsia.cpp", | ||
| 191 | "sanitizer_procmaps_linux.cpp", | ||
| 192 | "sanitizer_procmaps_mac.cpp", | ||
| 193 | "sanitizer_procmaps_solaris.cpp", | ||
| 194 | "sanitizer_rtems.cpp", | ||
| 195 | "sanitizer_solaris.cpp", | ||
| 196 | "sanitizer_stoptheworld_fuchsia.cpp", | ||
| 197 | "sanitizer_stoptheworld_mac.cpp", | ||
| 198 | "sanitizer_suppressions.cpp", | ||
| 199 | "sanitizer_termination.cpp", | ||
| 200 | "sanitizer_tls_get_addr.cpp", | ||
| 201 | "sanitizer_thread_registry.cpp", | ||
| 202 | "sanitizer_type_traits.cpp", | ||
| 203 | "sanitizer_win.cpp", | ||
| 204 | }; | ||
| 205 | |||
| 206 | // TODO This is next up | ||
| 207 | //const sanitizer_nolibc_sources = [_][]const u8{ | ||
| 208 | // "sanitizer_common_nolibc.cpp", | ||
| 209 | //}; | ||
| 210 | // | ||
| 211 | //const sanitizer_libcdep_sources = [_][]const u8{ | ||
| 212 | // "sanitizer_common_libcdep.cpp", | ||
| 213 | // "sanitizer_allocator_checks.cpp", | ||
| 214 | // "sanitizer_linux_libcdep.cpp", | ||
| 215 | // "sanitizer_mac_libcdep.cpp", | ||
| 216 | // "sanitizer_posix_libcdep.cpp", | ||
| 217 | // "sanitizer_stoptheworld_linux_libcdep.cpp", | ||
| 218 | // "sanitizer_stoptheworld_netbsd_libcdep.cpp", | ||
| 219 | //}; | ||
src/libunwind.zig+1| ... | @@ -103,6 +103,7 @@ pub fn buildStaticLib(comp: *Compilation) !void { | ... | @@ -103,6 +103,7 @@ pub fn buildStaticLib(comp: *Compilation) !void { |
| 103 | .want_sanitize_c = false, | 103 | .want_sanitize_c = false, |
| 104 | .want_stack_check = false, | 104 | .want_stack_check = false, |
| 105 | .want_valgrind = false, | 105 | .want_valgrind = false, |
| 106 | .want_tsan = false, | ||
| 106 | .want_pic = comp.bin_file.options.pic, | 107 | .want_pic = comp.bin_file.options.pic, |
| 107 | .want_pie = comp.bin_file.options.pie, | 108 | .want_pie = comp.bin_file.options.pie, |
| 108 | .emit_h = null, | 109 | .emit_h = null, |
src/link.zig+1| ... | @@ -75,6 +75,7 @@ pub const Options = struct { | ... | @@ -75,6 +75,7 @@ pub const Options = struct { |
| 75 | pic: bool, | 75 | pic: bool, |
| 76 | pie: bool, | 76 | pie: bool, |
| 77 | valgrind: bool, | 77 | valgrind: bool, |
| 78 | tsan: bool, | ||
| 78 | stack_check: bool, | 79 | stack_check: bool, |
| 79 | single_threaded: bool, | 80 | single_threaded: bool, |
| 80 | verbose_link: bool, | 81 | verbose_link: bool, |
src/link/Elf.zig+6| ... | @@ -1327,6 +1327,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1327,6 +1327,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1327 | man.hash.addStringSet(self.base.options.system_libs); | 1327 | man.hash.addStringSet(self.base.options.system_libs); |
| 1328 | man.hash.add(allow_shlib_undefined); | 1328 | man.hash.add(allow_shlib_undefined); |
| 1329 | man.hash.add(self.base.options.bind_global_refs_locally); | 1329 | man.hash.add(self.base.options.bind_global_refs_locally); |
| 1330 | man.hash.add(self.base.options.tsan); | ||
| 1330 | 1331 | ||
| 1331 | // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. | 1332 | // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. |
| 1332 | _ = try man.hit(); | 1333 | _ = try man.hit(); |
| ... | @@ -1545,6 +1546,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1545,6 +1546,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1545 | try argv.append(p); | 1546 | try argv.append(p); |
| 1546 | } | 1547 | } |
| 1547 | 1548 | ||
| 1549 | // TSAN | ||
| 1550 | if (self.base.options.tsan) { | ||
| 1551 | try argv.append(comp.tsan_static_lib.?.full_object_path); | ||
| 1552 | } | ||
| 1553 | |||
| 1548 | // libc | 1554 | // libc |
| 1549 | if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc and !self.base.options.link_libc) { | 1555 | if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc and !self.base.options.link_libc) { |
| 1550 | try argv.append(comp.libc_static_lib.?.full_object_path); | 1556 | try argv.append(comp.libc_static_lib.?.full_object_path); |
src/main.zig+10| ... | @@ -285,6 +285,8 @@ const usage_build_generic = | ... | @@ -285,6 +285,8 @@ const usage_build_generic = |
| 285 | \\ -fno-sanitize-c Disable C undefined behavior detection in safe builds | 285 | \\ -fno-sanitize-c Disable C undefined behavior detection in safe builds |
| 286 | \\ -fvalgrind Include valgrind client requests in release builds | 286 | \\ -fvalgrind Include valgrind client requests in release builds |
| 287 | \\ -fno-valgrind Omit valgrind client requests in debug builds | 287 | \\ -fno-valgrind Omit valgrind client requests in debug builds |
| 288 | \\ -fsanitize-thread Enable Thread Sanitizer | ||
| 289 | \\ -fno-sanitize-thread Disable Thread Sanitizer | ||
| 288 | \\ -fdll-export-fns Mark exported functions as DLL exports (Windows) | 290 | \\ -fdll-export-fns Mark exported functions as DLL exports (Windows) |
| 289 | \\ -fno-dll-export-fns Force-disable marking exported functions as DLL exports | 291 | \\ -fno-dll-export-fns Force-disable marking exported functions as DLL exports |
| 290 | \\ -fLLVM Force using LLVM as the codegen backend | 292 | \\ -fLLVM Force using LLVM as the codegen backend |
| ... | @@ -503,6 +505,7 @@ fn buildOutputType( | ... | @@ -503,6 +505,7 @@ fn buildOutputType( |
| 503 | var want_sanitize_c: ?bool = null; | 505 | var want_sanitize_c: ?bool = null; |
| 504 | var want_stack_check: ?bool = null; | 506 | var want_stack_check: ?bool = null; |
| 505 | var want_valgrind: ?bool = null; | 507 | var want_valgrind: ?bool = null; |
| 508 | var want_tsan: ?bool = null; | ||
| 506 | var want_compiler_rt: ?bool = null; | 509 | var want_compiler_rt: ?bool = null; |
| 507 | var rdynamic: bool = false; | 510 | var rdynamic: bool = false; |
| 508 | var linker_script: ?[]const u8 = null; | 511 | var linker_script: ?[]const u8 = null; |
| ... | @@ -847,6 +850,10 @@ fn buildOutputType( | ... | @@ -847,6 +850,10 @@ fn buildOutputType( |
| 847 | want_valgrind = true; | 850 | want_valgrind = true; |
| 848 | } else if (mem.eql(u8, arg, "-fno-valgrind")) { | 851 | } else if (mem.eql(u8, arg, "-fno-valgrind")) { |
| 849 | want_valgrind = false; | 852 | want_valgrind = false; |
| 853 | } else if (mem.eql(u8, arg, "-fsanitize-thread")) { | ||
| 854 | want_tsan = true; | ||
| 855 | } else if (mem.eql(u8, arg, "-fno-sanitize-thread")) { | ||
| 856 | want_tsan = false; | ||
| 850 | } else if (mem.eql(u8, arg, "-fLLVM")) { | 857 | } else if (mem.eql(u8, arg, "-fLLVM")) { |
| 851 | use_llvm = true; | 858 | use_llvm = true; |
| 852 | } else if (mem.eql(u8, arg, "-fno-LLVM")) { | 859 | } else if (mem.eql(u8, arg, "-fno-LLVM")) { |
| ... | @@ -1106,6 +1113,8 @@ fn buildOutputType( | ... | @@ -1106,6 +1113,8 @@ fn buildOutputType( |
| 1106 | .sanitize => { | 1113 | .sanitize => { |
| 1107 | if (mem.eql(u8, it.only_arg, "undefined")) { | 1114 | if (mem.eql(u8, it.only_arg, "undefined")) { |
| 1108 | want_sanitize_c = true; | 1115 | want_sanitize_c = true; |
| 1116 | } else if (mem.eql(u8, it.only_arg, "thread")) { | ||
| 1117 | want_tsan = true; | ||
| 1109 | } else { | 1118 | } else { |
| 1110 | try clang_argv.appendSlice(it.other_args); | 1119 | try clang_argv.appendSlice(it.other_args); |
| 1111 | } | 1120 | } |
| ... | @@ -1712,6 +1721,7 @@ fn buildOutputType( | ... | @@ -1712,6 +1721,7 @@ fn buildOutputType( |
| 1712 | .want_sanitize_c = want_sanitize_c, | 1721 | .want_sanitize_c = want_sanitize_c, |
| 1713 | .want_stack_check = want_stack_check, | 1722 | .want_stack_check = want_stack_check, |
| 1714 | .want_valgrind = want_valgrind, | 1723 | .want_valgrind = want_valgrind, |
| 1724 | .want_tsan = want_tsan, | ||
| 1715 | .want_compiler_rt = want_compiler_rt, | 1725 | .want_compiler_rt = want_compiler_rt, |
| 1716 | .use_llvm = use_llvm, | 1726 | .use_llvm = use_llvm, |
| 1717 | .use_lld = use_lld, | 1727 | .use_lld = use_lld, |
src/musl.zig+1| ... | @@ -207,6 +207,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { | ... | @@ -207,6 +207,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { |
| 207 | .want_sanitize_c = false, | 207 | .want_sanitize_c = false, |
| 208 | .want_stack_check = false, | 208 | .want_stack_check = false, |
| 209 | .want_valgrind = false, | 209 | .want_valgrind = false, |
| 210 | .want_tsan = false, | ||
| 210 | .emit_h = null, | 211 | .emit_h = null, |
| 211 | .strip = comp.bin_file.options.strip, | 212 | .strip = comp.bin_file.options.strip, |
| 212 | .is_native_os = false, | 213 | .is_native_os = false, |
src/stage1.zig+1| ... | @@ -116,6 +116,7 @@ pub const Module = extern struct { | ... | @@ -116,6 +116,7 @@ pub const Module = extern struct { |
| 116 | dll_export_fns: bool, | 116 | dll_export_fns: bool, |
| 117 | link_mode_dynamic: bool, | 117 | link_mode_dynamic: bool, |
| 118 | valgrind_enabled: bool, | 118 | valgrind_enabled: bool, |
| 119 | tsan_enabled: bool, | ||
| 119 | function_sections: bool, | 120 | function_sections: bool, |
| 120 | enable_stack_probing: bool, | 121 | enable_stack_probing: bool, |
| 121 | enable_time_report: bool, | 122 | enable_time_report: bool, |
src/stage1/all_types.hpp+1| ... | @@ -2199,6 +2199,7 @@ struct CodeGen { | ... | @@ -2199,6 +2199,7 @@ struct CodeGen { |
| 2199 | bool function_sections; | 2199 | bool function_sections; |
| 2200 | bool test_is_evented; | 2200 | bool test_is_evented; |
| 2201 | bool valgrind_enabled; | 2201 | bool valgrind_enabled; |
| 2202 | bool tsan_enabled; | ||
| 2202 | 2203 | ||
| 2203 | Buf *root_out_name; | 2204 | Buf *root_out_name; |
| 2204 | Buf *test_filter; | 2205 | Buf *test_filter; |
src/stage1/codegen.cpp+4| ... | @@ -472,6 +472,10 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { | ... | @@ -472,6 +472,10 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { |
| 472 | ZigLLVMFunctionSetCallingConv(llvm_fn, get_llvm_cc(g, cc)); | 472 | ZigLLVMFunctionSetCallingConv(llvm_fn, get_llvm_cc(g, cc)); |
| 473 | } | 473 | } |
| 474 | 474 | ||
| 475 | if (g->tsan_enabled) { | ||
| 476 | addLLVMFnAttr(llvm_fn, "sanitize_thread"); | ||
| 477 | } | ||
| 478 | |||
| 475 | bool want_cold = fn->is_cold; | 479 | bool want_cold = fn->is_cold; |
| 476 | if (want_cold) { | 480 | if (want_cold) { |
| 477 | ZigLLVMAddFunctionAttrCold(llvm_fn); | 481 | ZigLLVMAddFunctionAttrCold(llvm_fn); |
src/stage1/stage1.cpp+1| ... | @@ -93,6 +93,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) { | ... | @@ -93,6 +93,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) { |
| 93 | g->have_stack_probing = stage1->enable_stack_probing; | 93 | g->have_stack_probing = stage1->enable_stack_probing; |
| 94 | g->is_single_threaded = stage1->is_single_threaded; | 94 | g->is_single_threaded = stage1->is_single_threaded; |
| 95 | g->valgrind_enabled = stage1->valgrind_enabled; | 95 | g->valgrind_enabled = stage1->valgrind_enabled; |
| 96 | g->tsan_enabled = stage1->tsan_enabled; | ||
| 96 | g->link_libc = stage1->link_libc; | 97 | g->link_libc = stage1->link_libc; |
| 97 | g->link_libcpp = stage1->link_libcpp; | 98 | g->link_libcpp = stage1->link_libcpp; |
| 98 | g->function_sections = stage1->function_sections; | 99 | g->function_sections = stage1->function_sections; |
src/stage1/stage1.h+1| ... | @@ -185,6 +185,7 @@ struct ZigStage1 { | ... | @@ -185,6 +185,7 @@ struct ZigStage1 { |
| 185 | bool dll_export_fns; | 185 | bool dll_export_fns; |
| 186 | bool link_mode_dynamic; | 186 | bool link_mode_dynamic; |
| 187 | bool valgrind_enabled; | 187 | bool valgrind_enabled; |
| 188 | bool tsan_enabled; | ||
| 188 | bool function_sections; | 189 | bool function_sections; |
| 189 | bool enable_stack_probing; | 190 | bool enable_stack_probing; |
| 190 | bool enable_time_report; | 191 | bool enable_time_report; |