Snap for 10204122 from 6d7c70f1cf629814130b11a8136d5b12b1e840b7 to udc-qpr1-release
Change-Id: Id101ef995ee969b121dffb15634f7290fa0db0ae
diff --git a/common/native/bpf_headers/include/bpf/KernelUtils.h b/common/native/bpf_headers/include/bpf/KernelUtils.h
index 29a36e6..b3dd86c 100644
--- a/common/native/bpf_headers/include/bpf/KernelUtils.h
+++ b/common/native/bpf_headers/include/bpf/KernelUtils.h
@@ -17,6 +17,8 @@
#pragma once
#include <stdio.h>
+#include <string.h>
+#include <sys/personality.h>
#include <sys/utsname.h>
namespace android {
@@ -40,9 +42,124 @@
return kver;
}
-static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) {
+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?");
+#elif defined(__ILP32__)
+static_assert(isUserspace32bit(), "huh?");
+#else
+#error "huh?"
+#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__) || defined(__aarch64__)
+ return true;
+#else
+ return false;
+#endif
+}
+
+static constexpr bool isX86() {
+#if defined(__i386__) || defined(__x86_64__)
+ 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