+/* Build a structure in which we can capture the interesting data from the
+ * auxiliary vector.
+ */
+#define AUXUTYPE_i long
+#define AUXUTYPE_u unsigned long
+#define AUXUTYPE_p const void *
+struct auxprobe {
+#define AUXPROBE__SLOT(type, ubranch, slot) AUXUTYPE_##ubranch slot;
+ WANTAUX(AUXPROBE__SLOT)
+#undef AUXPROBE_SLOT
+};
+
+/* --- @probe_hwcaps@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Attempt to find the auxiliary vector (which is well hidden)
+ * and discover interesting features from it.
+ */
+
+static void probe_hwcaps(void)
+{
+ unsigned hw = HF_PROBED;
+ struct auxprobe probed = { 0 };
+
+ /* Populate `probed' with the information we manage to retrieve from the
+ * auxiliary vector. Slots we couldn't find are left zero-valued.
+ */
+#if defined(HAVE_GETAUXVAL)
+ /* Shiny new libc lets us request individual entry types. This is almost
+ * too easy.
+ */
+# define CAP__GET(type, ubranch, slot) \
+ probed.slot = (AUXUTYPE_##ubranch)getauxval(type);
+ WANTAUX(CAP__GET)
+#else
+ /* 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'.