Add tf_fuzz tool

This is fully derived from tf-m repo.

Signed-off-by: Karl Zhang <karl.zhang@arm.com>
Change-Id: I8d35e70eda9081af66d8fa3f3cb4beb1d953060e
diff --git a/tf_fuzz/calls/psa_call.cpp b/tf_fuzz/calls/psa_call.cpp
new file mode 100644
index 0000000..46af409
--- /dev/null
+++ b/tf_fuzz/calls/psa_call.cpp
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "class_forwards.hpp"
+
+#include "boilerplate.hpp"
+#include "gibberish.hpp"
+#include "compute.hpp"
+#include "string_ops.hpp"
+#include "data_blocks.hpp"
+#include "psa_asset.hpp"
+#include "find_or_create_asset.hpp"
+#include "template_line.hpp"
+#include "tf_fuzz.hpp"
+#include "crypto_asset.hpp"
+#include "psa_call.hpp"
+
+
+
+/**********************************************************************************
+   Methods of class psa_call follow:
+**********************************************************************************/
+
+//**************** psa_call methods ****************
+
+psa_call::psa_call (tf_fuzz_info *test_state, long &call_ser_no,   // (constructor)
+                    asset_search how_asset_found)
+{
+    this->test_state = test_state;
+    this->asset_info.how_asset_found = how_asset_found;
+    set_data.string_specified = false;
+    set_data.set ("");  // actual data
+    assign_data_var.assign ("");  // name of variable assigned (dumped) to
+    assign_data_var_specified = false;
+    set_data.file_specified = false;
+    set_data.file_path.assign ("");
+    this->call_ser_no = call_ser_no = unique_id_counter++;
+    // These will be set in the lower-level constructors, but...
+    prep_code = call_code = check_code = "";
+    print_data = hash_data = false;
+    barrier = target_barrier = "";  // not (yet) any barrier for re-ordering calls
+    call_description = "";
+}
+
+psa_call::~psa_call (void)
+{
+    return;  // just to have something to pin a breakpoint onto
+}
+
+void psa_call::write_out_prep_code (ofstream &test_file)
+{
+    test_file << prep_code;
+}
+
+void psa_call::write_out_command (ofstream &test_file)
+{
+    test_file << call_code;
+}
+
+void psa_call::write_out_check_code (ofstream &test_file)
+{
+    if (!exp_data.pf_nothing) {
+        test_file << check_code;
+    } else {
+        test_file << "    /* (No checks for this PSA call.) */" << endl;
+    }
+}
+
+/**********************************************************************************
+   End of methods of class psa_call.
+**********************************************************************************/
+
+
+/**********************************************************************************
+   Methods of class sst_call follow:
+**********************************************************************************/
+
+/* calc_result_code() fills in the check_code string member with the correct
+   result code (e.g., "PSA_SUCCESS" or whatever).
+
+   This is a big part of where the target modeling -- error modeling -- occurs,
+   so lots of room for further refinement here. */
+void sst_call::calc_result_code (void)
+{
+    string formalized;  // "proper" result string
+
+    if (!exp_data.pf_nothing) {
+        if (exp_data.pf_pass) {
+            find_replace_all ("$expect",
+                              test_state->bplate->bplate_string[sst_pass_string],
+                              check_code);
+        } else if (exp_data.pf_fail) {
+            // Check for not-success:
+            find_replace_1st ("!=", "==",
+                              check_code);
+            find_replace_all ("$expect",
+                              test_state->bplate->bplate_string[sst_pass_string],
+                              check_code);
+            find_replace_1st ("expected ", "expected not ",
+                              check_code);
+        } else {
+            if (exp_data.pf_specified) {
+                formalized = formalize (exp_data.pf_result_string, "PSA_ERROR_");
+                find_replace_all ("$expect", formalized, check_code);
+            } else {
+                // Figure out what the message should read:
+                switch (asset_info.how_asset_found) {
+                    case asset_search::found_active:
+                    case asset_search::created_new:
+                        find_replace_all ("$expect",
+                                          test_state->bplate->
+                                              bplate_string[sst_pass_string],
+                                          check_code);
+                        break;
+                    case asset_search::found_deleted:
+                    case asset_search::not_found:
+                        find_replace_all ("$expect",
+                                          test_state->bplate->
+                                              bplate_string[sst_fail_removed],
+                                          check_code);
+                        break;
+                    default:
+                        find_replace_1st ("!=", "==",
+                                          check_code);  // like "fail", just make sure...
+                        find_replace_all ("$expect",
+                                          test_state->bplate->
+                                              bplate_string[sst_pass_string],
+                                          check_code);  // ... it's *not* PSA_SUCCESS
+                        break;
+                }
+            }
+        }
+    }
+}
+
+vector<psa_asset*>::iterator sst_call::resolve_asset (bool create_asset_bool,
+                                                      psa_asset_usage where) {
+    vector<psa_asset*>::iterator found_asset;
+    vector<psa_asset*> *asset_vector;
+    int asset_pick;
+
+    if (random_asset != psa_asset_usage::all) {
+        // != psa_asset_usage::all means to choose some known asset at random:
+        if (random_asset == psa_asset_usage::active) {
+            asset_vector = &(test_state->active_sst_asset);
+            asset_info.how_asset_found = asset_search::found_active;
+        } else if (random_asset == psa_asset_usage::deleted) {
+            asset_vector = &(test_state->deleted_sst_asset);
+            asset_info.how_asset_found = asset_search::found_deleted;
+        } else {
+            // "invalid" assets are not currently used.
+            cerr << "\nError:  Tool-internal:  Please report error 1101 to " << endl
+                 << "TF-Fuzz developers."
+                 << endl;
+            exit(1101);
+        }
+        if (asset_vector->size() > 0) {
+            /* Pick an active or deleted asset at random: */
+            asset_pick = rand() % asset_vector->size();
+            found_asset = asset_vector->begin() + asset_pick;
+            /* Copy asset information into template tracker: */
+            asset_info.id_n = (*found_asset)->asset_info.id_n;
+            asset_info.asset_ser_no
+                    = (*found_asset)->asset_info.asset_ser_no;
+        } else {
+            if (random_asset == psa_asset_usage::active) {
+                cerr << "\nError:  An sst call asks for a "
+                     << "randomly chosen active asset, when none " << endl
+                     << "is currently defined." << endl;
+                exit(1008);
+            } else if (random_asset == psa_asset_usage::deleted) {
+                cerr << "\nError:  An sst call asks for a "
+                     << "randomly chosen deleted asset, when none " << endl
+                     << "is currently defined." << endl;
+                exit(1009);
+            }  // "invalid" assets are not currently used.
+        }
+    } else {
+        // Find the asset by name:
+        asset_info.how_asset_found = test_state->find_or_create_sst_asset (
+                            psa_asset_search::name, where,
+                            asset_info.get_name(), 0, asset_info.asset_ser_no,
+                            create_asset_bool, found_asset );
+        if (   asset_info.how_asset_found == asset_search::unsuccessful
+            || asset_info.how_asset_found == asset_search::something_wrong ) {
+            cerr << "\nError:  Tool-internal:  Please report error 108 to " << endl
+                 << "TF-Fuzz developers."
+                 << endl;
+            exit(108);
+        }
+    }
+    return found_asset;
+}
+
+sst_call::sst_call (tf_fuzz_info *test_state, long &call_ser_no,   // (constructor)
+                    asset_search how_asset_found)
+                        : psa_call(test_state, call_ser_no, how_asset_found)
+{
+    asset_info.the_asset = nullptr;
+    return;  // just to have something to pin a breakpoint onto
+}
+sst_call::~sst_call (void)
+{
+    return;  // just to have something to pin a breakpoint onto
+}
+
+/**********************************************************************************
+   End of methods of class sst_call.
+**********************************************************************************/
+
+
+/**********************************************************************************
+   Methods of class crypto_call follow:
+**********************************************************************************/
+
+/* calc_result_code() fills in the check_code string member with the correct
+   result code (e.g., "PSA_SUCCESS" or whatever).  This "modeling" needs to be
+   improved and expanded upon *massively* more or less mirroring what is seen in
+   .../test/suites/crypto/crypto_tests_common.c in the psa_key_interface_test()
+   method, (starting around line 20ish). */
+void crypto_call::calc_result_code (void)
+{
+    string formalized;  // "proper" result string
+
+    if (!exp_data.pf_nothing) {
+        if (exp_data.pf_pass) {
+            find_replace_all ("$expect",
+                              test_state->bplate->bplate_string[sst_pass_string],
+                              check_code);
+        } else if (exp_data.pf_fail) {
+            // Check for not-success:
+            find_replace_1st ("!=", "==",
+                              check_code);
+            find_replace_all ("$expect",
+                              test_state->bplate->bplate_string[sst_pass_string],
+                              check_code);
+            find_replace_1st ("expected ", "expected not ",
+                              check_code);
+        } else {
+            if (exp_data.pf_specified) {
+                formalized = formalize (exp_data.pf_result_string, "PSA_ERROR_");
+                find_replace_all ("$expect", formalized, check_code);
+            } else {
+                // Figure out what the message should read:
+                switch (asset_info.how_asset_found) {
+                    case asset_search::found_active:
+                    case asset_search::created_new:
+                        find_replace_all ("$expect",
+                                          test_state->bplate->
+                                              bplate_string[sst_pass_string],
+                                          check_code);
+                        break;
+                    case asset_search::not_found:
+                    case asset_search::found_deleted:
+                        find_replace_all ("$expect", "PSA_ERROR_INVALID_HANDLE",
+                                          check_code);  // TODO:  take from boilerplate
+                        break;
+                    default:
+                        find_replace_1st ("!=", "==",
+                                          check_code);  // like "fail", just make sure...
+                        find_replace_all ("$expect",
+                                          test_state->bplate->
+                                              bplate_string[sst_pass_string],
+                                          check_code);  // ... it's *not* PSA_SUCCESS
+                        break;
+                }
+            }
+        }
+    }
+}
+
+
+bool crypto_call::copy_asset_to_call (void)
+{
+    if (asset_info.the_asset == nullptr) {
+        return false;
+    } else {
+        // Get updated asset info from the asset:
+        asset_info.asset_ser_no = asset_info.the_asset->asset_info.asset_ser_no;
+        asset_info.id_n = asset_info.the_asset->asset_info.id_n;
+        exp_data.n_exp_vars = asset_info.the_asset->exp_data.n_exp_vars;
+        exp_data.data = asset_info.the_asset->exp_data.data;
+        return true;
+    }
+}
+
+
+crypto_call::crypto_call (tf_fuzz_info *test_state, long &call_ser_no,  // (constructor)
+                          asset_search how_asset_found)
+                             : psa_call(test_state, call_ser_no, how_asset_found)
+{
+    // Nothing further to initialize.
+    return;  // just to have something to pin a breakpoint onto
+}
+crypto_call::~crypto_call (void)
+{
+    // Nothing further to delete.
+    return;  // just to have something to pin a breakpoint onto
+}
+
+/**********************************************************************************
+   End of methods of class crypto_call.
+**********************************************************************************/
+
+
+/**********************************************************************************
+   Methods of class security_call follow:
+**********************************************************************************/
+
+security_call::security_call (tf_fuzz_info *test_state, long &call_ser_no,  // (constructor)
+                          asset_search how_asset_found)
+                             : psa_call(test_state, call_ser_no, how_asset_found)
+{
+    // Nothing further to initialize.
+    return;  // just to have something to pin a breakpoint onto
+}
+security_call::~security_call (void)
+{
+    // Nothing further to delete.
+    return;  // just to have something to pin a breakpoint onto
+}
+
+// resolve_asset() doesn't do anything for security_calls, since there's no asset involved.
+vector<psa_asset*>::iterator security_call::resolve_asset (bool create_asset_bool,
+                                                           psa_asset_usage where)
+{
+    return test_state->active_sst_asset.end();  // (anything)
+}
+
+/* calc_result_code() fills in the check_code string member with the correct result
+   code (e.g., "PSA_SUCCESS" or whatever).
+
+   Since there are no actual PSA calls associated with security calls (so far at least),
+   this should never be invoked. */
+void security_call::calc_result_code (void)
+{
+    // Currently should not be invoked.
+    cerr << "\nError:  Internal:  Please report error #205 to TF-Fuzz developers." << endl;
+    exit (205);
+}
+
+/**********************************************************************************
+   End of methods of class security_call.
+**********************************************************************************/
+
+