+ /* Otherwise we're a bit stuck, really. Modern Linux kernels make a copy
+ * of the vector available in `/procc' so we could try that.
+ *
+ * The usual place is stuck on the end of the environment vector, but that
+ * may well have moved, and we have no way of telling whether it has or
+ * whether there was ever an auxiliary vector there at all; so don't do
+ * that.
+ */
+ {
+ FILE *fp = 0;
+ unsigned char *p = 0, *q = 0;
+ const struct auxentry *a;
+ size_t sz, off, n;
+
+ /* Open the file and read it into a memory chunk. */
+ if ((fp = fopen("/proc/self/auxv", "rb")) == 0) goto clean;
+ sz = 4096; off = 0;
+ if ((p = malloc(sz)) == 0) goto clean;
+ for (;;) {
+ n = fread(p + off, 1, sz - off, fp);
+ off += n;
+ if (off < sz) break;
+ sz *= 2; if ((q = realloc(p, sz)) == 0) break;
+ p = q;
+ }
+
+ /* Work through the vector (or as much of it as we found) and extract the
+ * types we're interested in.
+ */
+ for (a = (const struct auxentry *)p,
+ n = sz/sizeof(struct auxentry);
+ n--; a++) {
+ switch (a->type) {
+#define CAP__SWITCH(type, ubranch, slot) \
+ case type: probed.slot = a->value.ubranch; break;
+ WANTAUX(CAP__SWITCH)
+ case AT_NULL: goto clean;
+ }
+ }
+
+ clean:
+ if (p) free(p);
+ if (fp) fclose(fp);
+ }
+#endif
+
+ /* Each CPU family now has to pick through what was found and stashed in
+ * `probed', and set the appropriate flag bits in `hw'.
+ */
+#if CPUFAM_ARMEL
+ if (probed.hwcap & HWCAP_VFPv3) hw |= HF_ARM_VFP;
+ if (probed.hwcap & HWCAP_NEON) hw |= HF_ARM_NEON;
+ if (probed.hwcap & HWCAP_VFPD32) hw |= HF_ARM_D32;
+ if (probed.hwcap & HWCAP_VFPv4) hw |= HF_ARM_V4;
+# ifdef HWCAP2_AES
+ if (probed.hwcap2 & HWCAP2_AES) hw |= HF_ARM_AES;
+# endif
+# ifdef HWCAP2_PMULL
+ if (probed.hwcap2 & HWCAP2_PMULL) hw |= HF_ARM_PMULL;
+# endif