├── .clang-format ├── .gitmodules ├── Adding_Models_and_Simulators.md ├── BUILDING.md ├── CMakeLists.txt ├── COPYING ├── LOGO_ERC-FLAG_EU.jpg ├── OPTIONS.md ├── README.md ├── cmake └── External.cmake ├── coeffs.json ├── doc ├── CMakeLists.txt └── Doxyfile.in ├── external └── CMakeLists.txt ├── src ├── Assembly_Instruction.hpp ├── CMakeLists.txt ├── Coefficients.cpp ├── Coefficients.hpp ├── Error.hpp ├── Execution.hpp ├── Factory │ ├── Abstract_Factory.hpp │ └── Abstract_Factory_Register.hpp ├── GILES.cpp ├── IO.cpp ├── IO.hpp ├── Main.cpp ├── Models │ ├── Hamming_Weight │ │ ├── Model_Hamming_Weight.cpp │ │ └── Model_Hamming_Weight.hpp │ ├── Model.hpp │ ├── Model_Math.hpp │ ├── Power │ │ ├── Model_Power.cpp │ │ └── Model_Power.hpp │ └── TEMPLATE │ │ ├── Model_TEMPLATE.cpp │ │ └── Model_TEMPLATE.hpp ├── Simulators │ ├── Emulator.hpp │ ├── TEMPLATE │ │ ├── Emulator_TEMPLATE.cpp │ │ └── Emulator_TEMPLATE.hpp │ └── Thumb_Sim │ │ ├── Emulator_Thumb_Sim.cpp │ │ └── Emulator_Thumb_Sim.hpp ├── Utility.hpp ├── Validator_Coefficients.cpp └── Validator_Coefficients.hpp ├── test ├── CMakeLists.txt ├── Test_Coefficients.cpp ├── Test_Execution.cpp ├── Test_Factory.cpp ├── Test_Validator_Coefficients.cpp └── Tests.cpp └── uml ├── Class.plantuml ├── Sequence.plantuml └── UseCase.plantuml /.clang-format: -------------------------------------------------------------------------------- 1 | AccessModifierOffset : -4 2 | AlignConsecutiveAssignments : true 3 | AlignTrailingComments : true 4 | AllowShortFunctionsOnASingleLine : true 5 | BasedOnStyle : llvm 6 | BinPackArguments : false 7 | BinPackParameters : false 8 | BreakBeforeBraces : Allman 9 | ColumnLimit : 80 10 | FixNamespaceComments : true 11 | IndentWidth : 4 12 | PointerBindsToType : true 13 | SpacesBeforeTrailingComments : 2 14 | TabWidth : 8 15 | UseTab : Never 16 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/Traces-Serialiser"] 2 | branch = master 3 | path = external/Traces_Serialiser 4 | url = https://github.com/bristol-sca/Traces-Serialiser.git 5 | [submodule "external/cxxopts"] 6 | branch = master 7 | path = external/cxxopts 8 | url = https://github.com/jarro2783/cxxopts.git 9 | [submodule "external/json"] 10 | branch = master 11 | path = external/json 12 | url = https://github.com/nlohmann/json.git 13 | [submodule "external/Catch2"] 14 | branch = master 15 | path = external/Catch2 16 | url = https://github.com/catchorg/Catch2.git 17 | [submodule "external/thumb-sim"] 18 | branch = master 19 | path = external/thumb-sim 20 | url = https://github.com/bristol-sca/thumb-sim.git 21 | [submodule "external/fmt"] 22 | branch = master 23 | path = external/fmt 24 | url = https://github.com/fmtlib/fmt 25 | -------------------------------------------------------------------------------- /Adding_Models_and_Simulators.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | - [Adding new Models](#adding-new-models) 6 | * [Copy the folder](#copy-the-folder) 7 | * [Rename all references to TEMPLATE to your new model name](#rename-all-references-to-template-to-your-new-model-name) 8 | * [Update m_required_terms](#update-m_required_terms) 9 | * [Implement the function Generate_Traces() (At the bottom of the cpp file)](#implement-the-function-generate_traces-at-the-bottom-of-the-cpp-file) 10 | * [Add the cpp file to the cmake build](#add-the-cpp-file-to-the-cmake-build) 11 | - [Adding new Simulators](#adding-new-simulators) 12 | * [Copy the folder](#copy-the-folder-1) 13 | * [Rename all references to TEMPLATE to your new simulator name](#rename-all-references-to-template-to-your-new-simulator-name) 14 | * [In the cpp file, **implement the Run_Code() function**](#in-the-cpp-file-implement-the-run_code-function) 15 | * [Add the cpp file to the cmake build](#add-the-cpp-file-to-the-cmake-build-1) 16 | * [Optional steps](#optional-steps) 17 | + [Implement the remaining functions in the cpp file](#implement-the-remaining-functions-in-the-cpp-file) 18 | - [Implement the Get_Extra_Data() function](#implement-the-get_extra_data-function) 19 | - [Implement the Inject_Fault() function](#implement-the-inject_fault-function) 20 | - [Implement the Add_Timeout() function](#implement-the-add_timeout-function) 21 | + [Implement the functions in elmo-funcs.h](#implement-the-functions-in-elmo-funcsh) 22 | - [start_trigger()/pause_trigger()](#start_triggerpause_trigger) 23 | - [get_rand()](#get_rand) 24 | - [add_byte_to_trace()/add_to_trace()](#add_byte_to_traceadd_to_trace) 25 | 26 | 27 | 28 | # Adding new Models 29 | 30 | ## Copy the folder 31 | Copy `src/Models/TEMPLATE` to `src/Models/*your-new-model-name*` 32 | 33 | ## Rename all references to TEMPLATE to your new model name 34 | Update the comments to match this. 35 | 36 | ## Update m_required_terms 37 | In the cpp file, update m_required_terms to contain a list of all the terms 38 | your model requires to be loaded from a coefficients file. 39 | 40 | **If your Model does not require anything to be loaded** make this an empty 41 | list. 42 | 43 | ## Implement the function Generate_Traces() (At the bottom of the cpp file) 44 | 45 | This function will generate the traces for you. m_execution and m_coefficients 46 | should contain the data you need. To understand more about these, look at the 47 | Execution and Coefficients class in the 48 | [API Documentation.](README.md#api-documentation) 49 | 50 | ## Add the cpp file to the cmake build 51 | This is done in the file `src/CMakeLists.txt`. The TEMPLATE file is listed in 52 | here, but commented out. This one line is exactly how your new model needs to 53 | be added to the build. 54 | 55 | # Adding new Simulators 56 | 57 | This is slightly harder than adding a new model but largely a similar 58 | process. 59 | 60 | ## Copy the folder 61 | Copy `src/Simulators/TEMPLATE` to `src/Simulators/*your-new-simulator-name*` 62 | 63 | ## Rename all references to TEMPLATE to your new simulator name 64 | Update the comments to match this. 65 | 66 | ## In the cpp file, **implement the Run_Code() function** 67 | m_program_path contains the path to the target program. This needs to be loaded 68 | and ran on whichever simulator is being integrated. 69 | 70 | This function needs to return a complete Execution object. This will contain 71 | a complete recording of the state of all registers and pipeline stages 72 | (Fetch, Decode, Execute, etc) during every clock cycle. This is the information 73 | that will later be used to generate traces from. 74 | 75 | The simulator may need to be edited in order to record this information. 76 | Take a look at the Execution class in the 77 | [API Documentation](README.md#api-documentation) for details about what needs 78 | to be made. 79 | 80 | ## Add the cpp file to the cmake build 81 | This is done in the file `src/CMakeLists.txt`. The TEMPLATE file is listed in 82 | here, but commented out. This one line is exactly how your new simulator needs 83 | to be added to the build. 84 | 85 | ## Optional steps 86 | 87 | **The rest of the steps are optional but highly recommended.** It is very likely 88 | that the rest of the steps will require custom edits to the simulator. 89 | 90 | ### Implement the remaining functions in the cpp file 91 | These can be left as stubs and these features will be simply unavailable. 92 | 93 | The implementation of these functions will be specific to the simulator and may 94 | require editing the simulators internals. 95 | 96 | #### Implement the Get_Extra_Data() function 97 | 98 | This requires the [add_to_trace()](#implement-the-get_extra_data-function) 99 | function to be implemented. 100 | 101 | When called, it will return the data stored by the 102 | [add_to_trace() function.](#implement-the-get_extra_data-function) 103 | 104 | #### Implement the Add_Timeout() function 105 | 106 | This function should add a timeout so that the simulator will stop executing 107 | the target program after the number of cycles given by the parameter have 108 | passed. 109 | 110 | It should still be run through the use of Run_Code() and 111 | should return normally. It is recommended to print a message indicating that the 112 | timeout has been reached. 113 | 114 | #### Implement the Inject_Fault() function 115 | 116 | This function should add a trigger so that after a set number of cycles have 117 | passed a bit flip should occur within one of the registers. The details of this 118 | are provided in parameters. 119 | 120 | It should still be run through the use of Run_Code() and 121 | should return normally. 122 | 123 | ### Implement the functions in elmo-funcs.h 124 | 125 | These functions allow special operations to be performed on the simulator from 126 | within the target program. 127 | 128 | #### start_trigger()/pause_trigger() 129 | 130 | These functions when called will start or pause the recording of the execution 131 | of the target program. This is only useful when generating traces and can be 132 | used to profile a subsection of the target program. 133 | 134 | #### get_rand() 135 | 136 | This function should simply return a random number. This is useful as often 137 | simulators do not contain a source of randomness. This is not needed if another 138 | source of randomness is available. 139 | 140 | #### add_byte_to_trace()/add_to_trace() 141 | 142 | Extra data can be added to each trace in a trs file. This data can be anything 143 | that will be useful to record, e.g. the plain text or key of a cryptographic 144 | algorithm. 145 | 146 | This function should place this data somewhere to be retrieved later by the 147 | [Get_Extra_Data() function created earlier.](#implement-the-get_extra_data-function) 148 | -------------------------------------------------------------------------------- /BUILDING.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | - [Getting started for development](#getting-started-for-development) 6 | * [Prerequisites](#prerequisites) 7 | + [Linux](#linux) 8 | + [MacOS](#macos) 9 | + [Windows](#windows) 10 | * [Get the code](#get-the-code) 11 | * [Building](#building) 12 | * [Running unit tests](#running-unit-tests) 13 | + [Coverage information](#coverage-information) 14 | - [CMake Configuration Options](#cmake-configuration-options) 15 | * [GILES_BUILD_DOCUMENTATION](#giles_build_documentation) 16 | * [GILES_CALCULATE_COVERAGE](#giles_calculate_coverage) 17 | - [Packaging](#packaging) 18 | 19 | 20 | 21 | ## Getting started for development 22 | 23 | ### Prerequisites 24 | 25 | This uses [CMake.](https://cmake.org/) As such, CMake needs to be 26 | installed first. 27 | Additionally, [Boost](https://www.boost.org/) needs to be installed manually. 28 | 29 | #### Linux 30 | 31 | The recommended way of installing CMake and Boost is through your package 32 | manager. 33 | 34 | If either package isn't available on your Linux distribution follow the 35 | [official CMake install instructions](https://cmake.org/install/) 36 | or the [official boost instructions.](https://www.boost.org/users/download/) 37 | 38 | #### MacOS 39 | 40 | CMake and boost can be installed using [Homebrew](https://brew.sh/) with the 41 | following command. 42 | ``` 43 | brew install cmake boost-python 44 | ``` 45 | Alternatively, follow the 46 | [official CMake install instructions](https://cmake.org/install/) 47 | and the [official boost instructions.](https://www.boost.org/users/download/) 48 | 49 | #### Windows 50 | 51 | Follow the [official CMake install instructions](https://cmake.org/install/) 52 | and the [official boost instructions.](https://www.boost.org/users/download/) 53 | 54 | ### Get the code 55 | 56 | It is highly recommended, but not essential, to use git to get the code. 57 | **Use this command** to get a copy: 58 | ``` 59 | git clone --recurse-submodules https://github.com/bristol-sca/GILES 60 | ``` 61 | **Note that the 62 | [--recurse-submodules flag](https://www.git-scm.com/docs/git-clone#Documentation/git-clone.txt---recurse-submodulesltpathspec) 63 | is needed.** 64 | 65 | If downloading manually or without this flag, you will also need to download the 66 | projects 67 | [in the external directory.](https://github.com/bristol-sca/GILES/tree/master/external) 68 | 69 | Additionally the 70 | [--jobs flag](https://www.git-scm.com/docs/git-clone#Documentation/git-clone.txt---jobsltngt) 71 | can be used to speed this process up. 72 | 73 | ### Building 74 | 75 | 1) **Create an empty build directory.** 76 | 77 | 2) **From the build directory you just created, run this command.** 78 | This will generate native build files for your platform. 79 | A specific generator can be specified using the 80 | `-G *generator*` flag. 81 | A [list of generators is available here.](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html) 82 | ``` 83 | cmake /path-to-source-directory 84 | ``` 85 | 86 | 3) **Run this command to compile the code.** This will compile the program using 87 | your chosen generator e.g. make. Alternatively the native build system can be 88 | used manually from this point on. 89 | ``` 90 | cmake --build . 91 | ``` 92 | 93 | ### Running unit tests 94 | 95 | 1) Firstly follow the instructions in the 96 | [**Getting started for Development section.**](#getting-started-for-development) 97 | 98 | 2) **Build the tests with this command.** This will tell the native build system 99 | to build the target called GILES-tests. 100 | ``` 101 | cmake --build . --target GILES-tests 102 | ``` 103 | 3) **Run the tests** 104 | ``` 105 | /path-to-build-directory/bin/tests 106 | ``` 107 | 108 | #### Coverage information 109 | 110 | In order to generate code coverage information, [Gcovr](https://gcovr.com/) is 111 | required. 112 | 113 | 1) **Regenerate the build files** using the option [shown below](#GILES_calculate_coverage) from the build 114 | directory. This is needed as specific compile flags need to be added in order to 115 | generate coverage information. 116 | ``` 117 | cmake /path-to-source-directory -DGILES_CALCULATE_COVERAGE=ON 118 | ``` 119 | 120 | 2) **Run this command.** This will tell the native build system to build the 121 | target called coverage. 122 | ``` 123 | cmake --build . --target coverage 124 | ``` 125 | Coverage information can be found by opening the file `coverage.html` in the 126 | folder `coverage` which should have been created in your *`build directory`*. 127 | ``` 128 | /path-to-build-directory/coverage/coverage.html 129 | ``` 130 | 131 | ## CMake Configuration Options 132 | 133 | These are all CMake options and can be appended to the CMake generate command. 134 | For example, from the build directory: 135 | ``` 136 | cmake /path-to-source-directory -DGILES_BUILD_DOCUMENTATION 137 | ``` 138 | 139 | ### GILES_BUILD_DOCUMENTATION 140 | 141 | This option will always built the "doc" target when the target "all" is built. 142 | See [API Documentation section.](#api-documentation) 143 | 144 | ### GILES_CALCULATE_COVERAGE 145 | 146 | This is needed to generate code coverage information. 147 | See [Coverage information](#coverage-information) for details on how to do this. 148 | 149 | **⚠️ Warning ⚠️ 150 | This will enable compile flags that are not recommended for normal 151 | purposes. Set this to OFF after you are done generating coverage information.** 152 | 153 | ## Packaging 154 | 155 | CMake's CPack is used for packaging. 156 | 157 | The command to build and package for your current operating system is 158 | ``` 159 | cmake --build . --target package --config release 160 | ``` 161 | 162 | Packaging as an [RPM](https://en.wikipedia.org/wiki/RPM_Package_Manager) 163 | package requires rpmbuild to be installed. 164 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[=[ 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | #]=] 17 | 18 | # Specify the minimum required version for CMake 19 | cmake_minimum_required(VERSION 3.0) 20 | 21 | # Project's name 22 | project(GILES) 23 | 24 | set(${PROJECT_NAME}_VERSION_MAJOR 1) 25 | set(${PROJECT_NAME}_VERSION_MINOR 1) 26 | set(${PROJECT_NAME}_VERSION_PATCH 0) 27 | 28 | # Stricter warnings 29 | # TODO: Replace with this: https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/#leave-cmake_cxx_flags-alone 30 | #set(Custom_Flags "${Custom_Flags} -Wall -Wextra -Wpedantic -Weffc++") 31 | 32 | # Even stricter warnings when using clang only 33 | if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") 34 | 35 | #set(Custom_Flags "${Custom_Flags} -Weverything") 36 | 37 | # Disable unwanted warnings 38 | set(Custom_Flags "${Custom_Flags} -Wno-c++98-compat") 39 | endif() 40 | 41 | # Coloured compilation output 42 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color") 43 | 44 | # Performance profiling 45 | #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") 46 | 47 | #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Ofast") 48 | #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") 49 | #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") 50 | 51 | # Warnings are errors 52 | #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") 53 | 54 | # Place executables into a 'bin' folder 55 | set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/bin) 56 | 57 | # Place libraries into a 'lib' folder 58 | set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/lib) 59 | 60 | set(EXTERNAL_PROJECT_DIR ${PROJECT_SOURCE_DIR}/external) 61 | 62 | # Recurse into the "test" subdirectory. This does not actually 63 | # cause another cmake executable to run. The same process will walk through 64 | # the project's entire directory structure. 65 | # The "test" directory is added before "src" so that compile flags can be added 66 | # if coverage is enabled. 67 | add_subdirectory(test EXCLUDE_FROM_ALL) 68 | 69 | add_subdirectory(doc) 70 | 71 | # Build external projects 72 | add_subdirectory(${EXTERNAL_PROJECT_DIR}) 73 | 74 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Custom_Flags}") 75 | add_subdirectory(src) 76 | 77 | 78 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "General Instruction Leakage Simulator") 79 | set(CPACK_PACKAGE_DESCRIPTION "A tool for simulating side-channel analysis traces") 80 | set(CMAKE_PROJECT_HOMEPAGE_URL "https://github.com/bristol-sca/GILES") 81 | set(CPACK_PACKAGE_CONTACT "scott.egerton@bristol.ac.uk") 82 | 83 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING") 84 | 85 | set(CPACK_PACKAGE_VERSION_MAJOR "${${PROJECT_NAME}_VERSION_MAJOR}") 86 | set(CPACK_PACKAGE_VERSION_MINOR "${${PROJECT_NAME}_VERSION_MINOR}") 87 | set(CPACK_PACKAGE_VERSION_PATCH "${${PROJECT_NAME}_VERSION_PATCH}") 88 | 89 | if(APPLE) 90 | set(CPACK_GENERATOR "productbuild" ${CPACK_GENERATOR}) 91 | endif() 92 | 93 | set(CPACK_BINARY_DEB ON) 94 | 95 | # There is a dependency bug here "Nothing provides libGILES" 96 | set(CPACK_BINARY_RPM OFF) 97 | 98 | set(CPACK_RPM_PACKAGE_PROVIDES lib${PROJECT_NAME}) 99 | set(CPACK_DEBIAN_PACKAGE_PROVIDES ${CPACK_RPM_PACKAGE_PROVIDES}) 100 | 101 | include(CPack) 102 | -------------------------------------------------------------------------------- /LOGO_ERC-FLAG_EU.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sca-research/GILES/a2d541bedd4b52dc87595e5b8f9ccf7df51beaa8/LOGO_ERC-FLAG_EU.jpg -------------------------------------------------------------------------------- /OPTIONS.md: -------------------------------------------------------------------------------- 1 | # All command line options 2 | All command line options can be printed using the -h or --help flags shown here: 3 | ``` 4 | ./GILES --help 5 | ``` 6 | This should produce the result below. 7 | ``` 8 | General instruction leakage simulator 9 | Usage: bin/GILES [--input] EXECUTABLE [--coefficients] COEFFICIENTS 10 | : 11 | -h [ --help ] Print help 12 | -r [ --runs ] arg (=1) Number of traces to generate 13 | -c [ --coefficients ] arg (=./coeffs.json) 14 | Coefficients file 15 | -i [ --input ] arg Executable to be ran in the simulator 16 | -o [ --output ] arg Generated traces output file 17 | -s [ --simulator ] arg (=Thumb Sim) The name of the simulator that should 18 | be used 19 | -m [ --model ] arg (=Hamming Weight) The name of the mathematical model that 20 | should be used to generate traces 21 | -f [ --fault ] arg Where to inject a fault. e.g. "--fault 22 | 10 R0 2" is inject a fault before the 23 | 10th clock cycle, by flipping the 24 | second least significant bit in the 25 | register R0 26 | -t [ --timeout ] arg The number of clock cycles to force 27 | stop execution after 28 | ``` 29 | 30 | 31 | 32 | - [--runs/-r](#--runs-r) 33 | - [--coefficients/-c](#--coefficients-c) 34 | - [--input/-i](#--input-i) 35 | - [--output/-o](#--output-o) 36 | - [--simulator/-s](#--simulator-s) 37 | - [--model/-m](#--model-m) 38 | - [--fault/-f](#--fault-f) 39 | - [--timeout/-t](#--timeout-t) 40 | 41 | 42 | 43 | ## --runs/-r 44 | 45 | This controls the number of times the target program will run within the 46 | simulator. When generating traces, this consequently controls the number of 47 | traces generated. 48 | 49 | This is an optional argument and will default to 1 run. 50 | 51 | ## --coefficients/-c 52 | 53 | Some models such as the ELMO power model require a coefficients file. 54 | 55 | This option indicates the path to this file. This is an optional argument and 56 | if not specified, GILES will look for the file coeffs.json in the currently 57 | directory and use that. If that is not found then it will continue without 58 | coefficients as they may not be needed. 59 | 60 | ## --input/-i 61 | 62 | This indicates the path to the target program to be run within the simulator. 63 | 64 | This is the only option that isn't optional and GILES will not run without it. 65 | 66 | ## --output/-o 67 | 68 | The path to save generated traces to. This is optional but if not specified a 69 | warning will be displayed as without this flag, it is possible to have long 70 | running operations producing no output. 71 | 72 | ## --simulator/-s 73 | 74 | This option can be ignored for now. 75 | 76 | The name of the simulator to use. Currently the only supported simulator is the 77 | [Thumb Timing Simulator](https://github.com/bristol-sca/thumb-sim) and this is 78 | the default option. 79 | 80 | ## --model/-m 81 | 82 | The name of the model to use. Valid names are shown under the 83 | [Leakage generation models section in the README.](README.md#leakage-generation-models) 84 | 85 | If not specified, this will default to "Hamming Weight". 86 | 87 | ## --fault/-f 88 | 89 | This option is used to inject faults. It required three arguments. For example: 90 | `--fault 10 R0 2" is inject a fault before the 10th clock cycle, by flipping the 91 | second least significant bit in the register R0. 92 | 93 | If not specificed, no faults will be injected. 94 | 95 | ## --timeout/-t 96 | 97 | This option is to stop execution after a set number of clock cycles have passed. 98 | This is designed to prevent infinite loops. 99 | 100 | If not specificed, no limit will be applied. 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GILES 2 | 3 | GILES is designed to help software engineers quickly identify 4 | [side channel](https://en.wikipedia.org/wiki/Side-channel_attack) and 5 | [fault injection](https://en.wikipedia.org/wiki/Fault_injection) 6 | security risks during development stages. 7 | 8 | 9 | 10 | - [Motivation](#motivation) 11 | - [Description](#description) 12 | - [Usage](#usage) 13 | - [All command line options](#all-command-line-options) 14 | - [Leakage generation models](#leakage-generation-models) 15 | * [ELMO Power model](#elmo-power-model) 16 | * [Hamming weight model](#hamming-weight-model) 17 | * [Others](#others) 18 | - [Output format](#output-format) 19 | - [API Documentation](#api-documentation) 20 | - [Building](#building) 21 | - [Built with](#built-with) 22 | - [License](#license) 23 | - [Acknowledgement](#acknowledgement) 24 | 25 | 26 | 27 | ## Motivation 28 | 29 | Developing software for leaky processors is not straightforward and even 30 | experienced developers need to check if the measures that they put in place 31 | actually work. Rather than having to go through the onerous task of a fully 32 | blown lab evaluation, it would be great if a "push button" solution could be 33 | run over the code that identifies leaks and maybe even helps fix them. 34 | GILES includes instruction level power profiles 35 | (taken on our high lab equipment) and "plugs them into" a simulator, 36 | thereby providing an instruction accurate leakage emulator. 37 | 38 | ## Description 39 | 40 | This tool simulates instruction-level 41 | [side channel analysis](https://en.wikipedia.org/wiki/Side-channel_attack) 42 | leakage without the need for anything other that a target program. 43 | Additionally it allows for fault injection attacks to be performed concurrently. 44 | 45 | It can support multiple different processors and multiple different methods of 46 | generating leakage from these. 47 | Currently the only supported simulator is the 48 | [Thumb Timing Simulator](https://github.com/bristol-sca/thumb-sim). 49 | This will simulate an 50 | [ARM Cortex M0 processor.](https://developer.arm.com/products/processors/cortex-m/cortex-m0) 51 | The [supported leakage models can be found here.](#leakage-generation-models) 52 | 53 | Please feel free to add more simulators and models! 54 | [Here is a guide](Adding_Models_and_Simulators.md) on how to do this. 55 | 56 | ## Usage 57 | 58 | 1) **[Download from the releases page](https://github.com/bristol-sca/GILES/releases)** 59 | Alternatively, [build it yourself](#building). 60 | 61 | 2) **Compile your target program for your chosen simulator.** 62 | Currently only one simulator is supported, 63 | [Thumb Timing Simulator](https://github.com/bristol-sca/thumb-sim), 64 | so compile for this simulator for now. 65 | [Here is an example](https://github.com/bristol-sca/thumb-sim/tree/master/example) 66 | to help you get started. 67 | 68 | It is heavily recommended (but not essential) that you make use of the 69 | `elmo-funcs.h` file to provide useful functions, such as trigger points and the 70 | ability to get random data inside the simulator. This can be 71 | [found on the releases page.](https://github.com/bristol-sca/GILES/releases) 72 | 73 | 74 | The target program should be edited to replace the target 75 | data, such as the cryptographic key, with randomly generated values. 76 | 77 | 3) **Run GILES.** 78 | Here is an example of the most common usage. 79 | ``` 80 | GILES my-program-binary-from-step-2 -o output-file.trs 81 | ``` 82 | This will use the Hamming weight model. 83 | [See here for more on models.](#leakage-generation-models) 84 | The ELMO power model requires the file coeffs.json to be in the same directory 85 | or specified like so: 86 | ``` 87 | GILES my-program-binary-from-step-2 --coefficients some-path/coeffs.json -o output-file.trs 88 | ``` 89 | 90 | 4) Done! Perform whatever side channel attacks/analysis you want on the 91 | [output file.](#output-format) 92 | 93 | ## All command line options 94 | All command line options can be printed using the -h or --help flags shown here: 95 | ``` 96 | GILES --help 97 | ``` 98 | This should produce the result below. 99 | ``` 100 | General instruction leakage simulator 101 | Usage: bin/GILES [--input] EXECUTABLE [--coefficients] COEFFICIENTS 102 | : 103 | -h [ --help ] Print help 104 | -r [ --runs ] arg (=1) Number of traces to generate 105 | -c [ --coefficients ] arg (=./coeffs.json) 106 | Coefficients file 107 | -i [ --input ] arg Executable to be ran in the simulator 108 | -o [ --output ] arg Generated traces output file 109 | -s [ --simulator ] arg (=Thumb Sim) The name of the simulator that should 110 | be used 111 | -m [ --model ] arg (=Hamming Weight) The name of the mathematical model that 112 | should be used to generate traces 113 | -f [ --fault ] arg Where to inject a fault. e.g. "--fault 114 | 10 R0 2" is inject a fault before the 115 | 10th clock cycle, by flipping the 116 | second least significant bit in the 117 | register R0 118 | -t [ --timeout ] arg The number of clock cycles to force 119 | stop execution after 120 | ``` 121 | 122 | [See here](OPTIONS.md) for a more in depth description of the available flags. 123 | 124 | ## Leakage generation models 125 | 126 | There are currently two methods supported for generating leakage supported. 127 | 128 | ### ELMO Power model 129 | 130 | This is the recommend model for generating high quality leakage. 131 | 132 | This can be used by specifying --model Power. 133 | 134 | [Details of how it works can be found here.](https://www.usenix.org/conference/usenixsecurity17/technical-sessions/presentation/mccann) 135 | 136 | ### Hamming weight model 137 | 138 | This is the default model and will generate leakage much faster but the 139 | leakage may not be as high quality. 140 | 141 | This is the default model that will be used if none as specified. 142 | 143 | This works by taking the 144 | [Hamming weight](https://en.wikipedia.org/wiki/Hamming_weight) 145 | of the operands of the instructions executed. 146 | 147 | ### Others 148 | 149 | Please help add more if you can! 150 | There will be a document describing how to do this at some point. 151 | 152 | ## Output format 153 | 154 | GILES currently saves traces in the `.trs` format. 155 | This format is designed for use in 156 | [Riscure's Inspector](https://www.riscure.com/security-tools/inspector-sca/), 157 | but can be interpreted in 158 | [other ways](https://github.com/Riscure/python-trsfile). 159 | 160 | We hope to support alternative formats in the future. 161 | 162 | ## API Documentation 163 | 164 | Documentation is generated using 165 | [Doxygen.](http://www.doxygen.nl/) In order to generate this 166 | follow these instructions: 167 | 168 | 1) [**Install Doxygen**](http://www.doxygen.nl/download.html) 169 | 170 | 2) Firstly follow the instructions in the 171 | [**Getting started for Development section.**](BUILDING.md#getting-started-for-development) 172 | 173 | 3) Documentation can be built with CMake using the "doc" target by **running the 174 | command as shown.** 175 | ``` 176 | cmake --build . --target doc 177 | ``` 178 | 179 | 4) **Open this file** 180 | ``` 181 | /path/to/build/directory/doc/html/index.html 182 | ``` 183 | 184 | Additionally, enabling the cmake configuration option 185 | `GILES_BUILD_DOCUMENTATION` will generate the documentation every 186 | time you compile. 187 | 188 | ## Building 189 | 190 | Refer to [BUILDING.md](BUILDING.md) for developer specific information. 191 | 192 | ## Built with 193 | 194 | - C++ 195 | - [CMake](https://cmake.org/) 196 | - [JSON for modern C++](https://github.com/nlohmann/json) 197 | - [OpenMP](https://www.openmp.org) 198 | - [Catch2](https://github.com/catchorg/Catch2) 199 | - [Traces Serailiser](https://github.com/bristol-sca/Traces-Serialiser) 200 | - [Thumb Timing Simulator](https://github.com/bristol-sca/thumb-sim) 201 | - [Boost](https://www.boost.org/) 202 | - [{fmt}](https://github.com/fmtlib/fmt) 203 | - [Gcovr](https://gcovr.com/) 204 | - [Doxygen](http://www.doxygen.nl/) 205 | - [markdown-toc](https://github.com/jonschlinkert/markdown-toc) 206 | - [LinuxDeploy](https://github.com/linuxdeploy/linuxdeploy) 207 | 208 | Thank you to the creators of all these. 209 | Without these, this would not have been possible. 210 | 211 | ## License 212 | This program is released under license AGPLv3+. 213 | 214 | Get a summary of this license 215 | [here at choosealicense.com](https://choosealicense.com/licenses/agpl-3.0/) 216 | 217 | ## Acknowledgement 218 | This project has received funding from the European Research Council (ERC) under the European Union’s 219 | Horizon 2020 research and innovation programme (grant agreement No 725042). 220 | 221 | ![EU Logo](https://github.com/bristol-sca/GILES/blob/master/LOGO_ERC-FLAG_EU.jpg "ERC") 222 | -------------------------------------------------------------------------------- /cmake/External.cmake: -------------------------------------------------------------------------------- 1 | #[=[ 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | #]=] 17 | 18 | # This option adds all dependencies to be re-downloaded as a method of updating 19 | # them. Dependencies that had not yet been downloaded will be downloaded. 20 | option(${PROJECT_NAME}_UPDATE_EXTERNAL_PROJECTS "Force re-download all external\ 21 | project files (Requires Git)" 22 | OFF) #TODO: Attach this to update all submodules command found online 23 | 24 | # This macro will clone the git submodule given by NAME into EXTERNAL_PROJECT_DIR if 25 | # it is not already there and include the directory within that project given by 26 | # INCLUDE_DIRECTORY in the building of TARGET. 27 | macro(target_include_external_project TARGET NAME INCLUDE_DIRECTORY) 28 | if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${NAME}) 29 | 30 | # Git is required to clone the submodules. Ensure this is found first. 31 | find_package(Git REQUIRED) 32 | 33 | # Checks whether the directory given by EXTERNAL_PROJECT_DIR exists, if it 34 | # does not then CMake will create it. 35 | if(NOT EXISTS ${EXTERNAL_PROJECT_DIR}) 36 | file(MAKE_DIRECTORY ${EXTERNAL_PROJECT_DIR}) 37 | endif() 38 | 39 | # Clone/Update the submodule 40 | execute_process(COMMAND git submodule update --init -- ${NAME} 41 | WORKING_DIRECTORY ${EXTERNAL_PROJECT_DIR}) 42 | 43 | target_include_directories(${TARGET} SYSTEM PRIVATE 44 | ${EXTERNAL_PROJECT_DIR}/${NAME}/${INCLUDE_DIRECTORY}) 45 | 46 | if(${PROJECT_NAME}_UPDATE_EXTERNAL_PROJECTS) 47 | update_external_submodules() 48 | endif() 49 | endif() 50 | endmacro() 51 | 52 | macro(get_submodule NAME) 53 | if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${NAME}) 54 | 55 | # Git is required to clone the submodules. Ensure this is found first. 56 | find_package(Git REQUIRED) 57 | 58 | # Checks whether the directory given by EXTERNAL_PROJECT_DIR exists, if it 59 | # does not then CMake will create it. 60 | if(NOT EXISTS ${EXTERNAL_PROJECT_DIR}) 61 | file(MAKE_DIRECTORY ${EXTERNAL_PROJECT_DIR}) 62 | endif() 63 | 64 | # Clone/Update the submodule 65 | execute_process(COMMAND git submodule update --init -- ${NAME} 66 | WORKING_DIRECTORY ${EXTERNAL_PROJECT_DIR}) 67 | endif() 68 | endmacro() 69 | 70 | macro(update_external_submodules) 71 | if(${PROJECT_NAME}_UPDATE_EXTERNAL_PROJECTS) 72 | # Git is required to clone the submodules. Ensure this is found first. 73 | find_package(Git REQUIRED) 74 | 75 | # Checks whether the directory given by EXTERNAL_PROJECT_DIR exists, if it 76 | # does not then CMake will create it. 77 | if(NOT EXISTS ${EXTERNAL_PROJECT_DIR}) 78 | file(MAKE_DIRECTORY ${EXTERNAL_PROJECT_DIR}) 79 | endif() 80 | 81 | # Update all submodules to their latest commit. 82 | execute_process(COMMAND git submodule update --quiet --recursive --init --remote 83 | WORKING_DIRECTORY ${EXTERNAL_PROJECT_DIR}) 84 | endif() 85 | endmacro() 86 | -------------------------------------------------------------------------------- /doc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[=[ 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | #]=] 17 | 18 | # TODO: Look into replacing this with DoxygenTargets from https://github.com/rpavlik/cmake-modules 19 | # Maybe auto download? 20 | 21 | find_package(Doxygen) 22 | 23 | option(${PROJECT_NAME}_BUILD_DOCUMENTATION 24 | "Create the API documentation (requires Doxygen)" ${DOXYGEN_FOUND} 25 | ) 26 | 27 | # if option is selected then build the documentation with target "all". 28 | if(${PROJECT_NAME}_BUILD_DOCUMENTATION) 29 | set(ALL_OPTION ALL) 30 | endif() 31 | 32 | if(DOXYGEN_FOUND) 33 | # Replace directories with those of the current build directory etc. 34 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in 35 | ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.in @ONLY 36 | ) 37 | 38 | # Needs to be configured twice to correctly evaluate version numbers. 39 | configure_file(${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.in 40 | ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY 41 | ) 42 | 43 | # add a target to generate API documentation with Doxygen 44 | add_custom_target(doc ${ALL_OPTION} 45 | ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 46 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 47 | COMMENT "Generating API documentation with Doxygen" VERBATIM 48 | ) 49 | endif() 50 | -------------------------------------------------------------------------------- /external/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[=[ 2 | This file is part of ELMO-2. 3 | 4 | ELMO-2 is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | ELMO-2 is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with ELMO-2. If not, see . 16 | #]=] 17 | 18 | include("${PROJECT_SOURCE_DIR}/cmake/External.cmake") 19 | 20 | # Downloads and updates all git submodules. 21 | update_external_submodules() 22 | 23 | # Build external projects 24 | add_subdirectory(thumb-sim EXCLUDE_FROM_ALL) 25 | add_subdirectory(Traces_Serialiser EXCLUDE_FROM_ALL) 26 | add_subdirectory(json EXCLUDE_FROM_ALL) 27 | add_subdirectory(fmt EXCLUDE_FROM_ALL) 28 | -------------------------------------------------------------------------------- /src/Assembly_Instruction.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Assembly_Instruction.hpp 20 | @brief The internal representation of an individual assembly instruction. 21 | @author Scott Egerton 22 | @date 2017-2019 23 | @copyright GNU Affero General Public License Version 3+ 24 | */ 25 | 26 | #ifndef ASSEMBLY_INSTRUCTION_HPP 27 | #define ASSEMBLY_INSTRUCTION_HPP 28 | 29 | #include // for uint32_t 30 | #include // for overflow_error, underflow_error 31 | #include // for string 32 | #include // for pair 33 | #include // for vector 34 | 35 | #include // TODO: Convert Uility.h over to boost algorithms (or the other way around?) 36 | 37 | namespace GILES 38 | { 39 | namespace Internal 40 | { 41 | //! @class Assembly_Instruction 42 | //! @brief The internal representation of an individual assembly instruction. 43 | //! This contains the opcode and operands of the instruction as well as a list 44 | //! of registers that have been changed making use of the Register class. 45 | //! @see https://en.wikipedia.org/wiki/Assembly_language 46 | class Assembly_Instruction 47 | { 48 | protected: 49 | //! A pair of the assembly and the binary representation of the opcode. 50 | //! @see https://en.wikipedia.org/wiki/Opcode 51 | //! @todo Future improvement: Store whole encoded instruction as well. 52 | // std::pair> m_opcode; 53 | // This is commented as the encoded opcode does not leak in any way. 54 | 55 | //! @see https://en.wikipedia.org/wiki/Opcode 56 | std::string m_opcode; 57 | 58 | //! The instruction operands stored in human readable form. 59 | //! @see https://en.wikipedia.org/wiki/Operand#Computer_science 60 | //! @todo Does this need to be stored in binary as well? If 61 | //! so then std::pair could be used with boost::dynamic_bitset. 62 | //! @todo Future improvement: Store whole encoded instruction 63 | std::vector m_operands; 64 | 65 | //! The numerical values stored within the operands in m_operands. If the 66 | //! operand is a register, then the value within that register is stored. 67 | //! @see https://en.wikipedia.org/wiki/Operand#Computer_science 68 | //! @todo Does this need to be stored in binary as well? If 69 | //! so then std::pair could be used with boost::dynamic_bitset. 70 | //! @todo Future improvement: Store whole encoded instruction 71 | // std::vector m_operand_values; 72 | 73 | // TODO: Future: Should this be stored in Assembly_Instruction or Execution? 74 | // const std::vector m_changed_registers; 75 | 76 | public: 77 | //! @todo Change brief. 78 | //! @brief The constructor must be given all details about the assembly 79 | //! instruction as these cannot be set or changed later. 80 | //! @param p_opcode The instructions opcode. 81 | //! @param p_opcode_binary The binary representation of the opcode as it 82 | //! would be encoded on real hardware. 83 | //! @param p_operands The binary representation of the operands as they 84 | //! would be encoded on real hardware. 85 | //! @todo Remove temp constructors 86 | //! @todo A disassembler is needed to get opcode as well as binary form of 87 | //! full instruction and binary form of opcode and separate operands 88 | Assembly_Instruction(const std::string& p_opcode, // TODO: Maybe refactor? 89 | std::vector p_operands) 90 | : m_opcode(p_opcode) 91 | { 92 | for (std::string& operand : p_operands) 93 | { 94 | boost::algorithm::trim(operand); // Remove whitespace 95 | m_operands.push_back(operand); 96 | } 97 | } 98 | 99 | // Copy Constructor 100 | Assembly_Instruction(const Assembly_Instruction& other) noexcept 101 | : m_opcode(other.m_opcode), m_operands(other.m_operands) 102 | { 103 | } 104 | 105 | // Move constructor 106 | Assembly_Instruction(Assembly_Instruction&& other) noexcept 107 | : m_opcode(std::move(other.m_opcode)), m_operands(other.m_operands) 108 | { 109 | } 110 | 111 | //! @todo document 112 | //! Move constructor 113 | //// TODO: should move be exchange? 114 | /* 115 | *Assembly_Instruction(const Assembly_Instruction&& other) 116 | * : m_opcode(std::move(other.m_opcode)), 117 | * m_operands(std::move(other.m_operands)) 118 | *{ 119 | *} 120 | */ 121 | 122 | //! @brief Gets the instructions opcode in human readable form e.g. 123 | //! "add". 124 | //! @return The opcode as a string. 125 | const std::string& Get_Opcode() const noexcept { return m_opcode; } 126 | 127 | //! @brief Gets a list of the instructions operands. 128 | //! @return A vector of operands. 129 | // TODO: Should this get the operand at a specified index i.e. 130 | // get_operand(1); //TODO: Implement both after converting OPERANDS to 131 | // ORDERED map. Operands != Registers. A list of registers is better 132 | // stored as a map. 133 | const std::vector& Get_Operands() const { return m_operands; } 134 | 135 | //! @brief Gets one of the instructions operands. 136 | //! @return A string containing the operand. 137 | //! @note get_operand(1) will return 138 | //! @exception std::out_of_range This is thrown when the index given by 139 | //! p_operand_index - 1 is out of the array bounds as no range checking 140 | //! is performed in this function. 141 | //! @throws overflow_error This is thrown when the instruction does not 142 | //! contain enough operands. E.g. The fifth operand is requested when the 143 | //! instruction only has one operand. 144 | //! @throws underflow_error When the number given by p_operand_index is too 145 | //! low to refer to any operand. 146 | //! @note This function is not zero indexed. Get_Operand(1) will retrieve 147 | //! the first operand. 148 | const std::string& Get_Operand(const uint8_t p_operand_index) const 149 | { 150 | if (p_operand_index > m_operands.size()) 151 | { 152 | throw std::overflow_error( 153 | "Cannot retrieve operand. This " + 154 | static_cast(m_opcode) + 155 | "instruction does not have that many operands"); 156 | } 157 | else if (0 == p_operand_index) 158 | { 159 | throw std::underflow_error( 160 | "Cannot retrieve operand. Operand index cannot be 0. This may " 161 | "because this function is not zero indexed. Get_Operand(1) " 162 | "will retrieve the first operand."); 163 | } 164 | return m_operands.at(p_operand_index - 1); 165 | } 166 | 167 | std::size_t Get_Number_of_Operands() const { return m_operands.size(); } 168 | 169 | /* 170 | *const std::size_t Get_Operand_Value(const uint8_t p_operand_index) const 171 | *{ 172 | * try 173 | * { 174 | * return Get_Operand(p_operand_index); 175 | * } 176 | * catch (const std::runtime_error& exception) 177 | * { 178 | * return 0; 179 | * } 180 | *}; 181 | */ 182 | }; 183 | } // namespace Internal 184 | } // namespace GILES 185 | 186 | #endif // EXECUTION_HPP 187 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[=[ 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | #]=] 17 | 18 | option(${PROJECT_NAME}_BUILD_EXECUTABLE 19 | "Build ${PROJECT_NAME} as a command line executable. (The library will be built regardless)" 20 | ON 21 | ) 22 | 23 | # Add library that is built from the source files 24 | add_library(lib${PROJECT_NAME} SHARED 25 | GILES.cpp 26 | Coefficients.cpp 27 | IO.cpp 28 | Validator_Coefficients.cpp 29 | 30 | # Model files 31 | ${CMAKE_CURRENT_SOURCE_DIR}/Models/Hamming_Weight/Model_Hamming_Weight.cpp 32 | ${CMAKE_CURRENT_SOURCE_DIR}/Models/Power/Model_Power.cpp 33 | #${CMAKE_CURRENT_SOURCE_DIR}/Models/TEMPLATE/Model_TEMPLATE.cpp 34 | 35 | # Simulator files 36 | ${CMAKE_CURRENT_SOURCE_DIR}/Simulators/Thumb_Sim/Emulator_Thumb_Sim.cpp 37 | #${CMAKE_CURRENT_SOURCE_DIR}/Simulators/TEMPLATE/Emulator_TEMPLATE.cpp 38 | ) 39 | 40 | target_compile_options(lib${PROJECT_NAME} 41 | PRIVATE 42 | $<$,$,$>: 43 | -Wall 44 | -Wextra 45 | -Wpedantic 46 | -Weffc++ 47 | -fdiagnostics-color> 48 | # Enable -Weverything when using clang 49 | $<$,$>: 50 | -Weverything 51 | -Wno-c++98-compat 52 | -Wno-c++98-compat-pedantic> 53 | ) 54 | 55 | find_package(Boost REQUIRED COMPONENTS system program_options) 56 | 57 | # If OpenMP is available then use it. 58 | find_package(OpenMP) 59 | if(OpenMP_CXX_FOUND) 60 | target_link_libraries(lib${PROJECT_NAME} PUBLIC OpenMP::OpenMP_CXX) 61 | endif() 62 | 63 | target_include_directories(lib${PROJECT_NAME} 64 | PUBLIC 65 | ${CMAKE_CURRENT_SOURCE_DIR} 66 | ${CMAKE_CURRENT_SOURCE_DIR}/Factory 67 | ${CMAKE_CURRENT_SOURCE_DIR}/Models 68 | ${CMAKE_CURRENT_SOURCE_DIR}/Simulators 69 | ) 70 | 71 | # Link to required external projects 72 | target_link_libraries(lib${PROJECT_NAME} 73 | PUBLIC 74 | Traces-Serialiser 75 | nlohmann_json::nlohmann_json 76 | fmt::fmt-header-only 77 | libthumb-sim 78 | Boost::system 79 | Boost::program_options 80 | ) 81 | 82 | set_target_properties(lib${PROJECT_NAME} PROPERTIES 83 | OUTPUT_NAME ${PROJECT_NAME} 84 | # C++17 is required for std::optional and init if statements 85 | # C++14 is required for unique pointers 86 | # C++11 is required for nlohmann_json 87 | CXX_STANDARD 17 88 | CXX_STANDARD_REQUIRED ON 89 | ) 90 | 91 | install(TARGETS lib${PROJECT_NAME} DESTINATION lib) 92 | 93 | if(${PROJECT_NAME}_BUILD_EXECUTABLE) 94 | # Add executable that is a command line wrapper around the library 95 | add_executable(${PROJECT_NAME} Main.cpp) 96 | 97 | target_link_libraries(${PROJECT_NAME} 98 | PUBLIC 99 | lib${PROJECT_NAME} 100 | ) 101 | 102 | set_target_properties(${PROJECT_NAME} PROPERTIES 103 | # C++17 is required for std::optional and init if statements 104 | CXX_STANDARD 17 105 | CXX_STANDARD_REQUIRED ON 106 | ) 107 | 108 | add_dependencies(${PROJECT_NAME} lib${PROJECT_NAME} libthumb-sim) 109 | 110 | install(TARGETS ${PROJECT_NAME} DESTINATION bin) 111 | endif() 112 | 113 | -------------------------------------------------------------------------------- /src/Coefficients.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Coefficients.hpp 20 | @brief Contains the internal representation of the Coefficients file. 21 | @author Scott Egerton 22 | @date 2017-2019 23 | @copyright GNU Affero General Public License Version 3+ 24 | */ 25 | 26 | #include // for find 27 | #include // for out_of_range 28 | 29 | #include "Coefficients.hpp" 30 | 31 | namespace GILES 32 | { 33 | namespace Internal 34 | { 35 | //! @brief Retrieves the category that the given instruction is contained 36 | //! within. This is a utility function that is used to assist in retrieving 37 | //! other 38 | //! data from the coefficients. 39 | //! @param p_opcode The opcode of the instruction for which the category will 40 | //! be retrieved. 41 | //! @returns The name of the category that the instruction is contained within. 42 | //! If the coefficients are not categorised then the instruction opcode is 43 | //! returned. 44 | //! @exception std::out_of_range This exception is thrown if the instruction 45 | //! given by p_opcode is not found within any category in the coefficients. 46 | //! @see https://eprint.iacr.org/2016/517 Section 4.2 for more on the 47 | //! categories. 48 | const std::string& GILES::Internal::Coefficients::Get_Instruction_Category( 49 | const std::string& p_opcode) const 50 | { 51 | for (const auto& category : m_coefficients.items()) 52 | { 53 | // The Instruction Categories are optional. If there are no 54 | // categories then the 'category' is simply the opcode 55 | if (category.key() == p_opcode) 56 | { 57 | return p_opcode; 58 | } 59 | 60 | // Ensure this category has an instruction section before accessing it. 61 | if (category.value().find("Instructions") != category.value().end()) 62 | { 63 | // If the instruction is in this category, return the name of the 64 | // category. 65 | if (const auto& instructions = category.value().at("Instructions"); 66 | instructions.end() != 67 | std::find(instructions.begin(), instructions.end(), p_opcode)) 68 | { 69 | return category.key(); 70 | } 71 | } 72 | } 73 | throw std::out_of_range("This instruction (" + p_opcode + 74 | ") was not found within the Coefficients"); 75 | } 76 | 77 | //! @brief Retrieves a list of all interaction terms contained within the 78 | //! coefficients. This is needed in order to ensure the Model will be 79 | //! provided with the terms it requires. The interaction terms of the first 80 | //! coefficient are used as they should be identical to all other 81 | //! coefficients. 82 | //! @returns All interaction terms contained, as an unordered set. An 83 | //! unordered set is used as the json standard dictates that json data is 84 | //! unordered therefore we should not expect any particular order. 85 | const std::unordered_set 86 | GILES::Internal::Coefficients::Get_Interaction_Terms() const 87 | { 88 | // Coefficients are optional, this handles that case. 89 | if (m_coefficients.empty()) 90 | { 91 | return {}; 92 | } 93 | std::unordered_set interaction_terms; 94 | for (const auto& interaction_term : 95 | m_coefficients.front()["Coefficients"].items()) 96 | { 97 | interaction_terms.insert(interaction_term.key()); 98 | } 99 | return interaction_terms; 100 | } 101 | 102 | //! @brief Retrieves the coefficients for the interaction term given by 103 | //! p_interaction_term under the instruction category that contains the 104 | //! instruction given by p_opcode. 105 | //! @param p_opcode The opcode of the instruction that the Coefficients are 106 | //! required for. 107 | //! @param p_interaction_term The interaction term from within the model 108 | //! that the Coefficients are required for. 109 | //! @returns An ordered vector of the coefficient values. 110 | const std::vector GILES::Internal::Coefficients::Get_Coefficients( 111 | const std::string& p_opcode, const std::string& p_interaction_term) const 112 | { 113 | return get_coefficient>(p_opcode, p_interaction_term); 114 | } 115 | 116 | //! @brief Retrieves the Constant for the Instruction Category that contains 117 | //! the instruction provided by p_opcode. 118 | //! @param p_opcode The opcode of the instruction that the Constant is 119 | //! required for. 120 | //! @returns The value of the constant for the category that the 121 | //! instruction belongs to. 122 | double 123 | GILES::Internal::Coefficients::Get_Constant(const std::string& p_opcode) const 124 | { 125 | return get_value_opcode(p_opcode, "Constant"); 126 | } 127 | } // namespace Internal 128 | } // namespace GILES 129 | -------------------------------------------------------------------------------- /src/Coefficients.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Coefficients.hpp 20 | @brief Contains the internal representation of the Coefficients file. 21 | @author Scott Egerton 22 | @date 2017-2019 23 | @copyright GNU Affero General Public License Version 3+ 24 | */ 25 | 26 | #ifndef COEFFICIENTS_HPP 27 | #define COEFFICIENTS_HPP 28 | 29 | #include // for string 30 | #include // for typeid 31 | #include // for unordered_set 32 | #include // for vector 33 | 34 | #include // for demangle 35 | #include // for json 36 | 37 | #include "Error.hpp" // for Report_Error 38 | 39 | #include 40 | 41 | namespace GILES 42 | { 43 | namespace Internal 44 | { 45 | //! @class Coefficients 46 | //! @brief The internal representation of the Coefficients file. 47 | //! The Coefficients file contains the coefficient values that were created by 48 | //! measuring real hardware traces. Each instruction will have a set of terms 49 | //! with a list of corresponding values that will be used to calculate 50 | //! predicted traces by the Model class. 51 | //! @see https://eprint.iacr.org/2016/517 52 | class Coefficients 53 | { 54 | private: 55 | const nlohmann::json m_coefficients; 56 | 57 | //! @brief Retrieves a value from the Coefficients. This is a generic 58 | //! function that can retrieve anything, dependent on its parameters. The 59 | //! parameters in p_categories are all evaluated in the order they are 60 | //! provided, each representing a sub category within the last, all within 61 | //! the coefficients. Once all the sub categories have been evaluated, what 62 | //! is found within that final category is retrieved as the type given by 63 | //! T_return. 64 | //! @tparam T_return The return type. 65 | //! @tparam T_categories The type of the names of the sub categories. This 66 | //! is only a template in order to be variadic; this is enforced as a string 67 | //! or something that can be static_cast into a string. 68 | //! @param p_categories This is a variadic parameter where each value 69 | //! represents a sub level within the Coefficients. 70 | //! @returns The value at the end of all the sub levels as the type given by 71 | //! T_return. 72 | template 75 | T_return static get_value(const nlohmann::json& p_coefficients, 76 | const T_head_category& p_head, 77 | const T_categories&... p_categories) 78 | { 79 | // If there are still more than 1 level left to recurse into. 80 | if constexpr (1 <= sizeof...(T_categories)) 81 | { 82 | // Go one level deeper and then recurse. 83 | return get_value(p_coefficients.at(p_head), 84 | p_categories...); 85 | } 86 | else 87 | { 88 | // This is the last sub level, stop recursing and start returning. 89 | try 90 | { 91 | return p_coefficients.at(p_head); 92 | } 93 | // If retrieval fails then throw an error that is slightly easier to 94 | // understand than a generic json type error. 95 | catch (const nlohmann::detail::type_error&) 96 | { 97 | GILES::Internal::Error::Report_Error( 98 | "Cannot retrieve value: {} from Coefficients as the chosen " 99 | "type: {}", 100 | p_coefficients.dump(4), 101 | boost::core::demangle(typeid(T_return).name())); 102 | } 103 | // If one of the categories doesn't exist then throw an error that 104 | // is slightly easier to understand than a generic json type error. 105 | catch (const nlohmann::detail::exception& exception) 106 | { 107 | // TODO: Is this a valid alternative ? It works 108 | // return T_return{}; 109 | // Make sure this is the type of exception we thought it 110 | // was. If "cannot use .at() with array" exception or "key not 111 | // found" 112 | if (304 == exception.id || 403 == exception.id) 113 | { 114 | GILES::Internal::Error::Report_Error( 115 | "Could not find category at the current place in " 116 | "the Coefficients with the given name: \"{}\".\n" 117 | "Current place in coefficients:\n{}\n ", 118 | p_head, 119 | p_coefficients.dump(4)); 120 | } 121 | throw; // Re-throw if this is not the expected exception. 122 | } 123 | } 124 | } 125 | 126 | //! @brief Retrieves a value from the Coefficients. This is mostly a wrapper 127 | //! function around the other get_value function that exists to simplify 128 | //! exception handling. 129 | //! @tparam T_return The return type. 130 | //! @tparam T_categories The type of the names of the sub categories. This 131 | //! is only a template in order to be variadic; this is enforced as a string 132 | //! or something that can be static_cast into a string. 133 | //! @param p_categories This is a variadic parameter where each value 134 | //! represents a sub level within the Coefficients. 135 | //! @returns The value at the end of all the sub levels as the type given by 136 | //! T_return. 137 | //! @exception std::invalid_argument If the resulting value cannot be cast 138 | //! to the chosen return type, this exception is thrown. 139 | //! @exception nlohmann::json::out_of_range This is thrown when any of the 140 | //! sub categories given by p_categories is not found. 141 | //! @see https://en.cppreference.com/w/cpp/language/fold 142 | template 143 | T_return get_value(const T_categories&... p_categories) const 144 | { 145 | return get_value(m_coefficients, p_categories...); 146 | } 147 | 148 | //! @brief This is a helper function that does nothing other than lookup 149 | //! the instruction category of the instruction given by p_opcode, and 150 | //! pass the results onto the get_value function. 151 | //! @param p_opcode The opcode of the instruction to lookup the category 152 | //! for. 153 | //! @param p_categories This is a variadic parameter where each value 154 | //! represents a sub level within the Coefficients. 155 | //! @tparam T_return The return type. 156 | //! @tparam T_categories The type of the names of the sub categories. 157 | //! This is only a template in order to be variadic; this is enforced as 158 | //! a string or something that can be static_cast into a string. 159 | //! @returns The value at the end of all the sub levels as the type 160 | //! given by T_return. 161 | template 162 | T_return get_value_opcode(const std::string& p_opcode, 163 | const T_categories&... p_categories) const 164 | { 165 | return get_value(Get_Instruction_Category(p_opcode), 166 | p_categories...); 167 | } 168 | 169 | //! @todo Change to be style of get_value_opcode comment 170 | //! @brief Retrieves an individual coefficient value by name, under the 171 | //! instruction category that contains the instruction given by 172 | //! p_opcode. p_categories is a variadic parameter that represents a 173 | //! list of sub categories within the instruction category to retrieve 174 | //! from. 175 | //! @tparam T_return The return type. 176 | //! @tparam T_categories The type of the names of the sub categories. 177 | //! This is only a template in order to be variadic; this is enforced as 178 | //! a string or something that can be static_cast into a string. 179 | //! @param p_opcode The opcode of the instruction that the Coefficients 180 | //! are required for. 181 | //! @param p_categories This is a variadic parameter where each value 182 | //! represents a sub level within the Coefficients. 183 | //! @returns The value at the end of all the sub levels as the type 184 | //! given by T_return. 185 | template 186 | T_return get_coefficient(const std::string& p_opcode, 187 | const T_categories&... p_categories) const 188 | { 189 | return get_value_opcode( 190 | p_opcode, "Coefficients", p_categories...); 191 | } 192 | 193 | public: 194 | //! @brief Constructors an instance from the json as loaded from the 195 | //! Coefficients file. 196 | //! @param p_coefficients The validated coefficients, contained within a 197 | //! json object, as they are stored in the file. 198 | //! @warning Validation of the json p_coefficients should have already 199 | //! occurred, using the Validator_Coefficients class, before calling the 200 | //! constructor. 201 | explicit Coefficients(const nlohmann::json& p_coefficients) 202 | : m_coefficients(p_coefficients) 203 | { 204 | } 205 | 206 | const std::string& 207 | Get_Instruction_Category(const std::string& p_opcode) const; 208 | 209 | const std::unordered_set Get_Interaction_Terms() const; 210 | 211 | const std::vector 212 | Get_Coefficients(const std::string& p_opcode, 213 | const std::string& p_interaction_term) const; 214 | 215 | //! @brief Retrieves an individual coefficient value by name, under the 216 | //! instruction category that contains the instruction given by 217 | //! p_opcode. p_categories is a variadic parameter that represents a 218 | //! list of sub categories within the instruction category to retrieve 219 | //! from. 220 | //! @tparam T_categories The type of the names of the sub categories. 221 | //! This is only a template in order to be variadic; this is enforced as 222 | //! a string or something that can be static_cast into a string. 223 | //! @param p_opcode The opcode of the instruction that the Coefficients 224 | //! are required for. 225 | //! @param p_categories This is a variadic parameter where each value 226 | //! represents a sub level within the Coefficients. 227 | //! @returns The value at the end of all the sub levels as type double. 228 | template 229 | double Get_Coefficient(const std::string& p_opcode, 230 | const T_categories&... p_categories) const 231 | { 232 | return get_coefficient(p_opcode, p_categories...); 233 | } 234 | 235 | double Get_Constant(const std::string& p_opcode) const; 236 | }; 237 | } // namespace Internal 238 | } // namespace GILES 239 | 240 | #endif 241 | -------------------------------------------------------------------------------- /src/Error.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Error.hpp 20 | @brief This file contains a custom error handler. 21 | @author Scott Egerton 22 | @date 2017-2019 23 | @copyright GNU Affero General Public License Version 3+ 24 | */ 25 | 26 | #ifndef ERROR_HPP 27 | #define ERROR_HPP 28 | 29 | #include // for exit, EXIT_FAILURE 30 | 31 | #include // for print, vprint, make_format_args. 32 | 33 | namespace GILES 34 | { 35 | namespace Internal 36 | { 37 | //! @class IO 38 | //! @brief This contains all Input and Output functions for GILES. This includes 39 | //! loading the Coefficients file and saving generated Traces. 40 | struct Error 41 | { 42 | private: 43 | //! @brief Prints a formatted error message followed by a newline. 44 | //! @param p_format The format string to be printed. 45 | //! @param p_args The arguments to be printed in the format string. 46 | static void vreport(const char* p_format, fmt::format_args p_args) 47 | { 48 | fmt::vprint(p_format, p_args); 49 | fmt::print("\n"); 50 | } 51 | 52 | //! @brief Prints formatted message and stops execution. 53 | //! @note This function is marked as noreturn as it is guaranteed to always 54 | //! halt the program. (Through std::exit()) 55 | //! @param p_format The format string to be printed. 56 | //! @param p_args The arguments to be printed in the format string. 57 | [[noreturn]] static void vreport_exit(const char* p_format, 58 | fmt::format_args p_args) 59 | { 60 | vreport(p_format, p_args); 61 | std::exit(EXIT_FAILURE); 62 | } 63 | 64 | //! @brief Prints a new line followed by: "Error: ", followed by a formatted 65 | //! error message and stops execution. 66 | //! @note This function is marked as noreturn as it is guaranteed to always 67 | //! halt the program. (Through std::exit()) 68 | //! @param p_format The format string to be printed. 69 | //! @param p_args The arguments to be printed in the format string. 70 | [[noreturn]] static void vreport_error(const char* p_format, 71 | fmt::format_args p_args) 72 | { 73 | fmt::print("\nError: "); 74 | vreport_exit(p_format, p_args); 75 | } 76 | 77 | //! @brief Prints a new line followed by: "Warning: ", followed by a 78 | //! formatted error message. 79 | //! @param p_format The format string to be printed. 80 | //! @param p_args The arguments to be printed in the format string. 81 | static void vreport_warning(const char* p_format, fmt::format_args p_args) 82 | { 83 | fmt::print("\nWarning: "); 84 | vreport(p_format, p_args); 85 | } 86 | 87 | public: 88 | //! @brief Prints "Error: " followed by a formatted error message and stops 89 | //! execution. 90 | //! @note This function is marked as noreturn as it is guaranteed to always 91 | //! halt the program. (Through std::exit()) 92 | //! @param p_format The format string to be printed. 93 | //! @param p_args The arguments to be printed in the format string.: 94 | template 95 | [[noreturn]] static constexpr void Report_Error(const char* p_format, 96 | const Args&... p_args) 97 | { 98 | vreport_error(p_format, fmt::make_format_args(p_args...)); 99 | } 100 | 101 | //! @brief Prints formatted message and stops execution. 102 | //! @note This function is marked as noreturn as it is guaranteed to always 103 | //! halt the program. (Through std::exit()) 104 | //! @param p_format The format string to be printed. 105 | //! @param p_args The arguments to be printed in the format string. 106 | template 107 | [[noreturn]] static constexpr void Report_Exit(const char* p_format, 108 | const Args&... p_args) 109 | { 110 | vreport_exit(p_format, fmt::make_format_args(p_args...)); 111 | } 112 | 113 | //! @brief Prints "Warning: " followed by a formatted message. 114 | //! @param p_format The format string to be printed. 115 | //! @param p_args The arguments to be printed in the format string. 116 | template 117 | static constexpr void Report_Warning(const char* p_format, 118 | const Args&... p_args) 119 | { 120 | vreport_warning(p_format, fmt::make_format_args(p_args...)); 121 | } 122 | }; 123 | } // namespace Internal 124 | } // namespace GILES 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /src/Factory/Abstract_Factory.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Abstract_Factory.hpp 20 | @brief Contains the Abstract_Factory class; a factory class for 21 | initialisation of objects. 22 | @author Scott Egerton 23 | @date 2017-2019 24 | @copyright GNU Affero General Public License Version 3+ 25 | */ 26 | 27 | #ifndef ABSTRACT_FACTORY_HPP 28 | #define ABSTRACT_FACTORY_HPP 29 | 30 | #include // for unique_ptr 31 | #include // for invalid_argument 32 | #include // for string 33 | #include // for unordered_map 34 | 35 | #include "Error.hpp" // for Report_Error 36 | 37 | namespace GILES 38 | { 39 | namespace Internal 40 | { 41 | // Forward Declarations 42 | // These are need to instantiate the templates at the bottom of the file. 43 | class Coefficients; 44 | class Emulator; 45 | class Execution; 46 | class Model; 47 | 48 | //! @class Abstract_Factory 49 | //! @brief This is a static factory class that assists in the construction of 50 | //! objects. By providing abstraction for the caller, it hides the exact type of 51 | //! the object from the caller and allows the caller to make use of the object 52 | //! through the Base class interface regardless of the derived type. 53 | //! @note The exact classes that this can construct are not stored here and are 54 | //! added at runtime using self-registering techniques. This simplifies the 55 | //! process of adding and removing classes and allows objects to be selectively 56 | //! compiled as a way to completely remove those as options. This is also a 57 | //! template class allowing it to construct any object and not just those of a 58 | //! fixed type. 59 | //! @see https://en.wikipedia.org/wiki/Factory_method_pattern 60 | //! @see https://www.bfilipek.com/2018/02/factory-selfregister.html 61 | template class Abstract_Factory 62 | { 63 | public: 64 | //! A function pointer used to point to the function that calls the 65 | //! constructor for objects in the factory. 66 | using Create_Function = std::unique_ptr (*)(args_t...); 67 | 68 | //! @brief Retrieves an object's constructor from the factory by name. 69 | //! If an object with the given name is not found then an error message will 70 | //! be reported and execution will halt. 71 | //! @param p_type The name of the object to be retrieved. 72 | //! @returns A function pointer, pointing at the constructor of the class 73 | //! corresponding to the name given by p_type. 74 | static Create_Function Find(const std::string& p_type) 75 | { 76 | // If p_type is registered. 77 | if (auto& all = Get_All(); all.end() != all.find(p_type)) 78 | { 79 | // Construct and return an instance of p_type. 80 | return all[p_type]; 81 | } 82 | Error::Report_Error("Could not find '{}'.\n", p_type); 83 | } 84 | 85 | //! @brief This function assists with the initialisation of the objects in 86 | //! the factory. This will be passed the parameters to be passed on to the 87 | //! constructor. It will selectively construct an object based on the 88 | //! first parameter, p_type and return a unique pointer to it. 89 | //! @param p_type The type of the object to be constructed as a 90 | //! string. 91 | //! @param p_execution The Execution as received from the emulator. 92 | //! @param p_coefficients The Coefficients as loaded from the 93 | //! coefficients file. 94 | //! @returns A unique pointer to the constructed object. The type of this 95 | //! is to the base class, given by the template Base, allowing the caller to 96 | //! ignore the actual type of the object and make use of the Base class 97 | //! interface. 98 | static std::unique_ptr Construct(const std::string& p_type, 99 | args_t... p_args) 100 | { 101 | return Find(p_type)(p_args...); 102 | } 103 | 104 | //! @brief This registers classes in the list available to the factory, 105 | //! allowing the factory to create an instance of anything within the list. 106 | //! This is needed to that classes can self register meaning that the list 107 | //! of classes available does not need to be hard coded. 108 | //! @see https://www.bfilipek.com/2018/02/factory-selfregister.html 109 | //! @param p_type A string representing the type of the class being 110 | //! registered. This is used to identify classes. 111 | //! @param p_create_function A pointer to a function that will return a 112 | //! constructed instance of the class. 113 | //! @returns A bool indicating whether or not the class given by p_type was 114 | //! already registered. 115 | static bool Register(const std::string& p_type, 116 | const Create_Function& p_constructor) 117 | { 118 | // Don't register if this is already registered. 119 | if (auto& all = Get_All(); all.end() == all.find(p_type)) 120 | { 121 | all[p_type] = p_constructor; 122 | return true; 123 | } 124 | return false; 125 | } 126 | 127 | //! @brief Retrieves a list of all of the classes that have been compiled 128 | //! and whether or not they are enabled. TODO: Make the code match this 129 | //! brief. 130 | //! @returns An unordered_map, indexed by the name of the class, containing 131 | //! boolean values indicating as to whether that class is enabled by 132 | //! default. TODO: Change this 133 | //! @note This is a function wrapper around a static object using the 134 | //! "Construct members on first use idiom". This is needed to guarantee that 135 | //! the unordered_map is initialised whilst the factory contents are 136 | //! registering themselves. This is a work around for the well known static 137 | //! initialisation order fiasco. 138 | //! @see https://isocpp.org/wiki/faq/ctors#static-init-order 139 | //! @see 140 | //! https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use-members 141 | static std::unordered_map& Get_All() 142 | { 143 | static std::unordered_map 145 | map; // TODO: Rename 146 | return map; 147 | } 148 | 149 | //! @brief This has been deleted to ensure the constructor and the copy 150 | //! constructor cannot be called as this is just a utility class containing 151 | //! nothing but static functions. 152 | //! @see https://en.cppreference.com/w/cpp/language/rule_of_three 153 | //! @see https://en.cppreference.com/w/cpp/language/copy_constructor 154 | Abstract_Factory(const Abstract_Factory&) = delete; 155 | 156 | //! @brief This has been deleted to ensure the copy 157 | //! assignment operator cannot be called as this is just a utility class 158 | //! containing nothing but static functions. 159 | //! @see https://en.cppreference.com/w/cpp/language/rule_of_three 160 | //! @see https://en.cppreference.com/w/cpp/language/copy_assignment 161 | Abstract_Factory& operator=(const Abstract_Factory&) = delete; 162 | }; 163 | 164 | //! @brief This exists only to simply the usage of the Abstract_Factory 165 | //! class. By providing an intermediate, the possibility of accidentally 166 | //! initialising a separate template is eliminated. Additionally, this 167 | //! provides for a more meaningful name. To see what is actually going on behind 168 | //! the scenes, refer to the Abstract_Factory class. 169 | using Model_Factory = 170 | Abstract_Factory; 171 | 172 | //! @brief This exists only to simply the usage of the Abstract_Factory 173 | //! class. By providing an intermediate, the possibility of accidentally 174 | //! initialising a separate template is eliminated. Additionally, this 175 | //! provides for a more meaningful name. To see what is actually going on behind 176 | //! the scenes, refer to the Abstract_Factory class. 177 | using Emulator_Factory = Abstract_Factory; 178 | 179 | } // namespace Internal 180 | } // namespace GILES 181 | 182 | #endif 183 | -------------------------------------------------------------------------------- /src/Factory/Abstract_Factory_Register.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @todo Change this 20 | @file Abstract_Factory_Register.hpp 21 | @brief This file contains the Abstract_Factory_Register class, which is used 22 | to assist with registering classes within the Abstract_Factory class. 23 | @author Scott Egerton 24 | @date 2017-2019 25 | @copyright GNU Affero General Public License Version 3+ 26 | */ 27 | 28 | #ifndef ABSTRACT_FACTORY_REGISTER_HPP 29 | #define ABSTRACT_FACTORY_REGISTER_HPP 30 | 31 | #include // for unique_ptr, make_unique 32 | #include // for string 33 | 34 | #include "Abstract_Factory.hpp" 35 | 36 | namespace GILES 37 | { 38 | namespace Internal 39 | { 40 | // Forward Declarations 41 | // These are need to instantiate the templates at the bottom of the file. 42 | class Model; 43 | class Execution; 44 | class Coefficients; 45 | class Emulator; 46 | 47 | //! @class Abstract_Factory_Register 48 | //! @brief This class is used to assist with the self registration of classes 49 | //! within the factory. 50 | //! The idea is that a class would inherit from this, using itself as the 51 | //! template typename. This will add the bool m_is_registered to it. At run 52 | //! time, m_is_registered will be evaluated due to the fact that it is static. 53 | //! The evaulation of this will call the Register function in the Factory class, 54 | //! registering the type given by T. i.e. The class that derived from this. 55 | //! @see https://www.bfilipek.com/2018/02/factory-selfregister.html 56 | template 57 | class Abstract_Factory_Register 58 | { 59 | private: 60 | //! @brief This calls the constructor of the Derived class. A pointer to 61 | //! this function is passed to the factory class so that it can create 62 | //! instances of the self registering derived classes. 63 | //! @param p_execution The recorded Execution of the simulation of the 64 | //! target program. 65 | //! @param p_coefficients The coefficients as loaded from the Coefficients 66 | //! file. 67 | //! @returns A unique_ptr to an object of the type given by the derived_t 68 | //! template. 69 | static std::unique_ptr create(args_t... p_args) 70 | { 71 | return std::make_unique(p_args...); 72 | } 73 | 74 | //! @brief Retrieves the name of the Derived class. 75 | //! @returns The name as a string. 76 | //! This is needed to ensure self registration in the factory works. As 77 | //! such, this implementation ensures that all classes that wish to self 78 | //! register must provide an implementation for Get_Name() because the 79 | //! factory registration requires this as unique identifier. 80 | //! @note This idiom is known as the curiously recurring template pattern. 81 | //! @see https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern 82 | static const std::string get_name() { return derived_t::Get_Name(); } 83 | 84 | public: // TODO: Should this be protected? 85 | //! This static variable is evaluated before main() is called. The 86 | //! evaluation of this requires the Register function to be called, 87 | //! automatically registering the class defined by the template T in the 88 | //! factory before main() is called. 89 | static bool m_is_registered; 90 | 91 | protected: 92 | //! @brief This has been made protected to ensure the constructor and 93 | //! the copy constructor cannot be called directly as this class is 94 | //! designed to be inherited from and not instantiated directly. 95 | Abstract_Factory_Register() 96 | { 97 | // This statement registers this class in the factory, allowing access 98 | // from elsewhere. Do not delete this or else this class will not appear 99 | // in the factory. If you wish to make this class inaccessible, a better 100 | // method would be to remove the corresponding cpp file from the build 101 | // script. 102 | // This is required to be "used" somewhere in order to prevent 103 | // the compiler from optimising it away, thus preventing self 104 | // registration. 105 | // Section 6.6.4.1, point 2 of the linked document states that this 106 | // statement will not be optimised away. 107 | // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf 108 | // The void cast does nothing functionally but prevents the compiler 109 | // warning about an unused result. 110 | (void)derived_t::m_is_registered; 111 | } 112 | 113 | //! @brief Virtual destructor to ensure proper memory cleanup. 114 | //! @see https://stackoverflow.com/a/461224 115 | virtual ~Abstract_Factory_Register() = 116 | default; // TODO: Should this = default? Rule of 117 | // ZERO? http://en.cppreference.com/w/cpp/language/rule_of_three 118 | }; 119 | 120 | //! @todo Does this inherit the doxygen comments from m_is_registered? - if not, 121 | //! add doxygen comments. 122 | //! @todo Add comment explaining why this is outside the class. 123 | template 124 | bool Abstract_Factory_Register::m_is_registered{ 125 | Abstract_Factory::Register(get_name(), create)}; 126 | 127 | //! @brief This exists only to simply the usage of the 128 | //! Abstract_Factory_Register class. By providing an intermediate, the 129 | //! possibility of accidentally initialising a separate template is 130 | //! eliminated. To see what is actually going on behind the scenes, refer to the 131 | //! Abstract_Factory_Register class. 132 | template 133 | using Model_Factory_Register = Abstract_Factory_Register; 137 | 138 | //! @brief This exists only to simply the usage of the 139 | //! Abstract_Factory_Register class. By providing an intermediate, the 140 | //! possibility of accidentally initialising a separate template is 141 | //! eliminated. To see what is actually going on behind the scenes, refer to the 142 | //! Abstract_Factory_Register class. 143 | template 144 | using Emulator_Factory_Register = 145 | Abstract_Factory_Register; 146 | } // namespace Internal 147 | } // namespace GILES 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /src/GILES.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file GILES.cpp 20 | @brief This file contains the entry point for GILES and invokes other 21 | operations. 22 | @author Scott Egerton 23 | @date 2017-2019 24 | @copyright GNU Affero General Public License Version 3+ 25 | */ 26 | 27 | #include // for make_unique, unique_ptr 28 | #include // for optional 29 | #include // for string 30 | #include // for unordered_map 31 | #include // for unordered_set 32 | #include // for pair, move 33 | 34 | #include 35 | #include // for print 36 | 37 | #include "Abstract_Factory.hpp" // for Emulator_Factory, Model_Factory 38 | #include "Coefficients.hpp" // for Coefficients 39 | #include "Emulator.hpp" // for Emulator 40 | #include "Error.hpp" // for Report_Error 41 | #include "Execution.hpp" // for Execution 42 | #include "IO.hpp" // for IO 43 | #include "Model.hpp" // for Model 44 | 45 | namespace GILES 46 | { 47 | //! @class GILES 48 | //! @brief This contains the operations that control the rest of the program 49 | //! passing data between them. 50 | class GILES 51 | { 52 | private: 53 | const Internal::Coefficients m_coefficients; 54 | const std::string m_program_path; 55 | const std::string m_model_name; 56 | const std::string m_simulator_name; 57 | const std::optional& m_traces_path; 58 | const std::uint32_t m_number_of_runs; 59 | 60 | // A timeout to stop execution after a set number of cycles. 61 | std::optional m_timeout; 62 | 63 | // These options are related to fault injection. 64 | bool m_fault; 65 | std::uint32_t m_fault_cycle; 66 | std::string m_fault_register; 67 | std::uint8_t m_fault_bit; 68 | 69 | // Future: This data is stored here as well as in Traces_Serialiser as it 70 | // should be able to be accessed programmatically in the future. 71 | // TODO: Add getter. 72 | std::vector> m_traces; 73 | std::vector m_extra_data; 74 | 75 | Traces_Serialiser::Serialiser m_serialiser; 76 | 77 | // TODO: Future: This has been left in as it will be used in future versions 78 | // when running multiple models at once is supported. 79 | //! @todo Optimise this using std methods. Can be reduced down to 80 | //! std::remove_if or something similar. 81 | //! @todo This is not needed. Using a lazy approach we can only check the 82 | //! constructed model. 83 | //! @todo maybe move to Model_Factory.hpp 84 | /*const std::unordered_set get_models_in_use() 85 | { 86 | std::unordered_set models_in_use; 87 | // Create a list of models to use from a list of all models compiled 88 | for (const auto& model : GILES::Internal::Model_Factory::Get_All()) 89 | { 90 | std::cout << "Found Model: " << model.first << std::endl; 91 | // if this model is enabled. 92 | tor_TE 93 | if (model.second) // TODO: model.second is currently a function 94 | // pointer to the constructor, not is_enabled 95 | // bool. 96 | { 97 | // Add it to the list of models in use. 98 | models_in_use.insert(model.first); 99 | //} 100 | } 101 | return models_in_use; 102 | }*/ 103 | 104 | //! @brief Prints a warning if the target program does not run in a constant 105 | //! number of clock cycles each time it is executed. 106 | //! @returns true if a warning was printed, false if not. 107 | //! @param p_trace_index The index of the current trace to have its size 108 | //! checked. 109 | //! @see https://en.wikipedia.org/wiki/Clock_cycle 110 | //! @todo: Future: This should only be checked if TRS files are being used. 111 | bool warn_if_not_constant_time() const 112 | { 113 | const auto current_size = m_traces.back().size(); 114 | static const auto first_size = m_traces.front().size(); 115 | 116 | // If there is no size difference then return false. 117 | if (first_size == current_size) 118 | { 119 | return false; 120 | } 121 | 122 | Internal::Error::Report_Warning( 123 | "The target program did not run in a constant number of cycles.\n" 124 | "If this was not an intentional countermeasure to timing attacks " 125 | "then this is considered insecure.\n" 126 | "Trace number 0 took {} clock cycles.\n" 127 | "Trace number {} took {} clock cycles.\n", 128 | first_size, 129 | m_traces.size() - 1, // Trace index 130 | current_size); 131 | return true; 132 | } 133 | 134 | //! @brief Prints a warning it traces will not be saved after the program 135 | //! stops. 136 | //! This is to prevent long running operations resulting in no output 137 | //! accidentally. 138 | void warn_if_not_saving() const 139 | { 140 | // If no path has been specified to save traces to. 141 | if (!m_traces_path) 142 | { 143 | Internal::Error::Report_Warning( 144 | "Trace(s) will not be saved to disk"); 145 | } 146 | } 147 | 148 | public: 149 | // TODO: Separate out some of the functionality in here into an API 150 | //! @brief The main entry point to the GILES library. This controls the 151 | //! running of GILES and invokes other components. 152 | //! @param p_program_path The path to the target executable to be ran in 153 | //! the emulator. 154 | //! @param p_coefficients_path The path to the Coefficients file. 155 | //! @param p_traces_path The path to save the Traces to. This is an 156 | //! optional parameter and omitting it will cause the traces to not be 157 | //! saved to a file. 158 | GILES(const std::string& p_program_path, 159 | const std::string& p_coefficients_path, 160 | const std::optional& p_traces_path, 161 | const std::uint32_t p_number_of_runs, 162 | const std::string& p_model_name = 163 | "Hamming Weight") // TODO: Set the default using cmake 164 | // configuring a static var in an external 165 | // file. 166 | : m_coefficients{Internal::IO().Load_Coefficients(p_coefficients_path)}, 167 | m_program_path{p_program_path}, m_model_name{std::move(p_model_name)}, 168 | m_traces_path{p_traces_path}, 169 | m_number_of_runs{p_number_of_runs}, m_fault{false}, m_serialiser{} 170 | { 171 | // Check the supplied model name is valid 172 | Internal::Model_Factory::Find(p_model_name); 173 | } 174 | 175 | //! @todo Document 176 | void Run() 177 | { 178 | warn_if_not_saving(); 179 | // Initialise all emulators. 180 | for (const auto& emulator_interface : 181 | Internal::Emulator_Factory::Get_All()) 182 | { 183 | fmt::print("Using simulator: {}\n", emulator_interface.first); 184 | 185 | // Run the emulator and save the results to m_traces. 186 | Run_Simulator(emulator_interface.first); 187 | 188 | // If a path was provided then save. 189 | if (m_traces_path) 190 | { 191 | // Save to file. 192 | m_serialiser.Save(m_traces_path.value()); 193 | } 194 | } 195 | } 196 | 197 | void Inject_Fault(const std::uint32_t p_cycle_to_fault, 198 | const std::string& p_register_to_fault, 199 | const std::uint8_t p_bit_to_fault) 200 | { 201 | m_fault = true; 202 | m_fault_cycle = p_cycle_to_fault; 203 | m_fault_register = p_register_to_fault; 204 | m_fault_bit = p_bit_to_fault; 205 | } 206 | 207 | void Set_Timeout(const std::uint32_t p_number_of_cycles) 208 | { 209 | m_timeout = p_number_of_cycles; 210 | } 211 | 212 | //! @brief Runs the simulator given by p_simulator_name and TODO: 213 | decltype(m_traces) Run_Simulator(const std::string& p_simulator_name) 214 | { 215 | fmt::print("Using model: {}\n", m_model_name); 216 | 217 | // Ensures that the constant time warning is not printed over and over. 218 | bool warning_printed{false}; 219 | 220 | // Used to indicate progress to the user. 'i' is not used as it is not 221 | // thread safe. This is. 222 | uint32_t steps_completed{0}; 223 | 224 | fmt::print("Starting... (0.0%)\n"); 225 | 226 | #pragma omp parallel for 227 | for (std::size_t i = 0; i < m_number_of_runs; ++i) 228 | { 229 | // Construct the simulator, ready for use. 230 | const auto simulator = Internal::Emulator_Factory::Construct( 231 | p_simulator_name, m_program_path); 232 | 233 | if (m_timeout) 234 | { 235 | simulator->Add_Timeout(m_timeout.value()); 236 | } 237 | 238 | if (m_fault) 239 | { 240 | simulator->Inject_Fault( 241 | m_fault_cycle, m_fault_register, m_fault_bit); 242 | } 243 | 244 | const auto execution = simulator->Run_Code(); 245 | 246 | // Any extra data to be included in the trace. 247 | const auto extra_data = simulator->Get_Extra_Data(); 248 | 249 | // Initialise all models. 250 | // TODO: Future: Add support for using multiple models at once using 251 | // this code. 252 | /*for (const auto& model_interface : 253 | GILES::Internal::Model_Factory::Get_All()) 254 | { 255 | 256 | // Construct the model, ready for use. 257 | const auto model = GILES::Internal::Model_Factory::Construct( 258 | model_interface.first, execution, m_coefficients);*/ 259 | 260 | // Construct the model, ready for use. 261 | const auto model = Internal::Model_Factory::Construct( 262 | m_model_name, execution, m_coefficients); 263 | 264 | // If this is not the first trace gathered then ensure that all 265 | // traces are the same length (Meaning the target algorithm runs 266 | // in constant time). This is a requirement for using the TRS 267 | // trace format. 268 | const auto trace = model->Generate_Traces(); 269 | 270 | // Increment the counter of number of traces generated. 271 | #pragma omp atomic 272 | ++steps_completed; 273 | 274 | // This is marked critical to ensure everything gets added and 275 | // locks are automatically handled. 276 | #pragma omp critical 277 | { 278 | // Add the generated trace to the list of traces. 279 | m_traces.emplace_back(trace); 280 | 281 | // Add any extra information given by the simulator to the 282 | // traces. 283 | m_extra_data.emplace_back(extra_data); 284 | 285 | m_serialiser.Add_Trace(trace, extra_data); 286 | 287 | // If this warning hasn't been printed before. 288 | if (!warning_printed) 289 | { 290 | // Will print a warning if the target program is not 291 | // constant time. 292 | warning_printed = warn_if_not_constant_time(); 293 | } 294 | } 295 | 296 | fmt::print("\rGenerated: {} of {} traces. ({}%)", 297 | steps_completed, 298 | m_number_of_runs, 299 | 100.0 * steps_completed / m_number_of_runs); 300 | //} 301 | } 302 | fmt::print("\nDone!\n"); 303 | return m_traces; 304 | } 305 | }; 306 | } // namespace GILES 307 | -------------------------------------------------------------------------------- /src/IO.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file IO.cpp 20 | @brief This file contains all input and output functions for GILES. 21 | @author Scott Egerton 22 | @date 2017-2019 23 | @copyright GNU Affero General Public License Version 3+ 24 | */ 25 | 26 | #include "IO.hpp" 27 | 28 | #include // for exit, EXIT_FAILURE 29 | #include // for ifstream 30 | #include // for invalid_argument 31 | 32 | #include // for json, basic_json<>::exception 33 | 34 | #include "Coefficients.hpp" // for Coefficients 35 | #include "Error.hpp" // for Report_Error 36 | #include "Validator_Coefficients.hpp" // for Validator_Coefficients 37 | 38 | namespace GILES 39 | { 40 | namespace Internal 41 | { 42 | //! @brief Loads the Coefficients from a file as specified by 43 | //! p_coefficients_path. 44 | //! @param p_coefficients_path The path where the Coefficients should be 45 | //! loaded from. 46 | //! @returns The Coefficients using the internal representation. 47 | const GILES::Internal::Coefficients GILES::Internal::IO::Load_Coefficients( 48 | const std::string& p_coefficients_path) const 49 | { 50 | // read the Coefficients file into a JSON object 51 | std::ifstream file{p_coefficients_path}; 52 | 53 | nlohmann::json json; 54 | 55 | // If the file doesn't exist then don't validate it. 56 | if (file.is_open()) 57 | { 58 | // Ensure the file contains valid JSON 59 | try 60 | { 61 | json = nlohmann::json::parse(file); 62 | } 63 | catch (nlohmann::detail::parse_error&) 64 | { 65 | // Do nothing as the model may not need any Coefficients. 66 | // If the model does need Coefficients then it will throw it's own 67 | // error. 68 | GILES::Internal::Error::Report_Error( 69 | "Coefficients file '{}' is not a valid JSON file", 70 | p_coefficients_path); 71 | } 72 | 73 | // This will throw an exception if validation fails. 74 | GILES::Internal::Validator_Coefficients::Validate_Json(json); 75 | } 76 | return GILES::Internal::Coefficients{json}; 77 | } 78 | } // namespace Internal 79 | } // namespace GILES 80 | -------------------------------------------------------------------------------- /src/IO.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file IO.hpp 20 | @brief This file contains all input and output functions for GILES. 21 | @author Scott Egerton 22 | @date 2017-2019 23 | @copyright GNU Affero General Public License Version 3+ 24 | */ 25 | 26 | #ifndef IO_HPP 27 | #define IO_HPP 28 | 29 | #include // for string 30 | 31 | #include "Coefficients.hpp" // for Coefficients 32 | 33 | namespace GILES 34 | { 35 | namespace Internal 36 | { 37 | //! @class IO 38 | //! @brief This contains all Input and Output functions for GILES. This includes 39 | //! loading the Coefficients file. 40 | struct IO 41 | { 42 | const GILES::Internal::Coefficients 43 | Load_Coefficients(const std::string& p_coefficients_path) const; 44 | }; 45 | } // namespace Internal 46 | } // namespace GILES 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/Main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Main.cpp 20 | @brief This file contains a command line entry executable that invokes GILES 21 | with the correct options. 22 | @author Scott Egerton 23 | @date 2017-2019 24 | @copyright GNU Affero General Public License Version 3+ 25 | */ 26 | 27 | #include // for move 28 | #include // for exit, EXIT_SUCCESS 29 | #include // for __shared_ptr_access 30 | #include // for optional 31 | #include // for invalid_argument 32 | #include // for string, operator<< 33 | #include // for vector 34 | 35 | #include // for options_description, value... 36 | #include // for format 37 | #include // for operator<< 38 | 39 | #include "Error.hpp" // for Report_Exit 40 | #include "GILES.cpp" // for GILES 41 | 42 | //! Anonymous namespace is used as this functionality is only required when 43 | //! building not as a library. 44 | namespace 45 | { 46 | // TODO: Put this all in a class? - Probably should 47 | std::string m_program_path; 48 | std::string m_coefficients_path; 49 | std::string m_model_name; 50 | std::string m_simulator_name; 51 | std::optional m_traces_path; 52 | std::uint32_t m_number_of_runs; 53 | 54 | // These options are related to fault injection. 55 | bool m_fault{false}; 56 | std::uint32_t m_fault_cycle; 57 | std::string m_fault_register; 58 | std::uint8_t m_fault_bit; 59 | 60 | std::optional m_timeout; 61 | 62 | //! @brief Prints an error message and exits. This is to be called when the 63 | //! program cannot run given the supplied command line arguments. 64 | //! @note This function is marked as noreturn as it is guaranteed to always 65 | //! halt the program. (Through std::exit()) 66 | //! @param p_message An error message can optionally be provided. This will 67 | //! be printed first on a separate line if provided. 68 | template 69 | [[noreturn]] void bad_options(const args_t&... p_message) { 70 | fmt::print(p_message...); 71 | GILES::Internal::Error::Report_Exit( 72 | "\nPlease use option --help or -h to see proper usage"); 73 | } 74 | 75 | //! @brief Interprets the command line flags. 76 | //! @param p_options The options as contained within a string. 77 | // TODO: Returns tag? 78 | void parse_command_line_flags(int argc, char* argv[]) 79 | { 80 | boost::program_options::options_description options_description{fmt::format( 81 | "General instruction leakage simulator\n" 82 | "Usage: {} [--input] EXECUTABLE [--coefficients] COEFFICIENTS\n", 83 | argv[0])}; 84 | 85 | std::vector fault_options{}; 86 | 87 | // clang-format off 88 | 89 | // Adds the command line options. 90 | options_description.add_options() 91 | ("help,h", "Print help") 92 | ("runs,r", 93 | boost::program_options::value()->default_value(1), 94 | "Number of traces to generate") 95 | ("coefficients,c", 96 | boost::program_options::value()->default_value( 97 | "./coeffs.json"), 98 | "Coefficients file") 99 | ("input,i", 100 | boost::program_options::value(), 101 | "Executable to be ran in the simulator") 102 | ("output,o", 103 | boost::program_options::value(), 104 | "Generated traces output file") 105 | ("simulator,s", 106 | boost::program_options::value()->default_value( 107 | "Thumb Sim"), 108 | "The name of the simulator that should be used") 109 | ("model,m", 110 | boost::program_options::value()->default_value( 111 | "Hamming Weight"), 112 | "The name of the mathematical model that should be used to " 113 | "generate traces") 114 | ("fault,f", 115 | boost::program_options::value>( 116 | &fault_options) 117 | ->multitoken(), 118 | "Where to inject a fault. e.g. \"--fault 10 R0 2\" is inject a " 119 | "fault " 120 | "before the 10th clock cycle, by flipping the second least " 121 | "significant bit in the register R0") 122 | ("timeout,t", 123 | boost::program_options::value(), 124 | "The number of clock cycles to force stop execution after"); 125 | // clang-format on 126 | 127 | boost::program_options::positional_options_description 128 | positional_options_description; 129 | // Input can be specified without -i/--input flag. 130 | positional_options_description.add("input", 1); 131 | 132 | boost::program_options::variables_map options; 133 | try 134 | { 135 | // Parse the provided arguments. 136 | boost::program_options::store( 137 | boost::program_options::command_line_parser(argc, argv) 138 | .options(options_description) 139 | .positional(positional_options_description) 140 | .run(), 141 | options); 142 | boost::program_options::notify(options); 143 | } 144 | catch (const std::exception& exception) 145 | { 146 | bad_options(exception.what()); 147 | } 148 | 149 | if (options.count("help")) // if help flag is passed 150 | { 151 | fmt::print("{}\n", options_description); 152 | std::exit(EXIT_SUCCESS); 153 | } 154 | 155 | if (options.count("output")) // if output flag is passed 156 | { 157 | m_traces_path = options["output"].as(); 158 | } 159 | 160 | if (options.count("input")) // if input flag is passed 161 | { 162 | m_program_path = options["input"].as(); 163 | } 164 | else 165 | { 166 | bad_options("Input option is required.(-i / --input \"Path to " 167 | "Executable\")"); 168 | } 169 | 170 | if (options.count("output")) // if output flag is passed 171 | { 172 | m_traces_path = options["output"].as(); 173 | } 174 | 175 | // Fault injection options 176 | if (options.count("fault")) 177 | { 178 | try 179 | { 180 | constexpr std::uint8_t number_of_fault_options{3}; 181 | if (const std::size_t size{fault_options.size()}; 182 | size != number_of_fault_options) 183 | { 184 | bad_options("Incorrect number of fault injection options " 185 | "provided.\nExpected: {}\nGot: {}", 186 | number_of_fault_options, 187 | size); 188 | } 189 | m_fault_cycle = std::stoi(fault_options[0]); 190 | m_fault_register = fault_options[1]; 191 | m_fault_bit = std::stoi(fault_options[2]); 192 | } 193 | catch (const std::exception&) 194 | { 195 | bad_options("Fault injection options could not be interpreted"); 196 | } 197 | m_fault = true; 198 | } 199 | 200 | if (options.count("timeout")) 201 | { 202 | m_timeout = options["timeout"].as(); 203 | } 204 | 205 | // default "./coeffs.json" is used if flag is not passed 206 | m_coefficients_path = options["coefficients"].as(); 207 | 208 | // default "Thumb Sim" is used if flag is not passed 209 | m_simulator_name = options["simulator"].as(); 210 | 211 | // default "Hamming Weight" is used if flag is not passed 212 | m_model_name = options["model"].as(); 213 | 214 | // default 1 is used if flag is not passed 215 | // TODO: Remove this default? 216 | m_number_of_runs = options["runs"].as(); 217 | } 218 | } // namespace 219 | 220 | //! @brief The entry point of the program. 221 | int main(int argc, char* argv[]) 222 | { 223 | parse_command_line_flags(argc, argv); 224 | 225 | GILES::GILES giles = GILES::GILES(m_program_path, 226 | m_coefficients_path, 227 | m_traces_path, 228 | m_number_of_runs, 229 | m_model_name); 230 | 231 | // If fault inject options are provided then send them to GILES, 232 | if (m_fault) 233 | { 234 | giles.Inject_Fault(m_fault_cycle, m_fault_register, m_fault_bit); 235 | } 236 | 237 | // If the timeout option is provided then send it to GILES, 238 | if (m_timeout) 239 | { 240 | giles.Set_Timeout(m_timeout.value()); 241 | } 242 | 243 | giles.Run(); 244 | return 0; 245 | } 246 | -------------------------------------------------------------------------------- /src/Models/Hamming_Weight/Model_Hamming_Weight.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @todo Change this 20 | @file Model_Hamming_Weight.hpp 21 | @brief This file is a template. This can be used as a base for implementing 22 | a mathematical model for generating traces of a given target program. 23 | @author Scott Egerton 24 | @date 2017-2019 25 | @copyright GNU Affero General Public License Version 3+ 26 | */ 27 | 28 | #include // for uint8_t, size_t 29 | #include // for vector 30 | 31 | #include "Model_Hamming_Weight.hpp" 32 | 33 | #include "Assembly_Instruction.hpp" // for Assembly_Instruction 34 | #include "Execution.hpp" // for Execution 35 | 36 | //! The list of interaction terms used by this model in order to generate 37 | //! traces. 38 | const std::unordered_set 39 | GILES::Internal::Model_Hamming_Weight::m_required_interaction_terms{}; 40 | 41 | //! @brief This function contains the mathematical calculations that generate 42 | //! the Traces. 43 | //! @returns The generated Traces for the target program. 44 | const std::vector 45 | GILES::Internal::Model_Hamming_Weight::Generate_Traces() 46 | { 47 | std::vector traces; 48 | 49 | const std::size_t number_of_cycles{m_execution.Get_Cycle_Count()}; 50 | for (std::size_t i{0}; i < number_of_cycles; ++i) 51 | { 52 | // Prevents trying to calculate the hamming weight of stalls and 53 | // flushes. 54 | if (!m_execution.Is_Normal_State(i, "Execute")) 55 | { 56 | // In the case of stalls and flushes just assume these use no power 57 | // for now. 58 | traces.push_back(0); 59 | continue; 60 | } 61 | 62 | // Calculates the Hamming weight of the first operand of the instruction 63 | // at clock cycle 'i' and appends it to the traces object. 64 | traces.push_back( 65 | Model_Math::Hamming_Weight(m_execution.Get_Operand_Value( 66 | i, m_execution.Get_Instruction(i, "Execute"), 1))); 67 | } 68 | return traces; 69 | } 70 | -------------------------------------------------------------------------------- /src/Models/Hamming_Weight/Model_Hamming_Weight.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @todo Change this 20 | @file Model_Hamming_Weight.hpp 21 | @brief This file is a template. This can be used as a base for implementing 22 | a mathematical model for generating traces of a given target program. 23 | @note When implementing a model there is no need to change much in this 24 | file. Only the word "Template" needs to be changed in various places as 25 | well as the comments. The code that needs to be changed is mainly contained 26 | to the corresponding .cpp file. 27 | @author Scott Egerton 28 | @date 2017-2019 29 | @copyright GNU Affero General Public License Version 3+ 30 | */ 31 | 32 | #ifndef MODEL_HAMMING_WEIGHT_HPP 33 | #define MODEL_HAMMING_WEIGHT_HPP 34 | 35 | #include // for size_t 36 | #include // for string 37 | #include // for unordered_set 38 | #include // for vector 39 | 40 | #include "Model.hpp" // for Model_Interface, Hamming_Weight 41 | 42 | namespace GILES 43 | { 44 | namespace Internal 45 | { 46 | // Forward Declarations 47 | class Coefficients; 48 | class Execution; 49 | 50 | //! @class Model_Hamming_Weight 51 | //! @brief This derived class contains a specific implementation of a 52 | //! mathematical model to calculate the traces for a target program. It is 53 | //! designed as a template allowing new models to be added with ease. 54 | //! Deriving from Model_Factory_Register as well will automatically register 55 | //! this class within the factory class. 56 | class Model_Hamming_Weight 57 | : public virtual Model_Interface 58 | { 59 | private: 60 | static const std::unordered_set m_required_interaction_terms; 61 | 62 | public: 63 | //! @brief The constructor makes use of the base Model constructor to assist 64 | //! with initialisation of private member variables. 65 | Model_Hamming_Weight(const Execution& p_execution, 66 | const Coefficients& p_coefficients) 67 | : Model_Interface(p_execution, p_coefficients) 68 | { 69 | } 70 | 71 | const std::vector Generate_Traces() override; 72 | 73 | //! @brief Retrieves a list of the interaction terms that are used within 74 | //! the model. These must be provided by the Coefficients in order for 75 | //! the model to function. 76 | //! @returns The list of interaction terms used within the model. 77 | static const std::unordered_set& Get_Interaction_Terms() 78 | { 79 | return m_required_interaction_terms; 80 | } 81 | 82 | //! @brief Retrieves the name of this Model. 83 | //! @returns The name as a string. 84 | //! @note This is needed to ensure self registration in the factory works. 85 | //! The factory registration requires this as unique identifier. 86 | static const std::string Get_Name() { return "Hamming Weight"; } 87 | }; 88 | } // namespace Internal 89 | } // namespace GILES 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /src/Models/Model.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Model.hpp 20 | @brief Contains the Model class which serves as a base case for mathematical 21 | models to be implemented. 22 | @author Scott Egerton 23 | @date 2017-2019 24 | @copyright GNU Affero General Public License Version 3+ 25 | */ 26 | 27 | #ifndef MODEL_HPP 28 | #define MODEL_HPP 29 | 30 | #include // for all_of 31 | #include // for string 32 | #include // for unordered_set 33 | #include // for vector 34 | 35 | #include "Abstract_Factory_Register.hpp" // for Model_Factory_Register 36 | #include "Coefficients.hpp" 37 | #include "Error.hpp" // for Report_Error 38 | #include "Execution.hpp" 39 | #include "Model_Math.hpp" 40 | 41 | namespace GILES 42 | { 43 | namespace Internal 44 | { 45 | //! @brief An abstract class that serves as a base class for mathematical models 46 | //! to be implemented, These models will generate the traces for the given 47 | //! program by making use of the Coefficients and the recorded Execution of the 48 | //! program. 49 | //! This class is not designed to be inherited from directly; instead 50 | //! Emulator_Interface should be inherited from. This class provides a 51 | //! non-templated base class to allow handling of derived objects. 52 | class Model 53 | { 54 | protected: 55 | //! The execution of the target program as recorded by the Emulator. 56 | const Execution m_execution; 57 | 58 | //! The Coefficients created by measuring real hardware traces. 59 | const Coefficients& m_coefficients; 60 | 61 | Model(const Execution& p_execution, const Coefficients& p_coefficients) 62 | : m_execution(p_execution), m_coefficients(p_coefficients) 63 | { 64 | } 65 | 66 | public: 67 | //! @brief In derived classes, this function should contain the 68 | //! mathematical calculations that generate the Traces. 69 | //! @returns The generated Traces for the target program. 70 | virtual const std::vector Generate_Traces() = 0; 71 | 72 | //! @brief Virtual destructor to ensure proper memory cleanup. 73 | //! @see https://stackoverflow.com/a/461224 74 | virtual ~Model() = default; 75 | }; 76 | 77 | //! @class Model 78 | //! @brief This adds self registering factory code to the derived class, given 79 | //! by derived_t and delegates construction of a base class to the Model 80 | //! class. Additionally this class will automatically check if the derived class 81 | //! has the required interaction terms using Check_Interaction_Terms during 82 | //! construction. 83 | //! @tparam derived_t This should be the same as the derived type. This will add 84 | //! the self registering factory code automatically, allowing use of the 85 | //! derived class. 86 | template 87 | class Model_Interface : public Model, public Model_Factory_Register 88 | { 89 | protected: 90 | //! @brief The constructor needs to be provided with the recorded 91 | //! Execution of the target program and the details from real world 92 | //! traces, the Coefficients, to be able to calculate the Traces for the 93 | //! target program. This constructor is marked as protected as it should 94 | //! only be called by derived classes to assist with initialisation. 95 | //! @param p_execution The recorded Execution of the target program, 96 | //! provided by the Emulator. 97 | //! @param p_coefficients The loaded Coefficients from real hardware 98 | //! traces. 99 | Model_Interface(const Execution& p_execution, 100 | const Coefficients& p_coefficients) 101 | : Model(p_execution, p_coefficients) 102 | { 103 | if (!Check_Interaction_Terms()) 104 | { 105 | Error::Report_Error("{} Model was not provided with correct " 106 | "interaction terms by the Coefficients file.", 107 | derived_t::Get_Name()); 108 | } 109 | } 110 | 111 | //! @brief Retrieves the interaction terms used within the model. This is 112 | //! required to ensure the Coefficients file provided all of the required 113 | //! interaction terms. 114 | //! @returns A list of required interaction terms as defined in the 115 | //! derived class. 116 | static const std::unordered_set& Get_Interaction_Terms() 117 | { 118 | return derived_t::Get_Interaction_Terms(); 119 | }; 120 | 121 | public: 122 | //! @brief Virtual destructor to ensure proper memory cleanup. 123 | //! @see https://stackoverflow.com/a/461224 124 | virtual ~Model_Interface() = default; 125 | 126 | //! @brief Ensures that all the interaction terms used within the model 127 | //! are provided by the Coefficients. 128 | //! @returns True if the all the interaction terms required by the model 129 | //! are contained within the Coefficients and false if not. 130 | bool Check_Interaction_Terms() const 131 | { 132 | const auto& models_terms = Get_Interaction_Terms(); 133 | const auto& coefficients_terms = m_coefficients.Get_Interaction_Terms(); 134 | 135 | // If there are less terms in the Coefficients then there are 136 | // missing terms. 137 | return models_terms.size() <= coefficients_terms.size() && 138 | // For each term the model uses, check it is contained within 139 | // the set of terms provided by the Coefficients. 140 | std::all_of(models_terms.begin(), 141 | models_terms.end(), 142 | // A lambda function for checking if an 143 | // individual element is in coefficients_terms. 144 | [&coefficients_terms](const auto& term) { 145 | return coefficients_terms.end() != 146 | coefficients_terms.find(term); 147 | }); 148 | } 149 | }; 150 | } // namespace Internal 151 | } // namespace GILES 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /src/Models/Model_Math.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Model_Math.hpp 20 | @brief Contains the Model_Math class which serves as a base case for 21 | mathematical Model_Maths to be implemented. 22 | @author Scott Egerton 23 | @date 2017-2019 24 | @copyright GNU Affero General Public License Version 3+ 25 | */ 26 | 27 | #ifndef Model_Math_MATH_HPP 28 | #define Model_Math_MATH_HPP 29 | 30 | #include // for array 31 | #include // for max 32 | #include // for vector 33 | 34 | namespace GILES 35 | { 36 | namespace Internal 37 | { 38 | //! @class Model_Math 39 | //! @brief An abstract class that serves as a base class for mathematical 40 | //! Models to be implemented, These Models will generate the traces 41 | //! for the given program by making use of the Coefficients and the recorded 42 | //! Execution of the program. 43 | class Model_Math 44 | { 45 | private: 46 | //! This controls the size of the hamming weight lookup table. 47 | using lookup_size_t = std::uint8_t; // 8 bit lookup table 48 | 49 | //! The size of the hamming weight lookup table to generate, 50 | static constexpr std::size_t array_size = 51 | std::numeric_limits::max() + 1; 52 | 53 | //! class Hamming 54 | //! @brief This class exists as a wrapper around a lookup table for 55 | //! Hamming weight values. The array 'weights' will be initialised to 56 | //! serve as a lookup table when an instance of Hamming is constructed. 57 | //! @see https://en.wikipedia.org/wiki/Hamming_weight 58 | struct Hamming 59 | { 60 | //! The hamming weight lookup table. 61 | std::array Weights; 62 | 63 | //! @brief Constructs Hamming and populates the lookup table with 64 | //! hamming weight values. 65 | //! @see https://en.wikipedia.org/wiki/Hamming_weight 66 | constexpr Hamming() : Weights{} 67 | { 68 | for (std::uint32_t i{0}; i < array_size; ++i) 69 | { 70 | Weights[i] = Hamming_Weight(i); 71 | } 72 | } 73 | 74 | //! @brief Calculates the hamming weight of the given input. 75 | //! @param p_input The value to find the hamming weight of. 76 | //! @returns The hamming weight of p_input. 77 | //! @see https://en.wikipedia.org/wiki/Hamming_weight 78 | static constexpr std::uint8_t Hamming_Weight(const std::size_t p_input) 79 | { 80 | // Use non standard accelerated function if it is available. 81 | #ifdef __GNUC 82 | return __builtin_popcount(p_input); 83 | 84 | // Otherwise manually calculate the hamming weights. 85 | #else 86 | std::size_t input{p_input}; 87 | std::uint8_t count = input ? 1 : 0; 88 | while (input &= (input - 1)) 89 | { 90 | ++count; 91 | } 92 | return count; 93 | #endif 94 | } 95 | }; 96 | 97 | public: 98 | //! @brief Retrieves the hamming weight of a given 32 bit value 99 | //! @param p_input The value to find the hamming weight of. 100 | //! @returns The hamming weight of p_input. 101 | //! @see https://en.wikipedia.org/wiki/Hamming_weight 102 | //! @todo Ensure T is an int type. 103 | template ::value>> 105 | static constexpr std::size_t Hamming_Weight(const T p_input) 106 | { 107 | // Initialise the lookup. 108 | constexpr Hamming hamming{}; 109 | 110 | // Split the input into a number of parts, each small enough to perform 111 | // a hamming weight lookup on. 112 | constexpr std::size_t number_of_parts{sizeof(T) / 113 | sizeof(lookup_size_t)}; 114 | union { 115 | T original; 116 | lookup_size_t part[number_of_parts]; 117 | } split_input{p_input}; 118 | 119 | // Calculate the sum of the hamming weight of all the parts. This is 120 | // equal to the hamming weight of the input. 121 | std::size_t result{0}; 122 | for (std::size_t i{0}; i < number_of_parts; ++i) 123 | { 124 | result += hamming.Weights[split_input.part[i]]; 125 | } 126 | 127 | return result; 128 | } 129 | 130 | //! @brief Calculates the hamming distance between the two given inputs. 131 | //! @param p_input_1 The value to find the hamming distance from. 132 | //! @param p_input_2 The value to find the hamming distance to. 133 | //! @tparam T This is a template in order to support multiple integer 134 | //! based types in one function. 135 | //! @returns The hamming distance between the inputs. 136 | //! @see https://en.wikipedia.org/wiki/Hamming_distance 137 | template 138 | static constexpr std::size_t Hamming_Distance(T p_input_1, T p_input_2) 139 | { 140 | return Hamming_Weight(p_input_1 ^ p_input_2); 141 | } 142 | 143 | //! @brief This has been deleted to ensure the constructor and the copy 144 | //! constructor cannot be called as this is just a utility class 145 | //! containing nothing but static functions. 146 | //! @see https://en.cppreference.com/w/cpp/language/rule_of_three 147 | //! @see https://en.cppreference.com/w/cpp/language/copy_constructor 148 | Model_Math(const Model_Math&) = delete; 149 | 150 | //! @brief This has been deleted to ensure the copy 151 | //! assignment operator cannot be called as this is just a utility class 152 | //! containing nothing but static functions. 153 | //! @see https://en.cppreference.com/w/cpp/language/rule_of_three 154 | //! @see https://en.cppreference.com/w/cpp/language/copy_assignment 155 | Model_Math& operator=(const Model_Math&) = delete; 156 | }; 157 | } // namespace Internal 158 | } // namespace GILES 159 | 160 | #endif 161 | -------------------------------------------------------------------------------- /src/Models/Power/Model_Power.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Model_Power.hpp 20 | @brief TODO: Add this. 21 | @author Scott Egerton 22 | @date 2017-2019 23 | @copyright GNU Affero General Public License Version 3+ 24 | */ 25 | 26 | #include "Model_Power.hpp" 27 | 28 | #include // for size_t 29 | #include // for deque 30 | #include // for pair, make_pair 31 | #include // for vector 32 | 33 | //! The list of interaction terms used by this model in order to generate 34 | //! traces. 35 | const std::unordered_set 36 | GILES::Internal::Model_Power::m_required_interaction_terms{ 37 | "Bit_Flip1", 38 | "Bit_Flip1_Bit_Interactions", 39 | "Bit_Flip2", 40 | "Bit_Flip2_Bit_Interactions", 41 | // TODO: Shorten strings as much as possible. 42 | "Hamming_Distance_Operand1_Previous_Instruction", 43 | "Hamming_Distance_Operand1_Subsequent_Instruction", 44 | "Hamming_Distance_Operand2_Previous_Instruction", 45 | "Hamming_Distance_Operand2_Subsequent_Instruction", 46 | "Hamming_Weight_Operand1_Previous_Instruction", 47 | "Hamming_Weight_Operand1_Subsequent_Instruction", 48 | "Hamming_Weight_Operand2_Previous_Instruction", 49 | "Hamming_Weight_Operand2_Subsequent_Instruction", 50 | "Operand1", 51 | "Operand1_Bit_Interactions", 52 | "Operand2", 53 | "Operand2_Bit_Interactions", 54 | "Previous_Instruction", 55 | "Subsequent_Instruction"}; 56 | 57 | //! @brief This function contains the mathematical calculations that generate 58 | //! the Traces. 59 | //! @returns The generated Traces for the target program. 60 | const std::vector GILES::Internal::Model_Power::Generate_Traces() 61 | { 62 | 63 | //! A sliding window that stores information about the previous, current and 64 | //! next instructions. 65 | //! Populated with the first two instructions, ready to be used as the 66 | //! previous and current instruction in calculations. 67 | //! This is done in advance as the loop below only adds the next 68 | //! instruction. 69 | std::deque 70 | instructions_window{ 71 | {get_instruction_terms(0), get_instruction_terms(1)}}; 72 | 73 | const auto previous_instruction = instructions_window.front(); 74 | const auto current_instruction = instructions_window[1]; 75 | const auto next_instruction = instructions_window.back(); 76 | 77 | //! The interactions between the instructions stored in instructions_window. 78 | //! This constructs the deque and adds one item to it, the interactions 79 | //! between the first and second instructions. 80 | std::deque instruction_interactions_window( 81 | {{previous_instruction, current_instruction}}); 82 | 83 | std::vector traces; 84 | 85 | // Start at 1 as we are taking the previous cycle into account in the 86 | // calculations. 87 | // Finish at size - 1 As we are taking the next cycle into account in the 88 | // calculations. 89 | { 90 | float constant{0}; 91 | 92 | const std::size_t size{m_execution.Get_Cycle_Count()}; 93 | 94 | // Start at 1 and end at size -1 as this takes into account the previous 95 | // and next instructions. 96 | for (std::size_t i{1}; i < size - 1; ++i) 97 | { 98 | // TODO: Add a special case for when i = 0 and i = last (and i = 1?/ 99 | // last-1?). 100 | 101 | // Add the next set of operands. 102 | instructions_window.emplace_back(get_instruction_terms(i + 1)); 103 | 104 | // Add the next set of cross instruction interactions. 105 | instruction_interactions_window.emplace_back(current_instruction, 106 | next_instruction); 107 | 108 | // if the constant of the previous instruction was 0 then it was 109 | // either unprofiled or an abnormal state. In this case we do not 110 | // want to use it in calculations so for the sake of these 111 | // calculations we will pretend it didn't occur. 112 | // TODO: This should only be the case for abnormal states. 113 | // Unprofiled instructions should not be captured by this. 114 | if (0 != constant) 115 | { 116 | const auto previous_instruction = instructions_window.front(); 117 | } 118 | const auto current_instruction = instructions_window[1]; 119 | const auto next_instruction = instructions_window.back(); 120 | 121 | // std::cout << instruction_interactions_window.size() << 122 | // std::endl; 123 | 124 | // TODO: Delete this? 125 | // TODO: Can/ Should this be made constexpr? 126 | const std::string& current_opcode{current_instruction.Get_Opcode()}; 127 | 128 | const std::string& previous_opcode{ 129 | previous_instruction.Get_Opcode()}; 130 | 131 | const std::string& next_opcode{next_instruction.Get_Opcode()}; 132 | 133 | // TODO: Bit flip 1 and 2 bit interactions is always 0 in the coeffs 134 | // file. Can these be removed? Is this a bug when turning into json? 135 | // Operand 1 and 2 bit interactions are only non 0 for muls and 136 | // stores 137 | 138 | // TODO: How does this work when the bit flip is based on 2 139 | // instructions but the opcode isn't? 140 | const auto bit_flip_1 = calculate_term( 141 | current_opcode, 142 | "Bit_Flip1", // TODO: This is a typo, why does it not crash??? 143 | instruction_interactions_window.front().Operand_1_Bit_Flip); 144 | 145 | // TODO: How does this work when the bit flip is based on 2 146 | // instructions but the opcode isn't? 147 | const auto bit_flip_2 = calculate_term( 148 | current_opcode, 149 | "Bit_Flip2", 150 | instruction_interactions_window.front().Operand_2_Bit_Flip); 151 | 152 | const auto bit_flip_interactions_1 = calculate_term( 153 | current_opcode, 154 | "Bit_Flip1_Bit_Interactions", 155 | std::bitset<32>(instruction_interactions_window.front() 156 | .Bit_Flip1_Bit_Interactions)); 157 | 158 | const auto bit_flip_interactions_2 = calculate_term( 159 | current_opcode, 160 | "Bit_Flip2_Bit_Interactions", 161 | std::bitset<32>(instruction_interactions_window.front() 162 | .Bit_Flip2_Bit_Interactions)); 163 | 164 | const auto operand_1 = 165 | calculate_term(current_opcode, 166 | "Operand1", 167 | std::bitset<32>(current_instruction.Operand_1)); 168 | // TODO: Which version should be used? 169 | /* 170 | * const auto operand_1 = 171 | * sum_of_scalar_multiply(current_instruction.Operand_1, 172 | * Get_Coefficient(current_opcode, 173 | * "Operand1")); 174 | */ 175 | 176 | const auto operand_2 = 177 | calculate_term(current_opcode, 178 | "Operand2", 179 | std::bitset<32>(current_instruction.Operand_2)); 180 | 181 | const auto operand_1_bit_interactions = calculate_term( 182 | current_opcode, 183 | "Operand1_Bit_Interactions", 184 | std::bitset<32>( 185 | current_instruction.Operand_1_Bit_Interactions)); 186 | 187 | const auto operand_2_bit_interactions = calculate_term( 188 | current_opcode, 189 | "Operand2_Bit_Interactions", 190 | std::bitset<32>( 191 | current_instruction.Operand_2_Bit_Interactions)); 192 | 193 | const auto previous_instruction_term = Get_Coefficient( 194 | current_opcode, "Previous_Instruction", previous_opcode); 195 | 196 | const auto subsequent_instruction_term = Get_Coefficient( 197 | current_opcode, "Subsequent_Instruction", next_opcode); 198 | 199 | const auto hamming_weight_terms = calculate_hamming_weight_terms( 200 | current_instruction, previous_opcode, next_opcode); 201 | 202 | const auto hamming_distance_terms = 203 | calculate_hamming_distance_terms(current_instruction, 204 | previous_instruction, 205 | next_instruction); 206 | 207 | constant = Get_Constant(current_opcode); 208 | 209 | // clang-format off 210 | traces.emplace_back(constant * ( 211 | previous_instruction_term + 212 | subsequent_instruction_term + 213 | operand_1 + 214 | operand_2 + 215 | operand_1_bit_interactions + 216 | operand_2_bit_interactions + 217 | bit_flip_1 + 218 | bit_flip_2 + 219 | bit_flip_interactions_1 + 220 | bit_flip_interactions_2 + 221 | hamming_weight_terms + 222 | hamming_distance_terms)); 223 | // clang-format on 224 | 225 | // fmt::print("{}: {}\n", i, traces.back()); 226 | // Get rid of the now unneeded instruction 2 cycles before. 227 | instructions_window.pop_front(); 228 | instruction_interactions_window.pop_front(); 229 | } 230 | } 231 | return traces; 232 | } 233 | -------------------------------------------------------------------------------- /src/Models/TEMPLATE/Model_TEMPLATE.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Model_TEMPLATE.hpp 20 | @brief This file is a template. This can be used as a base for implementing 21 | a mathematical model for generating traces of a given target program. 22 | @author Scott Egerton 23 | @date 2017-2019 24 | @copyright GNU Affero General Public License Version 3+ 25 | */ 26 | 27 | #include "Model_TEMPLATE.hpp" 28 | 29 | #include // for vector 30 | 31 | //! The list of interaction terms used by this model in order to generate 32 | //! traces. 33 | const std::unordered_set 34 | GILES::Internal::Model_TEMPLATE::m_required_interaction_terms{ 35 | "Bit_Flip1", 36 | "Bit_Flip1_Bit_Interactions", 37 | "Bit_Flip2", 38 | "Bit_Flip2_Bit_Interactions", 39 | "Hamming_Distance_Operand1_Previous_Instruction", 40 | "Hamming_Distance_Operand1_Subsequent_Instruction", 41 | "Hamming_Distance_Operand2_Previous_Instruction", 42 | "Hamming_Distance_Operand2_Subsequent_Instruction", 43 | "Hamming_Weight_Operand1_Previous_Instruction", 44 | "Hamming_Weight_Operand1_Subsequent_Instruction", 45 | "Hamming_Weight_Operand2_Previous_Instruction", 46 | "Hamming_Weight_Operand2_Subsequent_Instruction", 47 | "Operand1", 48 | "Operand1_Bit_Interactions", 49 | "Operand2", 50 | "Operand2_Bit_Interactions", 51 | "Previous_Instruction", 52 | "Subsequent_Instruction"}; 53 | 54 | //! @brief This function contains the mathematical calculations that generate 55 | //! the Traces. 56 | //! @returns The generated Traces for the target program. 57 | const std::vector 58 | GILES::Internal::Model_TEMPLATE::Generate_Traces() 59 | { 60 | // *** Place your code here *** 61 | //! @note m_coefficients and m_execution can be made use of to generate the 62 | //! traces. 63 | return std::vector(); // temp placeholder for debugging reasons 64 | } 65 | -------------------------------------------------------------------------------- /src/Models/TEMPLATE/Model_TEMPLATE.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Model_TEMPLATE.hpp 20 | @brief This file is a template. This can be used as a base for implementing 21 | a mathematical model for generating traces of a given target program. 22 | @note When implementing a model there is no need to change much in this 23 | file. Only the word "Template" needs to be changed in various places as 24 | well as the comments. The code that needs to be changed is mainly contained 25 | to the corresponding .cpp file. 26 | @author Scott Egerton 27 | @date 2017-2019 28 | @copyright GNU Affero General Public License Version 3+ 29 | */ 30 | 31 | #ifndef MODEL_TEMPLATE_HPP 32 | #define MODEL_TEMPLATE_HPP 33 | 34 | #include // for string 35 | #include // for unordered_set 36 | #include // for vector 37 | 38 | #include "Model.hpp" // for Model_Interface 39 | 40 | namespace GILES 41 | { 42 | namespace Internal 43 | { 44 | // Forward Declarations 45 | class Coefficients; 46 | class Execution; 47 | 48 | //! @class Model_TEMPLATE 49 | //! @brief This derived class contains a specific implementation of a 50 | //! mathematical model to calculate the traces for a target program. It is 51 | //! designed as a template allowing new models to be added with ease. 52 | //! Deriving from Model_Factory_Register as well will automatically register 53 | //! this class within the factory class. 54 | class Model_TEMPLATE : public virtual Model_Interface 55 | { 56 | private: 57 | static const std::unordered_set m_required_interaction_terms; 58 | 59 | public: 60 | //! @brief The constructor makes use of the base Model constructor to assist 61 | //! with initialisation of private member variables. 62 | Model_TEMPLATE(const GILES::Internal::Execution& p_execution, 63 | const GILES::Internal::Coefficients& p_coefficients) 64 | : Model_Interface(p_execution, p_coefficients) 65 | { 66 | } 67 | 68 | const std::vector Generate_Traces() override; 69 | 70 | //! @brief Retrieves a list of the interaction terms that are used within 71 | //! the model. These must be provided by the Coefficients in order for 72 | //! the model to function. 73 | //! @returns The list of interaction terms used within the model. 74 | static const std::unordered_set& get_interaction_terms() 75 | { 76 | return m_required_interaction_terms; 77 | } 78 | 79 | //! @brief Retrieves the name of this Model. 80 | //! @returns The name as a string. 81 | //! @note This is needed to ensure self registration in the factory works. 82 | //! The factory registration requires this as unique identifier. 83 | static const std::string Get_Name() { return "TEMPLATE"; } 84 | }; 85 | } // namespace Internal 86 | } // namespace GILES 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /src/Simulators/Emulator.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Emulator_Interface.hpp 20 | @brief Contains the Emulator_Interface class which serves as a base case for 21 | the interface to a specific emulator. 22 | @author Scott Egerton 23 | @date 2017-2019 24 | @copyright GNU Affero General Public License Version 3+ 25 | */ 26 | 27 | #ifndef EMULATOR_INTERFACE_HPP 28 | #define EMULATOR_INTERFACE_HPP 29 | 30 | #include // for popen 31 | #include // for string 32 | #include // for vector 33 | 34 | #include "Abstract_Factory_Register.hpp" // for Emulator_Factory_Register 35 | #include "Assembly_Instruction.hpp" 36 | #include "Execution.hpp" 37 | 38 | namespace GILES 39 | { 40 | namespace Internal 41 | { 42 | //! @class Emulator 43 | //! @brief An abstract class that serves as a base class for the interface 44 | //! to a specific emulator. The emulator will record the Execution of the 45 | //! target program. This class theoretically allows multiple emulators to be 46 | //! utilised as per the users choice. 47 | //! This class is not designed to be inherited from directly; instead 48 | //! Emulator_Interface should be inherited from. This class provides a 49 | //! non-templated base class to allow handling of derived objects. 50 | class Emulator 51 | { 52 | protected: 53 | //! The path to the target program. 54 | const std::string m_program_path; 55 | 56 | //! @brief This constructor is marked as protected as it should only be 57 | //! called by derived classes to assist with initialisation. 58 | //! @param p_program_path The path where the program is. 59 | explicit Emulator(const std::string& p_program_path) 60 | : m_program_path(p_program_path) 61 | { 62 | } 63 | 64 | //! @brief Runs the command provided and returns the stdout output contained 65 | //! within a string. 66 | //! @todo CHANGE THIS AND DOCUMENT 67 | //! @todo Change this to not return a string for speed? 68 | //! @see https://stackoverflow.com/q/478898 69 | const std::string invoke_emulator(const std::string& p_emulator_command, 70 | const std::string& p_emulator_path = "") 71 | { 72 | // A temporary buffer to read the output into. 73 | std::array buffer; 74 | 75 | // The result of running p_emulator_command. 76 | std::string result; 77 | 78 | // Run the command, and capture the output within a FILE 79 | std::shared_ptr command_output( 80 | popen((p_emulator_path + p_emulator_command).c_str(), "r"), pclose); 81 | 82 | if (!command_output) 83 | throw std::runtime_error("popen() failed!"); 84 | 85 | // While not the end of file, read more data. 86 | while (!feof(command_output.get())) 87 | { 88 | // Read data into the buffer and then append it to result. 89 | if (nullptr != fgets(buffer.data(), 128, command_output.get())) 90 | result += buffer.data(); 91 | } 92 | return result; 93 | } 94 | 95 | public: 96 | //! @brief Virtual destructor to ensure proper memory cleanup. 97 | //! @see https://stackoverflow.com/a/461224 98 | virtual ~Emulator() = default; 99 | 100 | //! @brief A function to start the process of invoking the emulator and 101 | //! recording the results. 102 | //! @returns The recorded Execution of the target program as an Execution 103 | //! object. 104 | virtual const Execution Run_Code() = 0; 105 | 106 | //! @brief A function to request to inject a fault in the simulator. 107 | //! @param p_cycle_to_fault The clock cycle indicating when to inject the 108 | //! fault. 109 | //! @param p_register_to_fault The name of the register to inject the fault 110 | //! into. 111 | //! @param p_bit_to_fault The index of the bit to be faulted. 112 | //! @see https://en.wikipedia.org/wiki/Fault_injection 113 | virtual void Inject_Fault(const std::uint32_t p_cycle_to_fault, 114 | const std::string& p_register_to_fault, 115 | const std::uint8_t p_bit_to_fault) = 0; 116 | 117 | virtual void Add_Timeout(const std::uint32_t p_number_of_cycles) = 0; 118 | 119 | //! @todo Document 120 | virtual const std::string& Get_Extra_Data() = 0; 121 | }; 122 | 123 | //! @class Emulator_Interface 124 | //! @brief This adds self registering factory code to the derived class, given 125 | //! by derived_t and delegates construction of a base class to the Emulator 126 | //! class. 127 | //! @tparam derived_t This should be the same as the derived type. This will add 128 | //! the self registering factory code automatically, allowing use of the 129 | //! derived class. 130 | template 131 | class Emulator_Interface : public Emulator, 132 | public Emulator_Factory_Register 133 | { 134 | protected: 135 | //! @brief This constructor is marked as protected as it should only be 136 | //! called by derived classes to assist with initialisation. 137 | //! @param p_program_path The path where the program is. 138 | explicit Emulator_Interface(const std::string& p_program_path) 139 | : Emulator(p_program_path) 140 | { 141 | } 142 | 143 | public: 144 | //! @brief Virtual destructor to ensure proper memory cleanup. 145 | //! @see https://stackoverflow.com/a/461224 146 | virtual ~Emulator_Interface() = default; 147 | }; 148 | } // namespace Internal 149 | } // namespace GILES 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /src/Simulators/TEMPLATE/Emulator_TEMPLATE.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Emulator_TEMPLATE.hpp 20 | @todo add brief 21 | @author Scott Egerton 22 | @date 2017-2019 23 | @copyright GNU Affero General Public License Version 3+ 24 | */ 25 | 26 | #include "Emulator_TEMPLATE.hpp" 27 | #include "Error.hpp" 28 | #include "Execution.hpp" 29 | 30 | const GILES::Internal::Execution GILES::Internal::Emulator_TEMPLATE::Run_Code() 31 | { 32 | // *** Place your code here *** 33 | //! @note m_program_path Should contain the path to the target program. 34 | //! @note invoke_emulator(...) will return the output of a binary as a 35 | //! string. This can be used if the emulator is a binary. 36 | Error::Report_Error("Not yet implemented"); 37 | } 38 | 39 | void GILES::Internal::Emulator_TEMPLATE::Inject_Fault( 40 | const std::uint32_t p_cycle_to_fault, 41 | const std::string& p_register_to_fault, 42 | const std::uint8_t p_bit_to_fault) 43 | { 44 | Error::Report_Error("This feature is not supported by this simulator"); 45 | } 46 | 47 | void GILES::Internal::Emulator_TEMPLATE::Add_Timeout( 48 | const std::uint32_t p_number_of_cyclest) 49 | { 50 | Error::Report_Error("This feature is not supported by this simulator"); 51 | } 52 | -------------------------------------------------------------------------------- /src/Simulators/TEMPLATE/Emulator_TEMPLATE.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | #ifndef EMULATOR_TEMPLATE_HPP 19 | #define EMULATOR_TEMPLATE_HPP 20 | 21 | #include // for string 22 | #include // for vector 23 | 24 | #include "Emulator.hpp" // for Emulator_Interface 25 | #include "Execution.hpp" // for Execution 26 | 27 | namespace GILES 28 | { 29 | namespace Internal 30 | { 31 | class Emulator_TEMPLATE 32 | : public virtual Emulator_Interface 33 | { 34 | public: 35 | //! @brief Constructs an Emulator that will simulate the program given by 36 | //! p_program_path. 37 | //! @param p_program_path The path to the program to be loaded into the 38 | //! simulator. 39 | explicit Emulator_TEMPLATE(const std::string& p_program_path) 40 | : Emulator_Interface(p_program_path) 41 | { 42 | } 43 | 44 | const GILES::Internal::Execution Run_Code() override; 45 | 46 | const std::string& Get_Extra_Data() override; 47 | 48 | void Inject_Fault(const std::uint32_t p_cycle_to_fault, 49 | const std::string& p_register_to_fault, 50 | const std::uint8_t p_bit_to_fault) override; 51 | 52 | void Add_Timeout(const std::uint32_t p_number_of_cyclest) override; 53 | 54 | //! @brief Retrieves the name of this Emulator. 55 | //! @returns The name as a string. 56 | //! @note This is needed to ensure self registration in the factory works. 57 | //! The factory registration requires this as unique identifier. 58 | static const std::string Get_Name() { return "TEMPLATE"; } 59 | }; 60 | } // namespace Internal 61 | } // namespace GILES 62 | 63 | #endif // EMULATOR_TEMPLATE_HPP 64 | -------------------------------------------------------------------------------- /src/Simulators/Thumb_Sim/Emulator_Thumb_Sim.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Emulator_Thumb_Sim.hpp 20 | @todo add brief 21 | @author Scott Egerton 22 | @date 2017-2019 23 | @copyright GNU Affero General Public License Version 3+ 24 | */ 25 | 26 | #include // for string 27 | #include // for pair 28 | 29 | #include "simulator/regfile.h" // for Reg 30 | 31 | #include "Emulator_Thumb_Sim.hpp" 32 | #include "Execution.hpp" 33 | 34 | const GILES::Internal::Execution GILES::Internal::Emulator_Thumb_Sim::Run_Code() 35 | { 36 | m_simulator.run(m_program_path); 37 | 38 | m_execution_recording = m_simulator.Get_Cycle_Recorder(); 39 | 40 | // Retrieve the results from the simulator 41 | const auto& fetch = m_execution_recording.Get_Fetch(); 42 | const auto& decode = m_execution_recording.Get_Decode(); 43 | const auto& execute = m_execution_recording.Get_Execute(); 44 | 45 | // TODO: When are the registers recorded? Should it be once or between every 46 | // stage? 47 | const auto& registers = m_execution_recording.Get_Registers(); 48 | 49 | // Create an Execution object and add the required data to it. 50 | Execution execution(m_execution_recording.Get_Cycle_Count()); 51 | execution.Add_Registers_All(registers); 52 | execution.Add_Pipeline_Stage("Fetch", fetch); 53 | execution.Add_Pipeline_Stage("Decode", decode); 54 | execution.Add_Pipeline_Stage("Execute", execute); 55 | 56 | // Correctly place stalls and flushes so that they can be easily identified. 57 | // TODO: Flushes 58 | for (std::size_t i{0}; i < execute.size(); ++i) 59 | { 60 | if ("Stalled, pending decode" == execute[i]) 61 | { 62 | execution.Add_Value( 63 | i, "Execute", GILES::Internal::Execution::State::Stalled); 64 | } 65 | } 66 | return execution; 67 | } 68 | 69 | const std::string& GILES::Internal::Emulator_Thumb_Sim::Get_Extra_Data() 70 | { 71 | return m_execution_recording.Get_Extra_Data(); 72 | } 73 | 74 | void GILES::Internal::Emulator_Thumb_Sim::Inject_Fault( 75 | const std::uint32_t p_cycle_to_fault, 76 | const std::string& p_register_to_fault, 77 | const std::uint8_t p_bit_to_fault) 78 | { 79 | const Reg register_to_fault{[&p_register_to_fault] { 80 | if ("R0" == p_register_to_fault) 81 | { 82 | return Reg::R0; 83 | } 84 | if ("R1" == p_register_to_fault) 85 | { 86 | return Reg::R1; 87 | } 88 | if ("R2" == p_register_to_fault) 89 | { 90 | return Reg::R2; 91 | } 92 | if ("R3" == p_register_to_fault) 93 | { 94 | return Reg::R3; 95 | } 96 | if ("R4" == p_register_to_fault) 97 | { 98 | return Reg::R4; 99 | } 100 | if ("R5" == p_register_to_fault) 101 | { 102 | return Reg::R5; 103 | } 104 | if ("R6" == p_register_to_fault) 105 | { 106 | return Reg::R6; 107 | } 108 | if ("R7" == p_register_to_fault) 109 | { 110 | return Reg::R7; 111 | } 112 | if ("R8" == p_register_to_fault) 113 | { 114 | return Reg::R8; 115 | } 116 | if ("R9" == p_register_to_fault) 117 | { 118 | return Reg::R9; 119 | } 120 | if ("R10" == p_register_to_fault) 121 | { 122 | return Reg::R10; 123 | } 124 | if ("R11" == p_register_to_fault) 125 | { 126 | return Reg::R11; 127 | } 128 | if ("R12" == p_register_to_fault) 129 | { 130 | return Reg::R12; 131 | } 132 | if ("R13" == p_register_to_fault || "MSP" == p_register_to_fault) 133 | { 134 | return Reg::MSP; 135 | } 136 | if ("R14" == p_register_to_fault || "LR" == p_register_to_fault) 137 | { 138 | return Reg::LR; 139 | } 140 | if ("R15" == p_register_to_fault || "PC" == p_register_to_fault) 141 | { 142 | return Reg::PC; 143 | } 144 | if ("PSP" == p_register_to_fault) 145 | { 146 | return Reg::PSP; 147 | } 148 | if ("XPSR" == p_register_to_fault) 149 | { 150 | return Reg::XPSR; 151 | } 152 | if ("CONTROL" == p_register_to_fault) 153 | { 154 | return Reg::CONTROL; 155 | } 156 | Error::Report_Error("Could not find register with the name \"{}\"", 157 | p_register_to_fault); 158 | }()}; 159 | 160 | m_simulator.InjectFault( 161 | p_cycle_to_fault, register_to_fault, p_bit_to_fault); 162 | } 163 | 164 | void GILES::Internal::Emulator_Thumb_Sim::Add_Timeout( 165 | const std::uint32_t p_number_of_cycles) 166 | { 167 | m_simulator.AddTimeout(p_number_of_cycles); 168 | } 169 | -------------------------------------------------------------------------------- /src/Simulators/Thumb_Sim/Emulator_Thumb_Sim.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | #ifndef EMULATOR_THUMB_SIM_HPP 19 | #define EMULATOR_THUMB_SIM_HPP 20 | 21 | #include // for string 22 | #include // for vector 23 | 24 | #include "Emulator.hpp" // for Emulator_Interface 25 | #include "Execution.hpp" // for Execution 26 | 27 | #include "simulator.cpp" // for Simulator 28 | 29 | namespace GILES 30 | { 31 | namespace Internal 32 | { 33 | class Emulator_Thumb_Sim : public virtual Emulator_Interface 34 | { 35 | private: 36 | Simulator m_simulator; 37 | Thumb_Simulator::Debug m_execution_recording; 38 | 39 | public: 40 | //! @brief Constructs an Emulator that will simulate the program given by 41 | //! p_program_path. 42 | //! @param p_program_path The path to the program to be loaded into the 43 | //! simulator. 44 | explicit Emulator_Thumb_Sim(const std::string& p_program_path) 45 | : Emulator_Interface{p_program_path}, m_simulator{} 46 | { 47 | } 48 | 49 | const GILES::Internal::Execution Run_Code() override; 50 | 51 | const std::string& Get_Extra_Data() override; 52 | 53 | void Inject_Fault(const std::uint32_t p_cycle_to_fault, 54 | const std::string& p_register_to_fault, 55 | const std::uint8_t p_bit_to_fault) override; 56 | 57 | void Add_Timeout(const std::uint32_t p_number_of_cyclest) override; 58 | 59 | //! @brief Retrieves the name of this Emulator. 60 | //! @returns The name as a string. 61 | //! @note This is needed to ensure self registration in the factory 62 | //! works. The factory registration requires this as unique identifier. 63 | static const std::string Get_Name() { return "Thumb Sim"; } 64 | }; 65 | } // namespace Internal 66 | } // namespace GILES 67 | 68 | #endif // EMULATOR_THUMB_SIM_HPP 69 | -------------------------------------------------------------------------------- /src/Utility.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Utility.hpp 20 | @brief This file contains the Utility class. A simple class with a few 21 | static helper functions that is otherwise empty. 22 | @author Scott Egerton 23 | @date 2017-2019 24 | @copyright GNU Affero General Public License Version 3+ 25 | */ 26 | 27 | #ifndef UTILITY_HPP 28 | #define UTILITY_HPP 29 | 30 | #include // for string 31 | #include // for vector 32 | 33 | #include 34 | 35 | #include "Assembly_Instruction.hpp" 36 | 37 | namespace GILES 38 | { 39 | namespace Internal 40 | { 41 | //! @class Utility This is a simple class containing nothing but static function 42 | //! that has a few functions to help with simple operations such as string 43 | //! transformations that are not in the standard library. 44 | class Utility 45 | { 46 | public: 47 | //! @brief Splits a string into a vector of strings using a string given by 48 | //! p_delimiter as a delimiter for splitting. 49 | //! For example: Splitting the string "Hello!World" with the delimiter "!" 50 | //! would become {"Hello", "World"}. 51 | //! @param p_input The string to be split. 52 | //! @param p_delimiter The delimiting string to spilt on. This will not be 53 | //! present in the output. 54 | //! @ returns a vector containing each split part of the input string. 55 | static const std::vector 56 | string_split(std::string p_input, const std::string& p_delimiter) 57 | { 58 | std::vector split_string; 59 | boost::split(split_string, p_input, boost::is_any_of(p_delimiter)); 60 | return split_string; 61 | } 62 | 63 | //! @brief Splits a string into into two using a string given by 64 | //! p_delimiter as a delimiter for splitting. The left hand side of the 65 | //! split is removed from the input and returned. 66 | //! If the delimiter is not found, the entire string is popped and returned, 67 | //! clearing p_input. 68 | //! @warning This function can potentially remove characters from the 69 | //! original input as p_input is a pointer. 70 | //! @param p_input The string to be split. This is a passed by pointer and 71 | //! will also contain the right hand side of the split after the function 72 | //! returns. This has been declared as a const pointer instead of a 73 | //! reference to indicate that it contains the original data. 74 | //! @param p_delimiter The delimiting string to spilt on. This will not be 75 | //! present in the output. 76 | //! @returns The left hand side of the first occurrence of p_delimiter in 77 | //! p_input or the entire string if p_delimiter is not found. 78 | static const std::string 79 | string_split_head_pop(std::string* const p_input, 80 | const std::string& p_delimiter) 81 | { 82 | std::string head; 83 | auto position = p_input->find(p_delimiter); 84 | 85 | // Push back everything from the beginning until this point as one 86 | // split. 87 | head = p_input->substr(0, position); 88 | 89 | // Remove what was just pushed back from the input string. 90 | p_input->erase(0, position + p_delimiter.length()); 91 | 92 | if (std::string::npos == position) 93 | { 94 | // If the delimiting value was not found, then pop the whole string 95 | // as the head 96 | p_input->clear(); 97 | } 98 | return head; 99 | } 100 | 101 | private: 102 | //! @brief This has been deleted to ensure the constructor and the copy 103 | //! constructor cannot be called as this is just a utility class containing 104 | //! nothing but static functions. 105 | //! @see https://en.cppreference.com/w/cpp/language/rule_of_three 106 | //! @see https://en.cppreference.com/w/cpp/language/copy_constructor 107 | Utility(const Utility&) = delete; 108 | 109 | //! @brief This has been deleted to ensure the copy 110 | //! assignment operator cannot be called as this is just a utility class 111 | //! containing nothing but static functions. 112 | //! @see https://en.cppreference.com/w/cpp/language/rule_of_three 113 | //! @see https://en.cppreference.com/w/cpp/language/copy_assignment 114 | Utility& operator=(const Utility&) = delete; 115 | }; 116 | } // namespace Internal 117 | } // namespace GILES 118 | 119 | #endif // UTILITY_HPP 120 | -------------------------------------------------------------------------------- /src/Validator_Coefficients.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Validator_Coefficients.cpp 20 | @brief Contains the validation rules for validating a Coefficients file. 21 | @author Scott Egerton 22 | @date 2017-2019 23 | @copyright GNU Affero General Public License Version 3+ 24 | */ 25 | 26 | #include // for find 27 | #include // for ios_base::failure, ios_base 28 | #include // for basic_string, string 29 | 30 | #include "Validator_Coefficients.hpp" 31 | 32 | namespace GILES 33 | { 34 | namespace Internal 35 | { 36 | //! @brief This function serves as an entry point to the validation rules. 37 | //! This function will invoke each validation rule in turn. 38 | //! @param p_coefficients The coefficients to be validated, stored within a 39 | //! nlohmann::json object. 40 | //! returns This does not return anything as instead an exception will be 41 | //! thrown if a rule fails. 42 | void GILES::Internal::Validator_Coefficients::Validate_Json( 43 | const nlohmann::json& p_coefficients) 44 | { 45 | Validate_Not_Empty(p_coefficients, "Coefficients file must not be empty."); 46 | Validate_Is_Object(p_coefficients); 47 | 48 | // Check each instruction category 49 | for (const auto& category : p_coefficients) 50 | { 51 | Validate_Is_Object(category); 52 | Validate_Not_Empty( 53 | category, 54 | "Coefficients file must not contain empty coefficient categories."); 55 | Validate_Category_Headings_Constant(category); 56 | Validate_Category_Headings_Coefficients(category); 57 | Validate_Is_Number(category["Constant"]); 58 | Validate_Is_Object(category["Coefficients"]); 59 | } 60 | Validate_Not_Empty(p_coefficients.front().at("Coefficients"), 61 | "There must be at least one interaction term in the " 62 | "Coefficients file."); 63 | for (const auto& category : p_coefficients.items()) // .items() is used as 64 | // Validate_category_Instruction_Unique 65 | // requires the key as well as the value 66 | { 67 | for (const auto& interaction_term : category.value()["Coefficients"]) 68 | { 69 | Validate_Not_Empty(interaction_term, 70 | "Each interaction term in the " 71 | "Coefficients file must " 72 | "contain at least one value."); 73 | Validate_Is_Array(interaction_term); 74 | for (const auto& value : interaction_term) 75 | { 76 | Validate_Is_Number(value); 77 | } 78 | } 79 | 80 | if (category.value().find("Instructions") != category.value().end()) 81 | { 82 | Validate_Not_Empty(category.value()["Instructions"], 83 | "Categories in the Coefficients file must " 84 | "not contain an empty list of instructions."); 85 | Validate_Is_Array(category.value()["Instructions"]); 86 | for (const auto& instruction : category.value()["Instructions"]) 87 | { 88 | Validate_Is_String(instruction); 89 | } 90 | } 91 | 92 | // If there is only one category then there is no need to perform 93 | // this validation check 94 | if (1 < p_coefficients.size()) 95 | { 96 | Validate_Category_Correct_Interaction_Terms(category.value(), 97 | p_coefficients); 98 | } 99 | Validate_Category_Interaction_Terms_Size(category.value(), 100 | p_coefficients); 101 | 102 | // If the "Instructions" tag not is present then there is no need to 103 | // apply these validation rules as other catergories validations will 104 | // check this. 105 | // Additionally JSON specification does not allow two 106 | // objects with the same name. 107 | if (category.value().find("Instructions") != category.value().end()) 108 | { 109 | Validate_Category_Instructions_Unique( 110 | category.value(), category.key(), p_coefficients); 111 | Validate_Category_Header_Unique( 112 | category.value(), category.key(), p_coefficients); 113 | } 114 | } 115 | } 116 | 117 | //! @brief Ensures that the given JSON is not an empty structure. 118 | //! @param p_json The json to be validated 119 | //! @exception std::ios_base::failure This is thrown in the case that this 120 | //! validation rule fails. In this case, the JSON is an empty structure. 121 | void GILES::Internal::Validator_Coefficients::Validate_Not_Empty( 122 | const nlohmann::json& p_json, const std::string& p_exception_message) 123 | { 124 | if (p_json.empty()) 125 | { 126 | throw std::ios_base::failure(p_exception_message); 127 | } 128 | } 129 | 130 | //! @brief Ensures that the given JSON is a JSON object. 131 | //! @param p_json The json to be validated 132 | //! @exception std::ios_base::failure This is thrown in the case that this 133 | //! validation rule fails. In this case, the JSON is an not an object. 134 | void GILES::Internal::Validator_Coefficients::Validate_Is_Object( 135 | const nlohmann::json& p_json) 136 | { 137 | if (!p_json.is_object()) 138 | { 139 | throw std::ios_base::failure("Expected a JSON object, found: " + 140 | p_json.dump()); 141 | } 142 | } 143 | 144 | //! @brief Ensures that the given JSON is a JSON number. 145 | //! @param p_json The json to be validated 146 | //! @exception std::ios_base::failure This is thrown in the case that this 147 | //! validation rule fails. In this case, the JSON is an not a number. 148 | void GILES::Internal::Validator_Coefficients::Validate_Is_Number( 149 | const nlohmann::json& p_json) 150 | { 151 | if (!p_json.is_number()) 152 | { 153 | throw std::ios_base::failure("Expected a JSON number, found: " + 154 | p_json.dump()); 155 | } 156 | } 157 | 158 | //! @brief Ensures that the given JSON is a JSON array. 159 | //! @param p_json The json to be validated 160 | //! @exception std::ios_base::failure This is thrown in the case that this 161 | //! validation rule fails. In this case, the JSON is an not an array. 162 | void GILES::Internal::Validator_Coefficients::Validate_Is_Array( 163 | const nlohmann::json& p_json) 164 | { 165 | // TODO: Seperate newly added functionality into different methods. 166 | if (p_json.is_object()) 167 | { 168 | for (const auto& item : p_json) 169 | { 170 | if (!item.is_number()) 171 | { 172 | throw std::ios_base::failure( 173 | "Expected a key value pair, found: " + p_json.dump()); 174 | } 175 | } 176 | return; 177 | } 178 | if (!p_json.is_array()) 179 | { 180 | throw std::ios_base::failure("Expected a JSON array, found: " + 181 | p_json.dump()); 182 | } 183 | } 184 | 185 | //! @brief Ensures that the given JSON is a JSON string. 186 | //! @param p_json The json to be validated 187 | //! @exception std::ios_base::failure This is thrown in the case that this 188 | //! validation rule fails. In this case, the JSON is an not a string. 189 | void GILES::Internal::Validator_Coefficients::Validate_Is_String( 190 | const nlohmann::json& p_json) 191 | { 192 | if (!p_json.is_string()) 193 | { 194 | throw std::ios_base::failure("Expected a JSON string, found: " + 195 | p_json.dump()); 196 | } 197 | } 198 | 199 | //! @brief Ensures that the given category contains a "Coefficients" 200 | //! subheading. Without this, the category would not contain any actual 201 | //! coefficient values. 202 | //! @param p_category The instruction category to be validated. 203 | //! @exception std::ios_base::failure This is thrown in the case that this 204 | //! validation rule fails. In this case, the "Coefficients" heading was not 205 | //! found. 206 | void GILES::Internal::Validator_Coefficients:: 207 | Validate_Category_Headings_Coefficients(const nlohmann::json& p_category) 208 | { 209 | if (p_category.find("Coefficients") == p_category.end()) 210 | { 211 | // Each category must contain Coefficients 212 | throw std::ios_base::failure( 213 | "Each category in the Coefficients file must contain a set of " 214 | "Coefficients."); 215 | } 216 | } 217 | 218 | //! @brief Ensures that the given category contains a "Constant" value. 219 | //! subheading. Without this, the coefficient values could not be utilised 220 | //! within a Model. 221 | //! @param p_category The instruction category to be validated. 222 | //! @exception std::ios_base::failure This is thrown in the case that this 223 | //! validation rule fails. In this case, the "Constant" heading was not 224 | //! found. 225 | void GILES::Internal::Validator_Coefficients:: 226 | Validate_Category_Headings_Constant(const nlohmann::json& p_category) 227 | { 228 | if (p_category.find("Constant") == p_category.end()) 229 | { 230 | // Each category must contain a Constant 231 | throw std::ios_base::failure("Each category in the Coefficients file " 232 | "must contain a Constant value."); 233 | } 234 | } 235 | 236 | //! @brief Ensures that the given category contains the same interaction 237 | //! terms as every other category. The Model will expect to find the same 238 | //! interaction terms for each category. The first category is used to check 239 | //! against as all categories should be the same except when checking the 240 | //! contents of the first category. When checking the contents of the first 241 | //! category, the last category is used to check against. 242 | //! @param p_category The instruction category to be validated. 243 | //! @param p_coefficients The coefficients, in order to compare against the 244 | //! first category. 245 | //! @exception std::ios_base::failure This is thrown in the case that this 246 | //! validation rule fails. In this case, the correct interaction terms were 247 | //! not found. 248 | void GILES::Internal::Validator_Coefficients:: 249 | Validate_Category_Correct_Interaction_Terms( 250 | const nlohmann::json& p_category, const nlohmann::json& p_coefficients) 251 | { 252 | // If this is the first category don't compare against itself, instead 253 | // use the last element as a reference as it is easy to access. When not 254 | // checking the first category, compare against the first. 255 | const nlohmann::json& reference_category = 256 | p_coefficients.front() == p_category ? p_coefficients.back() 257 | : p_coefficients.front(); 258 | 259 | // check each interaction term individually. 260 | for (const auto& interaction_term : p_category["Coefficients"].items()) 261 | { 262 | // if the reference category doesn't contain interaction_term.key() 263 | if (reference_category.at("Coefficients") 264 | .find(interaction_term.key()) == 265 | reference_category.at("Coefficients").end()) 266 | { 267 | throw std::ios_base::failure( 268 | "The same interaction terms must be provided for all " 269 | "categories in the Coefficients file."); 270 | } 271 | } 272 | } 273 | 274 | //! @brief Ensures that each of the interaction terms within the given 275 | //! category contains the same amount of values. The first category is used 276 | //! to check against as all categories should be the same. 277 | //! @param p_category The instruction category to be validated. 278 | //! @param p_coefficients The coefficients, in order to compare against the 279 | //! first category. 280 | //! @exception std::ios_base::failure This is thrown in the case that this 281 | //! validation rule fails. In this case, an interaction term does not 282 | //! contain the correct number of values. 283 | void GILES::Internal::Validator_Coefficients:: 284 | Validate_Category_Interaction_Terms_Size( 285 | const nlohmann::json& p_category, const nlohmann::json& p_coefficients) 286 | { 287 | for (const auto& interaction_term : p_category["Coefficients"].items()) 288 | { 289 | // Interaction terms must all have the same number of 290 | // Coefficient values. 291 | if (interaction_term.value().size() != 292 | p_coefficients.front()["Coefficients"][interaction_term.key()] 293 | .size()) 294 | { 295 | throw std::ios_base::failure( 296 | "Each interaction term in the Coefficients file must " 297 | "contain the same amount of values for each " 298 | "category."); 299 | } 300 | } 301 | } 302 | 303 | //! @brief Ensures that no category has the same name as an instruction within a 304 | //! different category. This removes ambiguity as the same name can refer to two 305 | //! different sets of coefficients. 306 | //! @param p_category The instruction category to be validated. 307 | //! @param p_category_key The heading of the category contained within 308 | //! p_category. 309 | //! @param p_coefficients The coefficients, in order to compare against the 310 | //! first category. 311 | //! @exception std::ios_base::failure This is thrown in the case that this 312 | //! validation rule fails. In this case, an instruction was found to have 313 | //! more than one set of coefficients associated with it. 314 | void GILES::Internal::Validator_Coefficients::Validate_Category_Header_Unique( 315 | const nlohmann::json& p_category, 316 | const std::string& p_category_key, 317 | const nlohmann::json& p_coefficients) 318 | { 319 | // For each category 320 | for (const auto& search_category : p_coefficients.items()) 321 | { 322 | // For each instruction 323 | for (const auto& instruction : p_category["Instructions"]) 324 | { 325 | // If the category has the same name as the instruction then 326 | // throw an exception. 327 | if (search_category.key() == instruction) 328 | { 329 | throw std::ios_base::failure( 330 | "Each instruction in the Coefficients file must have " 331 | "only one set of Coefficients associated with it. " + 332 | instruction.dump() + 333 | " was used as category name and also under the " 334 | "'Instructions' tag in the " 335 | "category: \"" + 336 | p_category_key + "\""); 337 | } 338 | } 339 | } 340 | } 341 | 342 | //! @brief Ensures that no instruction is contained within multiple 343 | //! categories. 344 | //! @param p_category The instruction category to be validated. 345 | //! @param p_category_key The heading of the category contained within 346 | //! p_category. 347 | //! @param p_coefficients The coefficients, in order to compare against the 348 | //! first category. 349 | //! @exception std::ios_base::failure This is thrown in the case that this 350 | //! validation rule fails. In this case, an instruction was found to have 351 | //! more than one set of coefficients associated with it. 352 | void GILES::Internal::Validator_Coefficients:: 353 | Validate_Category_Instructions_Unique(const nlohmann::json& p_category, 354 | const std::string& p_category_key, 355 | const nlohmann::json& p_coefficients) 356 | { 357 | // Check against every other category 358 | for (const auto& search_category : p_coefficients.items()) 359 | { 360 | // Don't search the category it was originally found in. 361 | if (p_category_key == search_category.key()) 362 | { 363 | continue; 364 | } 365 | 366 | // For each instruction in the category 367 | for (const auto& instruction : p_category["Instructions"]) 368 | { 369 | // If the Instructions heading is not present there is 370 | // nothing 371 | // to check. 372 | if (search_category.value().find("Instructions") == 373 | search_category.value().end()) 374 | { 375 | continue; 376 | } 377 | // If the instruction is not the search category, there is 378 | // no 379 | // problem 380 | if (std::find(search_category.value().at("Instructions").begin(), 381 | search_category.value().at("Instructions").end(), 382 | instruction.get()) == 383 | search_category.value().at("Instructions").end()) 384 | { 385 | continue; 386 | } 387 | // If the above checks fail then throw an exception 388 | throw std::ios_base::failure( 389 | "Each instruction in the Coefficients file must have " 390 | "only one set of Coefficients associated with it. Found: " + 391 | instruction.dump() + " in: '" + p_category_key + "'" + 392 | p_category.at("Instructions").dump() + "' and also in: '" + 393 | search_category.key() + "'" + 394 | search_category.value().at("Instructions").dump()); 395 | } 396 | } 397 | } 398 | } // namespace Internal 399 | } // namespace GILES 400 | -------------------------------------------------------------------------------- /src/Validator_Coefficients.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Validator_Coefficients.hpp 20 | @brief Contains the validation rules for validating a Coefficients file. 21 | @author Scott Egerton 22 | @date 2017-2019 23 | @copyright GNU Affero General Public License Version 3+ 24 | */ 25 | 26 | #ifndef VALIDATOR_COEFFICIENTS_HPP 27 | #define VALIDATOR_COEFFICIENTS_HPP 28 | 29 | #include // for string 30 | 31 | #include // for json 32 | 33 | namespace GILES 34 | { 35 | namespace Internal 36 | { 37 | 38 | //! @class Validator_Coefficients 39 | //! @brief A static class that validates Coefficients before they are stored 40 | //! within Coefficient objects. This contains all validation rules, implemented 41 | //! as individual functions, that need to be run to ensure that the JSON is in 42 | //! the correct format as valid JSON does not mean that it is a valid 43 | //! Coefficients file. 44 | class Validator_Coefficients 45 | { 46 | private: 47 | static void Validate_Not_Empty(const nlohmann::json& p_coefficients, 48 | const std::string& p_exception_message); 49 | 50 | static void Validate_Is_Object(const nlohmann::json& p_json); 51 | 52 | static void Validate_Is_Number(const nlohmann::json& p_json); 53 | 54 | static void Validate_Is_Array(const nlohmann::json& p_json); 55 | 56 | static void Validate_Is_String(const nlohmann::json& p_json); 57 | 58 | static void 59 | Validate_Category_Headings_Coefficients(const nlohmann::json& p_category); 60 | 61 | static void 62 | Validate_Category_Headings_Constant(const nlohmann::json& p_category); 63 | 64 | static void Validate_Category_Correct_Interaction_Terms( 65 | const nlohmann::json& p_category, const nlohmann::json& p_coefficients); 66 | 67 | static void Validate_Category_Interaction_Terms_Size( 68 | const nlohmann::json& p_category, const nlohmann::json& p_coefficients); 69 | 70 | static void 71 | Validate_Category_Instructions_Unique(const nlohmann::json& p_category, 72 | const std::string& p_category_key, 73 | const nlohmann::json& p_coefficients); 74 | 75 | static void 76 | Validate_Category_Header_Unique(const nlohmann::json& p_category, 77 | const std::string& p_category_key, 78 | const nlohmann::json& p_coefficients); 79 | 80 | //! @brief This has been deleted to ensure the constructor and the copy 81 | //! constructor cannot be called as this is just a utility class containing 82 | //! nothing but static functions. 83 | //! @see https://en.cppreference.com/w/cpp/language/rule_of_three 84 | //! @see https://en.cppreference.com/w/cpp/language/copy_constructor 85 | Validator_Coefficients(const Validator_Coefficients&) = delete; 86 | 87 | //! @brief This has been deleted to ensure the copy 88 | //! assignment operator cannot be called as this is just a utility class 89 | //! containing nothing but static functions. 90 | //! @see https://en.cppreference.com/w/cpp/language/rule_of_three 91 | //! @see https://en.cppreference.com/w/cpp/language/copy_assignment 92 | Validator_Coefficients& operator=(const Validator_Coefficients&) = delete; 93 | 94 | public: 95 | static void Validate_Json(const nlohmann::json& p_coefficients); 96 | }; 97 | } // namespace Internal 98 | } // namespace GILES 99 | 100 | #endif // VALIDATOR_COEFFICIENTS_HPP 101 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[=[ 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | #]=] 17 | 18 | cmake_minimum_required(VERSION 2.6) 19 | 20 | include("${PROJECT_SOURCE_DIR}/cmake/External.cmake") 21 | 22 | # C++11 is required for nlohmann_json and catch 23 | set(CMAKE_CXX_STANDARD 11) 24 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 25 | 26 | option(${PROJECT_NAME}_CALCULATE_COVERAGE "Setup ready to calculate the code coverage of the unit tests. This adds profiling compiler flags, disables optimisations and adds the 'coverage' target. Requires Gcovr." OFF) 27 | 28 | if(${PROJECT_NAME}_CALCULATE_COVERAGE) 29 | # Enable profiling for code coverage 30 | # PARENT_SCOPE is needed for these flags to persist outside this directory 31 | set(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage" PARENT_SCOPE) 32 | # Second call is needed to set these in the current directory 33 | set(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") 34 | 35 | # A custom command to generate a html code coverage report using gcovr. 36 | # (https://gcovr.com/) 37 | # This will create a directory, "coverage", compile and run the tests and then 38 | # generate the coverage information for those tests. 39 | add_custom_target(coverage 40 | COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/coverage 41 | COMMAND ${EXECUTABLE_OUTPUT_PATH}/${PROJECT_NAME}-tests 42 | COMMAND gcovr ${PROJECT_BINARY_DIR} -r ${PROJECT_SOURCE_DIR} --exclude-unreachable-branches --exclude-directories=test --html --html-details -o ${PROJECT_BINARY_DIR}/coverage/coverage.html 43 | DEPENDS ${PROJECT_NAME}-tests 44 | COMMENT "Generating HTML coverage report" 45 | ) 46 | endif(${PROJECT_NAME}_CALCULATE_COVERAGE) 47 | 48 | # Make the test executable 49 | add_executable(${PROJECT_NAME}-tests 50 | #Test_Validator_Coefficients.cpp 51 | #Test_Factory.cpp 52 | Tests.cpp 53 | ) 54 | 55 | 56 | # Link to required external projects 57 | target_link_libraries(${PROJECT_NAME}-tests PUBLIC nlohmann_json::nlohmann_json) 58 | 59 | # Download and include required files from external projects 60 | target_include_external_project(${PROJECT_NAME}-tests Catch2 single_include/catch2) 61 | 62 | # Include the src being tested 63 | target_include_directories(${PROJECT_NAME}-tests PRIVATE 64 | ${PROJECT_SOURCE_DIR}/src 65 | ${EXECUTABLE_OUTPUT_PATH}) 66 | 67 | target_link_libraries(${PROJECT_NAME}-tests PUBLIC lib${PROJECT_NAME}) 68 | #target_include_directories(${PROJECT_NAME}-tests SYSTEM PRIVATE ${THIRD_PARTY_DIR}) 69 | 70 | enable_testing() 71 | add_test(NAME Run_Tests COMMAND ${PROJECT_NAME}-tests) 72 | -------------------------------------------------------------------------------- /test/Test_Coefficients.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Test_Validator_Coefficients.cpp 20 | @brief Contains the tests for the Validator_Coefficients class. 21 | @author Scott Egerton 22 | @date 2017-2018 23 | @copyright GNU Affero General Public License Version 3+ 24 | */ 25 | 26 | #include // for catch 27 | 28 | #include // for json 29 | 30 | #include "Coefficients.hpp" 31 | #include "Validator_Coefficients.hpp" 32 | 33 | TEST_CASE("Coefficients" 34 | "[!throws][coefficients]") 35 | { 36 | // A test Coefficients class is used for testing purposes. 37 | // This is its contents. 38 | const nlohmann::json json = R"( 39 | { 40 | "ALU" : 41 | { 42 | "Constant" : 0, 43 | "Coefficients" : 44 | { 45 | "Operand1" : [0, 1, 2, 3], 46 | "Operand2" : [4, 5, 6], 47 | "Hello" : 48 | { 49 | "World" : 4.0001, 50 | "Hi" : 3.9999 51 | } 52 | }, 53 | "Instructions" : ["add", "odd", "edd"] 54 | }, 55 | "Shifts" : 56 | { 57 | "Constant" : 1, 58 | "Coefficients" : 59 | { 60 | "Operand1" : [7, 8, 9, 10], 61 | "Operand2" : [11, 12, 13], 62 | "Hello" : 63 | { 64 | "World" : 0, 65 | "Hi" : -1 66 | } 67 | }, 68 | "Instructions" : ["lsls", "lsrs"] 69 | }, 70 | "eors" : 71 | { 72 | "Constant" : 2.01, 73 | "Coefficients" : 74 | { 75 | "Operand1" : [14, 15, 16, 17], 76 | "Operand2" : [18, 19, 20], 77 | "Hello" : 78 | { 79 | "World" : 14, 80 | "Hi" : 5.0 81 | } 82 | } 83 | } 84 | })"_json; 85 | 86 | // Ensure that this is valid JSON before using it to test the Coefficients 87 | // class. 88 | REQUIRE_NOTHROW( 89 | GILES::Internal::Validator_Coefficients::Validate_Json(json)); 90 | 91 | GILES::Internal::Coefficients coefficients{json}; 92 | 93 | SECTION("Get_Instruction_Category") 94 | { 95 | REQUIRE("ALU" == coefficients.Get_Instruction_Category("add")); 96 | REQUIRE("ALU" == coefficients.Get_Instruction_Category("odd")); 97 | REQUIRE("ALU" == coefficients.Get_Instruction_Category("edd")); 98 | } 99 | 100 | SECTION("Get_Coefficients") 101 | { 102 | REQUIRE(std::vector{0, 1, 2, 3} == 103 | coefficients.Get_Coefficients("add", "Operand1")); 104 | REQUIRE(std::vector{0, 1, 2, 3} == 105 | coefficients.Get_Coefficients("odd", "Operand1")); 106 | REQUIRE(std::vector{4, 5, 6} == 107 | coefficients.Get_Coefficients("odd", "Operand2")); 108 | } 109 | 110 | SECTION("Get_Coefficient") 111 | { 112 | REQUIRE(4.0001 == 113 | coefficients.Get_Coefficient("add", "Hello", "World")); 114 | REQUIRE(3.9999 == coefficients.Get_Coefficient("odd", "Hello", "Hi")); 115 | 116 | REQUIRE(0 == coefficients.Get_Coefficient("lsls", "Hello", "World")); 117 | REQUIRE(-1 == coefficients.Get_Coefficient("lsrs", "Hello", "Hi")); 118 | 119 | REQUIRE(14 == coefficients.Get_Coefficient("eors", "Hello", "World")); 120 | REQUIRE(5.0 == coefficients.Get_Coefficient("eors", "Hello", "Hi")); 121 | /* 122 | *REQUIRE(std::vector{0, 1, 2, 3} == 123 | * coefficients.Get_Coefficients("odd", "Operand1")); 124 | *REQUIRE(std::vector{4, 5, 6} == 125 | * coefficients.Get_Coefficient("odd", "Operand2")); 126 | */ 127 | } 128 | 129 | SECTION("Get_Constant") 130 | { 131 | REQUIRE(0 == coefficients.Get_Constant("add")); 132 | REQUIRE(0 == coefficients.Get_Constant("odd")); 133 | REQUIRE(0 == coefficients.Get_Constant("odd")); 134 | REQUIRE(1 == coefficients.Get_Constant("lsls")); 135 | REQUIRE(1 == coefficients.Get_Constant("lsrs")); 136 | REQUIRE(2.01 == coefficients.Get_Constant("eors")); 137 | 138 | REQUIRE_THROWS_WITH(coefficients.Get_Constant("Invalid"), 139 | "This instruction (Invalid) was not found " 140 | "within the Coefficients"); 141 | } 142 | 143 | SECTION("Get_Interaction_Terms") 144 | { 145 | REQUIRE( 146 | std::unordered_set{"Operand1", "Operand2", "Hello"} == 147 | coefficients.Get_Interaction_Terms()); 148 | } 149 | 150 | // TODO: Find a way of testing these invalid results that don't return. 151 | /* 152 | *SECTION("Get_Coefficients Invalid") 153 | *{ 154 | * REQUIRE_THROWS(coefficients.Get_Coefficients("add", "Operand2")); 155 | * REQUIRE_THROWS(coefficients.Get_Coefficients("Invalid", 156 | * "Operand1")); 157 | * 158 | * REQUIRE_THROWS(coefficients.Get_Coefficients("add", 159 | * "Invalid")); 160 | * 161 | * REQUIRE_THROWS(coefficients.Get_Coefficients("Invalid", 162 | * "Invalid")); 163 | *} 164 | */ 165 | } 166 | -------------------------------------------------------------------------------- /test/Test_Execution.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Test_Validator_Coefficients.cpp 20 | @brief Contains the tests for the Validator_Coefficients class. 21 | @author Scott Egerton 22 | @date 2017-2018 23 | @copyright GNU Affero General Public License Version 3+ 24 | */ 25 | 26 | #include // for catch 27 | 28 | #include // for json 29 | 30 | #include "Execution.hpp" 31 | 32 | TEST_CASE("Execution class testing" 33 | "[execution]") 34 | { 35 | GILES::Internal::Execution execution{3}; 36 | 37 | SECTION("Add_Pipeline_Stage uint8_t") 38 | { 39 | REQUIRE_NOTHROW(execution.Add_Pipeline_Stage( 40 | "Execute", std::vector{5, 1})); 41 | } 42 | 43 | SECTION("Add_Pipeline_Stage bool") 44 | { 45 | // Test adding different types 46 | REQUIRE_NOTHROW(execution.Add_Pipeline_Stage( 47 | "Fetch", std::vector{true, false})); 48 | } 49 | 50 | SECTION("Add_Registers_All correct size") 51 | { 52 | std::vector> registers{ 53 | {{"1", 1}, {"2", 0}, {"SP", 9}, {"A0", 1}}, 54 | {{"1", 1}, {"2", 0}, {"SP", 9}, {"A0", 1}}, 55 | {{"1", 4}, {"2", 10}, {"SP", 0xB}, {"A0", 7}}}; 56 | 57 | REQUIRE_NOTHROW(execution.Add_Registers_All(registers)); 58 | } 59 | 60 | SECTION("Add_Registers_Cycle & Check Registers") 61 | { 62 | REQUIRE_NOTHROW(execution.Add_Registers_Cycle( 63 | 0, {{"1", 1}, {"2", 0}, {"SP", 9}, {"A0", 1}})); 64 | 65 | REQUIRE(execution.Is_Register("A0")); 66 | 67 | REQUIRE_FALSE(execution.Is_Register("false")); 68 | } 69 | 70 | SECTION("Add_Value & Get_Value") 71 | { 72 | REQUIRE_NOTHROW( 73 | execution.Add_Value(0, "Execute", 0b0101101)); 74 | 75 | REQUIRE_NOTHROW(execution.Get_Value(0, "Execute")); 76 | 77 | REQUIRE_THROWS_WITH( 78 | execution.Get_Value(0, "Execute"), 79 | "The requested pipeline state is not stored as the requested type"); 80 | } 81 | 82 | SECTION("Get_Cycle_Count") 83 | { 84 | REQUIRE_NOTHROW(3 == execution.Get_Cycle_Count()); 85 | } 86 | 87 | SECTION("Get_Instruction") 88 | { 89 | REQUIRE_NOTHROW( 90 | execution.Add_Value(0, "Execute", "add r0, 10")); 91 | 92 | REQUIRE_NOTHROW(execution.Get_Instruction(0, "Execute")); 93 | REQUIRE_THROWS(execution.Get_Instruction(-1, "Execute")); 94 | REQUIRE_THROWS(execution.Get_Instruction(1, "Execute")); 95 | REQUIRE_THROWS(execution.Get_Instruction(0, "Fetch")); 96 | } 97 | 98 | SECTION("Get_Operand_Value - Operand") 99 | { 100 | REQUIRE_NOTHROW(execution.Add_Registers_Cycle( 101 | 0, {{"r1", 1}, {"2", 0}, {"SP", 9}, {"A0", 1}})); 102 | 103 | // Register lookups. 104 | REQUIRE(9 == execution.Get_Operand_Value(0, "SP")); 105 | REQUIRE(0 == execution.Get_Operand_Value(0, "2")); 106 | 107 | // Not a register. 108 | REQUIRE(5 == execution.Get_Operand_Value(0, "5")); 109 | } 110 | 111 | SECTION("Get_Operand_Value - Instruction") 112 | { 113 | const GILES::Internal::Assembly_Instruction instruction{"add", 114 | {"r1", "10"}}; 115 | 116 | REQUIRE_NOTHROW(execution.Add_Registers_Cycle( 117 | 0, {{"r1", 1}, {"2", 0}, {"SP", 9}, {"A0", 1}})); 118 | 119 | // Get register r1 120 | REQUIRE(1 == execution.Get_Operand_Value(0, instruction, 1)); 121 | 122 | // Get value 10 123 | REQUIRE(10 == execution.Get_Operand_Value(0, instruction, 2)); 124 | } 125 | 126 | SECTION("Get_Registers") 127 | { 128 | std::map registers{ 129 | {"r1", 1}, {"2", 0}, {"SP", 9}, {"A0", 1}}; 130 | 131 | REQUIRE_NOTHROW(execution.Add_Registers_Cycle(0, registers)); 132 | 133 | REQUIRE(registers == execution.Get_Registers(0)); 134 | 135 | // Cycle 2 is within range but should be blank as nothing has been 136 | // added for this yet. 137 | REQUIRE_NOTHROW(execution.Get_Registers(2)); 138 | 139 | REQUIRE_THROWS(execution.Get_Registers(7)); 140 | REQUIRE_THROWS(execution.Get_Registers(-1)); 141 | } 142 | 143 | SECTION("Get_Register_Value") 144 | { 145 | REQUIRE_NOTHROW(execution.Add_Registers_Cycle( 146 | 0, {{"r1", 1}, {"2", 0}, {"SP", 9}, {"A0", 1}})); 147 | 148 | REQUIRE(1 == execution.Get_Register_Value(0, "r1")); 149 | 150 | REQUIRE_THROWS(execution.Get_Register_Value(2, "r1")); 151 | REQUIRE_THROWS(execution.Get_Register_Value(-1, "r1")); 152 | REQUIRE_THROWS(execution.Get_Register_Value(100, "r1")); 153 | REQUIRE_THROWS(execution.Get_Register_Value(0, "invalid")); 154 | } 155 | 156 | SECTION("Cycle state tests") 157 | { 158 | // Add a few test states. 159 | REQUIRE_NOTHROW( 160 | execution.Add_Value(0, "Execute", 0b0101101)); 161 | REQUIRE_NOTHROW(execution.Add_Value( 162 | 0, "Stalled", GILES::Internal::Execution::State::Stalled)); 163 | REQUIRE_NOTHROW(execution.Add_Value( 164 | 1, "Flush", GILES::Internal::Execution::State::Flushing)); 165 | 166 | // Perform the tests. 167 | 168 | // Test Get_State with valid parameters. 169 | REQUIRE(GILES::Internal::Execution::State::Normal == 170 | execution.Get_State(0, "Execute")); 171 | 172 | REQUIRE(GILES::Internal::Execution::State::Stalled == 173 | execution.Get_State(0, "Stalled")); 174 | 175 | REQUIRE(GILES::Internal::Execution::State::Flushing == 176 | execution.Get_State(1, "Flush")); 177 | 178 | // TODO: Find a way of testing for report_error. 179 | 180 | // Test Get_State_Unsafe with valid parameters. 181 | REQUIRE(GILES::Internal::Execution::State::Normal == 182 | execution.Get_State_Unsafe(0, "Execute")); 183 | 184 | REQUIRE(GILES::Internal::Execution::State::Stalled == 185 | execution.Get_State_Unsafe(0, "Stalled")); 186 | 187 | REQUIRE(GILES::Internal::Execution::State::Flushing == 188 | execution.Get_State_Unsafe(1, "Flush")); 189 | 190 | // Test Get_State_Unsafe with invalid parameters. 191 | REQUIRE(GILES::Internal::Execution::State::Stalled == 192 | execution.Get_State_Unsafe(0, "Invalid")); 193 | 194 | REQUIRE(GILES::Internal::Execution::State::Stalled == 195 | execution.Get_State_Unsafe(-1, "Execute")); 196 | 197 | REQUIRE(GILES::Internal::Execution::State::Stalled == 198 | execution.Get_State_Unsafe(1, "Execute")); 199 | 200 | REQUIRE(GILES::Internal::Execution::State::Stalled == 201 | execution.Get_State_Unsafe(100, "Execute")); 202 | 203 | // Test Is_Normal_State with valid parameters. 204 | REQUIRE(execution.Is_Normal_State(0, "Execute")); 205 | 206 | REQUIRE_FALSE(execution.Is_Normal_State(0, "Stalled")); 207 | 208 | REQUIRE_FALSE(execution.Is_Normal_State(1, "Flush")); 209 | 210 | // Test Is_Normal_State_Unsafe with valid parameters. 211 | REQUIRE(execution.Is_Normal_State_Unsafe(0, "Execute")); 212 | 213 | REQUIRE_FALSE(execution.Is_Normal_State_Unsafe(0, "Stalled")); 214 | 215 | REQUIRE_FALSE(execution.Is_Normal_State_Unsafe(1, "Flush")); 216 | 217 | // Test Is_Normal_State_Unsafe with invalid parameters. 218 | REQUIRE_FALSE(execution.Is_Normal_State_Unsafe(0, "Invalid")); 219 | 220 | REQUIRE_FALSE(execution.Is_Normal_State_Unsafe(-1, "Execute")); 221 | 222 | REQUIRE_FALSE(execution.Is_Normal_State_Unsafe(1, "Execute")); 223 | 224 | REQUIRE_FALSE(execution.Is_Normal_State_Unsafe(100, "Execute")); 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /test/Test_Factory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Test_Validator_Coefficients.cpp 20 | @brief Contains the tests for the Validator_Coefficients class. 21 | @author Scott Egerton 22 | @date 2017-2018 23 | @copyright GNU Affero General Public License Version 3+ 24 | */ 25 | 26 | #include 27 | 28 | #include // for catch 29 | 30 | #include // for json 31 | 32 | #include "Abstract_Factory.hpp" 33 | #include "Abstract_Factory_Register.hpp" 34 | #include "Execution.hpp" 35 | 36 | TEST_CASE("Factory pattern testing" 37 | "[factory]") 38 | { 39 | class Abstract_Base 40 | { 41 | }; 42 | 43 | struct Abstract_Derived 44 | : public Abstract_Base, 45 | public GILES::Internal::Abstract_Factory_Register 47 | { 48 | Abstract_Derived() 49 | { 50 | // This statement registers this class in the factory, allowing 51 | // access from elsewhere. Do not delete this or else this class 52 | // will not appear in the factory. If you wish to make this 53 | // class inaccessible, a better method would be to remove the 54 | // corresponding cpp file from the build script. This is 55 | // required to be "used" somewhere in order to prevent the 56 | // compiler from optimising it away, thus preventing self 57 | // registration. 58 | // Section 6.6.4.1, point 2 of the linked document states that 59 | // this statement will not be optimised away. 60 | // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf 61 | // The void cast does nothing functionally but prevents the 62 | // compiler warning about an unused result. 63 | (void)m_is_registered; 64 | } 65 | 66 | static const std::string Get_Name() { return "Abstract_Derived"; } 67 | }; 68 | 69 | using Factory_t = GILES::Internal::Abstract_Factory; 70 | 71 | SECTION("Abstract factory auto registration") 72 | { 73 | const auto registered = Factory_t::Get_All(); 74 | 75 | // Ensure it was successfully added to the factory. 76 | REQUIRE(registered.size() == 1); 77 | } 78 | 79 | SECTION("Abstract factory construction") 80 | { 81 | const auto object = Factory_t::Construct("Abstract_Derived"); 82 | 83 | // Check we can construct using the factory and that we end up with 84 | // something of the expected type. 85 | REQUIRE(typeid(Abstract_Base) == typeid(*object)); 86 | } 87 | 88 | SECTION("Abstract factory find") 89 | { 90 | // Check if it can be found by name. This function should never return a 91 | // nullptr. It will exit in the case of failure but that will also cause 92 | // this to fail. 93 | REQUIRE(nullptr != Factory_t::Find("Abstract_Derived")); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /test/Tests.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of GILES. 3 | 4 | GILES is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | GILES is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with GILES. If not, see . 16 | */ 17 | 18 | /*! 19 | @file Tests.cpp 20 | @brief Contains the entry point for the tests 21 | @author Scott Egerton 22 | @date 2017-2018 23 | @copyright GNU Affero General Public License Version 3+ 24 | */ 25 | 26 | //! Required when using Catch testing framework - Tells Catch to provide a 27 | //! main() 28 | //! @see https://github.com/catchorg/Catch2 29 | #ifndef CATCH_CONFIG_MAIN 30 | #define CATCH_CONFIG_MAIN 31 | #endif // CATCH_CONFIG_MAIN 32 | 33 | #include // for catch 34 | 35 | // The actual tests 36 | #include "Test_Coefficients.cpp" 37 | #include "Test_Execution.cpp" 38 | #include "Test_Factory.cpp" 39 | #include "Test_Validator_Coefficients.cpp" 40 | -------------------------------------------------------------------------------- /uml/Class.plantuml: -------------------------------------------------------------------------------- 1 | @startuml 2 | 3 | title ELMO - Class Diagram 4 | 5 | package ELMO { 6 | class ELMO { 7 | -IO io 8 | -list models 9 | -Interface interface 10 | -Execution execution 11 | -Traces traces 12 | -Coefficients coefficients 13 | +main() 14 | -parseCommandLineOptions() 15 | -reOrderAssembly() 16 | } 17 | 18 | class "I/O" as IO { 19 | +Coefficients LoadCoefficients(string coefficientsPath) 20 | +Traces OutputTraces(string tracesPath, Traces traces, string format) 21 | } 22 | 23 | abstract class "Emulator Interface" { 24 | {abstract} +Interface(string programPath) 25 | {abstract} +Execution RunCode() 26 | {abstract} -list parseRegisters(string registers) 27 | {abstract} -AssemblyInstruction parseAssembly(string assembly) 28 | } 29 | 30 | class "Unicorn Interface" { 31 | +Interface(string programPath) 32 | +Execution RunCode() 33 | -list parseRegisters(string registers) 34 | -AssemblyInstruction parseAssembly(string assembly) 35 | } 36 | 37 | abstract class "Model" { 38 | +{abstract} Traces GenerateTraces(Execution execution, Coefficients coefficients) 39 | -addNoise(&Traces traces) 40 | } 41 | 42 | class ModelPower { 43 | +Traces GenerateTraces(Execution execution, Coefficients coefficients) 44 | } 45 | 46 | class Execution { 47 | -list registersInitialState 48 | -list assembly 49 | +Execution(list registersInitialState, AssemblyInstruction firstInstruction) 50 | +list getRegistersInitialState() 51 | +list getAssembly() 52 | } 53 | 54 | class AssemblyInstruction { 55 | -string opcode 56 | -list operands 57 | list ChangedRegisters 58 | +AssemblyInstruction(string opcode, list changedRegisters) 59 | +string getOpcode() 60 | +list getOperands() 61 | +list getChangedRegisters() 62 | } 63 | note bottom of AssemblyInstruction 64 | Do operands actually need to be stored 65 | if register changes are recorded? 66 | end note 67 | note bottom of AssemblyInstruction 68 | Assembly instructions executed should be 69 | stored as programs don't always run sequentially 70 | end note 71 | 72 | class Register { 73 | -string name 74 | -string value 75 | +Register(string name, string value) 76 | +string getName() 77 | +string getValue() 78 | } 79 | 80 | class "Traces" { 81 | } 82 | note bottom of Traces 83 | See Riscure Inspector Manual for format. 84 | Maybe optionally allow different formats. 85 | end note 86 | 87 | class "Coefficients" { 88 | } 89 | note bottom of Coefficients 90 | Internal representation of the Coefficient files. 91 | Should be able to represent multiple different kind of Coefficients 92 | end note 93 | } 94 | 95 | package "Unicorn Engine" { 96 | } 97 | 98 | package "Assembly Re-orderer" { 99 | } 100 | 101 | package "Coefficient Files" <> { 102 | } 103 | 104 | package "Generated Traces" <> { 105 | } 106 | 107 | Model <|-- ModelPower 108 | "Emulator Interface" <|-- "Unicorn Interface" 109 | 110 | ELMO "1"*-- "1" IO 111 | ELMO "1"*-- "1" "Emulator Interface" 112 | ELMO <--> "Assembly Re-orderer" : Interacts with 113 | ELMO "1"*--"1...*" Model 114 | 115 | Model "1"*--"1" Coefficients : Uses > 116 | Model "1"*--"1" Execution : Uses > 117 | Model "1"*--"1" Traces : Generates > 118 | 119 | "Unicorn Interface" <--> "Unicorn Engine" : Interacts with 120 | 121 | "Emulator Interface" "1"*--"1" Execution : Creates and Updates > 122 | "Execution" "1"*--"1...*" AssemblyInstruction 123 | 124 | AssemblyInstruction "1"*--"1...*" Register 125 | Execution ..> Register 126 | 127 | IO --> "Coefficient Files" : Loads < 128 | note on link 129 | No need for validation it can be assumed 130 | that the Coefficient files are correct 131 | end note 132 | IO --> "Generated Traces" : Saves > 133 | 134 | "Coefficient Files" <.. Coefficients : Maps to > 135 | "Generated Traces" <.. Traces : Maps to < 136 | 137 | ModelPower -[hidden]- Coefficients 138 | ModelPower -[hidden]- Traces 139 | 140 | @enduml 141 | -------------------------------------------------------------------------------- /uml/Sequence.plantuml: -------------------------------------------------------------------------------- 1 | @startuml 2 | 3 | title "ELMO - Sequence Diagram" 4 | 5 | actor User 6 | 7 | User -> ELMO : Request traces for program 8 | activate ELMO 9 | 10 | par 11 | ELMO -> "Assembly Re-orderer" : Re-order assembly 12 | note right: To better emulate hardware optimisations 13 | activate "Assembly Re-orderer" 14 | ELMO <-- "Assembly Re-orderer" : Pass Re-ordered assembly 15 | deactivate "Assembly Re-orderer" 16 | 17 | ELMO -> "Unicorn-Engine" : Run program in Unicorn Engine 18 | activate "Unicorn-Engine" 19 | ELMO <-- "Unicorn-Engine" : Pass execution information 20 | deactivate "Unicorn-Engine" 21 | else 22 | database "Coefficients" as Coefficients 23 | database "Traces" as Traces 24 | 25 | ELMO -> Coefficients : Load coefficients 26 | activate Coefficients 27 | ELMO <-- Coefficients : Load coefficients 28 | deactivate Coefficients 29 | end 30 | 31 | ELMO -> ELMO : Generate traces 32 | 33 | opt 34 | ELMO -> Traces : Save traces 35 | activate Traces 36 | ELMO <-- Traces : Save traces 37 | deactivate Traces 38 | else 39 | User <-- ELMO : Pass coefficients 40 | end 41 | 42 | deactivate ELMO 43 | 44 | @enduml 45 | -------------------------------------------------------------------------------- /uml/UseCase.plantuml: -------------------------------------------------------------------------------- 1 | @startuml 2 | 3 | title GILES - Use Case Diagram 4 | 5 | 6 | rectangle ELMO { 7 | (Generate traces for code) as Generate 8 | (Load coefficients from file) as Load 9 | (Save generated traces to file) as Save 10 | rectangle Unicorn-Engine { 11 | (Emulate running of code) as Emulate 12 | } 13 | } 14 | 15 | :User: 16 | 17 | User -> Generate : Request traces 18 | Emulate ..> Generate : <> 19 | Load ..> Generate : <> 20 | Save ..> Generate : <> 21 | 22 | @enduml 23 | --------------------------------------------------------------------------------