diff options
Diffstat (limited to 'common/native/bpf_headers/include/bpf/KernelUtils.h')
-rw-r--r-- | common/native/bpf_headers/include/bpf/KernelUtils.h | 173 |
1 files changed, 0 insertions, 173 deletions
diff --git a/common/native/bpf_headers/include/bpf/KernelUtils.h b/common/native/bpf_headers/include/bpf/KernelUtils.h deleted file mode 100644 index 59257b8b..00000000 --- a/common/native/bpf_headers/include/bpf/KernelUtils.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <stdio.h> -#include <string.h> -#include <sys/personality.h> -#include <sys/utsname.h> - -namespace android { -namespace bpf { - -#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c)) - -static inline unsigned uncachedKernelVersion() { - struct utsname buf; - if (uname(&buf)) return 0; - - unsigned kver_major = 0; - unsigned kver_minor = 0; - unsigned kver_sub = 0; - (void)sscanf(buf.release, "%u.%u.%u", &kver_major, &kver_minor, &kver_sub); - return KVER(kver_major, kver_minor, kver_sub); -} - -static inline unsigned kernelVersion() { - static unsigned kver = uncachedKernelVersion(); - return kver; -} - -static inline __unused bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { - return kernelVersion() >= KVER(major, minor, sub); -} - -// Figure out the bitness of userspace. -// Trivial and known at compile time. -static constexpr bool isUserspace32bit() { - return sizeof(void*) == 4; -} - -static constexpr bool isUserspace64bit() { - return sizeof(void*) == 8; -} - -#if defined(__LP64__) -static_assert(isUserspace64bit(), "huh? LP64 must have 64-bit userspace"); -#elif defined(__ILP32__) -static_assert(isUserspace32bit(), "huh? ILP32 must have 32-bit userspace"); -#else -#error "huh? must be either LP64 (64-bit userspace) or ILP32 (32-bit userspace)" -#endif - -static_assert(isUserspace32bit() || isUserspace64bit(), "must be either 32 or 64 bit"); - -// Figure out the bitness of the kernel. -static inline bool isKernel64Bit() { - // a 64-bit userspace requires a 64-bit kernel - if (isUserspace64bit()) return true; - - static bool init = false; - static bool cache = false; - if (init) return cache; - - // Retrieve current personality - on Linux this system call *cannot* fail. - int p = personality(0xffffffff); - // But if it does just assume kernel and userspace (which is 32-bit) match... - if (p == -1) return false; - - // This will effectively mask out the bottom 8 bits, and switch to 'native' - // personality, and then return the previous personality of this thread - // (likely PER_LINUX or PER_LINUX32) with any extra options unmodified. - int q = personality((p & ~PER_MASK) | PER_LINUX); - // Per man page this theoretically could error out with EINVAL, - // but kernel code analysis suggests setting PER_LINUX cannot fail. - // Either way, assume kernel and userspace (which is 32-bit) match... - if (q != p) return false; - - struct utsname u; - (void)uname(&u); // only possible failure is EFAULT, but u is on stack. - - // Switch back to previous personality. - // Theoretically could fail with EINVAL on arm64 with no 32-bit support, - // but then we wouldn't have fetched 'p' from the kernel in the first place. - // Either way there's nothing meaningful we can do in case of error. - // Since PER_LINUX32 vs PER_LINUX only affects uname.machine it doesn't - // really hurt us either. We're really just switching back to be 'clean'. - (void)personality(p); - - // Possible values of utsname.machine observed on x86_64 desktop (arm via qemu): - // x86_64 i686 aarch64 armv7l - // additionally observed on arm device: - // armv8l - // presumably also might just be possible: - // i386 i486 i586 - // and there might be other weird arm32 cases. - // We note that the 64 is present in both 64-bit archs, - // and in general is likely to be present in only 64-bit archs. - cache = !!strstr(u.machine, "64"); - init = true; - return cache; -} - -static inline __unused bool isKernel32Bit() { - return !isKernel64Bit(); -} - -static constexpr bool isArm() { -#if defined(__arm__) - static_assert(isUserspace32bit(), "huh? arm must be 32 bit"); - return true; -#elif defined(__aarch64__) - static_assert(isUserspace64bit(), "aarch64 must be LP64 - no support for ILP32"); - return true; -#else - return false; -#endif -} - -static constexpr bool isX86() { -#if defined(__i386__) - static_assert(isUserspace32bit(), "huh? i386 must be 32 bit"); - return true; -#elif defined(__x86_64__) - static_assert(isUserspace64bit(), "x86_64 must be LP64 - no support for ILP32 (x32)"); - return true; -#else - return false; -#endif -} - -static constexpr bool isRiscV() { -#if defined(__riscv) - static_assert(isUserspace64bit(), "riscv must be 64 bit"); - return true; -#else - return false; -#endif -} - -static_assert(isArm() || isX86() || isRiscV(), "Unknown architecture"); - -static __unused const char * describeArch() { - // ordered so as to make it easier to compile time optimize, - // only thing not known at compile time is isKernel64Bit() - if (isUserspace64bit()) { - if (isArm()) return "64-on-aarch64"; - if (isX86()) return "64-on-x86-64"; - if (isRiscV()) return "64-on-riscv64"; - } else if (isKernel64Bit()) { - if (isArm()) return "32-on-aarch64"; - if (isX86()) return "32-on-x86-64"; - } else { - if (isArm()) return "32-on-arm32"; - if (isX86()) return "32-on-x86-32"; - } -} - -} // namespace bpf -} // namespace android |