├── .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 | 
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 |
--------------------------------------------------------------------------------