Simulate other ARM CPUs when running tests.

We test all Intel variants via SDE. For ARM, we can do the next best
thing and tweak with OPENSSL_armcap_P. If the host CPU does not support
the instructions we wish to test, skip it, but print something so we
know whether we need a more featureful test device.

Also fix the "CRASHED" status to "CRASH", to match
https://chromium.googlesource.com/chromium/src/+/master/docs/testing/json_test_results_format.md
(It's unclear if anything actually parses that JSON very carefully...)

Bug: 19
Change-Id: I811cc00a0d210a454287ac79c06f18fbc54f96dd
Reviewed-on: https://boringssl-review.googlesource.com/c/33204
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/crypto.c b/crypto/crypto.c
index 5f1a69a..f7ac255 100644
--- a/crypto/crypto.c
+++ b/crypto/crypto.c
@@ -102,6 +102,10 @@
 
 #else
 HIDDEN uint32_t OPENSSL_armcap_P = 0;
+
+uint32_t *OPENSSL_get_armcap_pointer_for_test(void) {
+  return &OPENSSL_armcap_P;
+}
 #endif
 
 #endif
diff --git a/crypto/internal.h b/crypto/internal.h
index a251b95..b98b556 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -150,6 +150,14 @@
 void OPENSSL_cpuid_setup(void);
 #endif
 
+#if (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) && \
+    !defined(OPENSSL_STATIC_ARMCAP)
+// OPENSSL_get_armcap_pointer_for_test returns a pointer to |OPENSSL_armcap_P|
+// for unit tests. Any modifications to the value must be made after
+// |CRYPTO_library_init| but before any other function call in BoringSSL.
+OPENSSL_EXPORT uint32_t *OPENSSL_get_armcap_pointer_for_test(void);
+#endif
+
 
 #if (!defined(_MSC_VER) || defined(__clang__)) && defined(OPENSSL_64_BIT)
 #define BORINGSSL_HAS_UINT128
diff --git a/crypto/test/gtest_main.cc b/crypto/test/gtest_main.cc
index 5dc8b23..4501bbb 100644
--- a/crypto/test/gtest_main.cc
+++ b/crypto/test/gtest_main.cc
@@ -12,13 +12,22 @@
  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
 
+#include <stdio.h>
 #include <string.h>
 
 #include <gtest/gtest.h>
 
+#include <openssl/cpu.h>
 #include <openssl/rand.h>
 
 #include "gtest_main.h"
+#include "../internal.h"
+
+#if (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) &&       \
+    !defined(OPENSSL_STATIC_ARMCAP)
+#include <openssl/arm_arch.h>
+#define TEST_ARM_CPUS
+#endif
 
 
 int main(int argc, char **argv) {
@@ -33,5 +42,33 @@
   }
 #endif
 
+#if defined(TEST_ARM_CPUS)
+  for (int i = 1; i < argc; i++) {
+    if (strncmp(argv[i], "--cpu=", 6) == 0) {
+      const char *cpu = argv[i] + 6;
+      uint32_t armcap;
+      if (strcmp(cpu, "none") == 0) {
+        armcap = 0;
+      } else if (strcmp(cpu, "neon") == 0) {
+        armcap = ARMV7_NEON;
+      } else if (strcmp(cpu, "crypto") == 0) {
+        armcap = ARMV7_NEON | ARMV8_AES | ARMV8_SHA1 | ARMV8_SHA256 | ARMV8_PMULL;
+      } else {
+        fprintf(stderr, "Unknown CPU: %s\n", cpu);
+        exit(1);
+      }
+
+      uint32_t *armcap_ptr = OPENSSL_get_armcap_pointer_for_test();
+      if ((armcap & *armcap_ptr) != armcap) {
+        fprintf(stderr,
+                "Host CPU does not support features for testing CPU '%s'.\n",
+                cpu);
+        exit(89);
+      }
+      *armcap_ptr = armcap;
+    }
+  }
+#endif  // TEST_ARM_CPUS
+
   return RUN_ALL_TESTS();
 }