[boringssl] Autogenerate #[link_name] attributes
- Split the symbol whitelist into function names and others
- Postprocess boringssl.rs after formatting to add the #[link_name]
attributes
- Use the function names from the whitelist for consistency
checking. Postprocessing will exit with an error if a) a function
is not in the whitelist, b) a function from the whitelist was not
encountered in the file, c) a function was encountered more than
once (should never happen)
Closes #7
Change-Id: Ied1c2481b73d0fc20b86115d431a4164f6263d4a
diff --git a/boringssl/bindgen.sh b/boringssl/bindgen.sh
index cc2e636..57e62b1 100755
--- a/boringssl/bindgen.sh
+++ b/boringssl/bindgen.sh
@@ -32,85 +32,97 @@
# effort in a graceful transition or decide to abandon the change. Thus, instead
# of whitelisting broad classes of symbols, we explicitly whitelist the exact
# list of symbols that Mundane depends on.
-WHITELIST="(CBB|\
+
+# TODO(inejge):
+# - When https://github.com/rust-lang-nursery/rust-bindgen/issues/1375 is resolved,
+# go back to a single whitelist
+
+# Split the whitelist into function names and other symbols, in order to use the
+# former for a consistency check of the postprocessing step which adds the
+# #[link_name...] attributes. Any change of the whitelist must be made to the
+# appropriate sub-list.
+WHITELIST_FUNCS="CBS_init|\
+CBS_len|\
+CBB_init|\
CBB_cleanup|\
CBB_data|\
-CBB_init|\
CBB_len|\
-CBS|\
-CBS_init|\
-CBS_len|\
-CRYPTO_memcmp|\
-ECDSA_sign|\
-ECDSA_size|\
-ECDSA_verify|\
-EC_GROUP|\
-EC_GROUP_get_curve_name|\
-EC_GROUP_new_by_curve_name|\
-EC_KEY|\
-EC_KEY_free|\
-EC_KEY_generate_key|\
-EC_KEY_get0_group|\
-EC_KEY_marshal_private_key|\
-EC_KEY_new|\
-EC_KEY_parse_private_key|\
-EC_KEY_set_group|\
-EC_KEY_up_ref|\
-EC_curve_nid2nist|\
-ED25519_PRIVATE_KEY_LEN|\
-ED25519_PUBLIC_KEY_LEN|\
-ED25519_SIGNATURE_LEN|\
ED25519_keypair|\
-ED25519_keypair_from_seed|\
ED25519_sign|\
ED25519_verify|\
+ED25519_keypair_from_seed|\
+EC_GROUP_new_by_curve_name|\
+EC_GROUP_get_curve_name|\
+EC_curve_nid2nist|\
+EC_KEY_new|\
+EC_KEY_free|\
+EC_KEY_up_ref|\
+EC_KEY_get0_group|\
+EC_KEY_set_group|\
+EC_KEY_generate_key|\
+EC_KEY_parse_private_key|\
+EC_KEY_marshal_private_key|\
+ECDSA_sign|\
+ECDSA_verify|\
+ECDSA_size|\
ERR_print_errors_cb|\
-EVP_MD|\
-EVP_PBE_scrypt|\
-EVP_PKEY|\
-EVP_PKEY_assign_EC_KEY|\
-EVP_PKEY_free|\
-EVP_PKEY_get1_EC_KEY|\
-EVP_PKEY_new|\
-EVP_PKEY_up_ref|\
-EVP_marshal_public_key|\
-EVP_parse_public_key|\
EVP_sha1|\
EVP_sha256|\
EVP_sha384|\
EVP_sha512|\
-HMAC_CTX|\
-HMAC_CTX_cleanup|\
+EVP_PKEY_new|\
+EVP_PKEY_free|\
+EVP_PKEY_up_ref|\
+EVP_PKEY_assign_EC_KEY|\
+EVP_PKEY_get1_EC_KEY|\
+EVP_parse_public_key|\
+EVP_marshal_public_key|\
+PKCS5_PBKDF2_HMAC|\
+EVP_PBE_scrypt|\
HMAC_CTX_init|\
-HMAC_Final|\
+HMAC_CTX_cleanup|\
HMAC_Init_ex|\
HMAC_Update|\
+HMAC_Final|\
HMAC_size|\
+CRYPTO_memcmp|\
+RAND_bytes|\
+SHA1_Init|\
+SHA1_Update|\
+SHA1_Final|\
+SHA256_Init|\
+SHA256_Update|\
+SHA256_Final|\
+SHA384_Init|\
+SHA384_Update|\
+SHA384_Final|\
+SHA512_Init|\
+SHA512_Update|\
+SHA512_Final"
+
+WHITELIST_OTHERS="CBB|\
+CBS|\
+EC_GROUP|\
+EC_KEY|\
+ED25519_PRIVATE_KEY_LEN|\
+ED25519_PUBLIC_KEY_LEN|\
+ED25519_SIGNATURE_LEN|\
+EVP_MD|\
+EVP_PKEY|\
+HMAC_CTX|\
NID_X9_62_prime256v1|\
NID_secp384r1|\
NID_secp521r1|\
-RAND_bytes|\
-PKCS5_PBKDF2_HMAC|\
SHA_CTX|\
SHA_DIGEST_LENGTH|\
-SHA1_Final|\
-SHA1_Init|\
-SHA1_Update|\
SHA256_CTX|\
SHA256_DIGEST_LENGTH|\
-SHA256_Final|\
-SHA256_Init|\
-SHA256_Update|\
SHA512_CTX|\
SHA384_DIGEST_LENGTH|\
-SHA384_Final|\
-SHA384_Init|\
-SHA384_Update|\
SHA512_CTX|\
-SHA512_DIGEST_LENGTH|\
-SHA512_Final|\
-SHA512_Init|\
-SHA512_Update)"
+SHA512_DIGEST_LENGTH"
+
+WHITELIST="(${WHITELIST_FUNCS}|${WHITELIST_OTHERS})"
# NOTE(joshlf): Currently, we don't pass --target since none of the symbols
# we're linking against are architecture-specific (TODO: are any of them
@@ -125,7 +137,7 @@
# Prepend copyright comment, #[allow] for various warnings we don't care about,
# and a line telling Rust to link against libcrypto.
-cat >> "$TMP" <<'EOF'
+(cat <<'EOF'
// Copyright 2018 Google LLC
//
// Use of this source code is governed by an MIT-style
@@ -147,10 +159,47 @@
# Do this on a separate line because we need string interpolation, but we can't
# use string interpolation in the preceding 'cat' command, or else the !
# characters would be interpreted.
-echo "#[link(name = \"crypto_${MAJOR}_${MINOR}_${PATCH}\")] extern {}" >> "$TMP"
-echo >> "$TMP"
+echo "#[link(name = \"crypto_${MAJOR}_${MINOR}_${PATCH}\")] extern {}"
+echo
-cat boringssl.rs >> "$TMP"
-
+cat boringssl.rs) \
+| rustfmt \
+| (
+# Postprocess the generated bindings, adding the "#[link_name ...]"
+# attribute to exported functions. Since the function sites are matched
+# lexically, check the consistency of matches against the list of function
+# names defined above. An error will be returned if a) a matched function
+# is not in the whitelist, b) a name from the whitelist wasn't matched
+# in the input, or c) a name was matched more than once (which should
+# never happen).
+awk -v "vers=${MAJOR}_${MINOR}_${PATCH}_" -v "funcs=${WHITELIST_FUNCS}" '
+BEGIN {
+ split(funcs, fa, "[|]")
+ for (fn in fa)
+ f[fa[fn]]
+}
+/extern "C" {/ {
+ print
+ getline
+ if ($0 ~ "#[[]link_name")
+ getline
+ if ($0 ~ "pub fn") {
+ fn = $3
+ sub("[(].*", "", fn)
+ if (!(fn in f)) {
+ print "fatal: fn not in whitelist: " fn | "cat >&2"
+ exit 1
+ } else
+ f[fn]++
+ print " #[link_name = \"__RUST_MUNDANE_" vers fn "\"]"
+ }
+}
+{ print }
+END {
+ for (fn in f)
+ if (f[fn] != 1) {
+ print "fatal: fn match count = " f[fn] + 0 ", should be 1: " fn | "cat >&2"
+ exit 1
+ }
+}') > "$TMP"
mv "$TMP" boringssl.rs
-rustfmt boringssl.rs