Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Variable length instructions for single faults #83

Merged
merged 2 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,6 @@ def build_fault_list(conf_list, combined_faults, ret_faults):
for tcounter in build_ranges(faultdev["trigger_counter"]):
for numbytes in build_ranges(faultdev["num_bytes"]):
if isinstance(fmask, dict):
assert (
wildcard_fault
), "only wildcard faults can be evaluated, if fault.mask is a dict"
assert ftype == detect_type(
"instruction"
), "fault.type has to be 'instruction', if fault.mask is a dict"
Expand Down
16 changes: 14 additions & 2 deletions fault-readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,14 +186,14 @@ For example when you want to shift a bit mask, you can use the type "shift" as f
The shift corresponds to a left shift. In the above case, the number 3 is subsequently shifted by 7, 8, 9 to the left (binary representation).

Another example of a dictionary is the use of instruction width dependent fault masks.
This only works in combination with the wildcard mode, the instruction fault type, and the overwrite fault model.
berkayurun marked this conversation as resolved.
Show resolved Hide resolved
This only works in combination with the instruction fault type and the overwrite fault model.
Below is an example fault configuration.
This example targets an ARM Cortex M4 processor.
The scenario is to apply an instruction skip.
Therefore, the fault_mask contains opcodes for a 16-bit and 32-bit NOP instruction.
Note that the num_bytes must not be set as this changes depending on the targeted instruction.

Example:
Example 1:
```
{
"fault_address" : ["*"],
Expand All @@ -206,6 +206,18 @@ Example:
}
```

Example 2:
```
{
"fault_address" : [0x08000056],
"fault_type" : "instruction",
"fault_model" : "overwrite",
"fault_lifespan" : [100],
"fault_mask" : {"type": "dict", "dict": {"2": 0xbf00, "4": 0x8000f3af}},
"trigger_address" : [0x08000040],
"trigger_counter" : [1]
}
```

##### trigger_address
Defines the trigger instruction, i.e., when this instruction has been executed, the faults (defined in fault mask) are inserted into the respective fault address. The trigger_address must be an executed instruction! For every fault address, there is a separate test, i.e., experiment.
Expand Down
43 changes: 43 additions & 0 deletions goldenrun.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ def run_goldenrun(
tbexec = pd.DataFrame(experiment["data"]["tbexec"])
tbinfo = pd.DataFrame(experiment["data"]["tbinfo"])
process_wildcard_faults(faultconfig, tbexec, tbinfo)
process_single_faults(faultconfig, tbexec, tbinfo)
calculate_trigger_addresses(faultconfig, tbexec, tbinfo)
faultconfig = checktriggers_in_tb(faultconfig, experiment["data"])

Expand Down Expand Up @@ -418,3 +419,45 @@ def process_wildcard_faults(faultconfig, tbexec, tbinfo):
new_fault_entry["faultlist"] = [wildcard_faults[i]]
new_fault_entry["delete"] = False
faultconfig.append(new_fault_entry)


def process_single_faults(faultconfig, tbexec, tbinfo):
remove_list = []
for faultentry in faultconfig:
for fault in faultentry["faultlist"]:
if not isinstance(fault.mask, dict):
continue

tbinfo_tb_indexed = tbinfo.set_index("id")
for tb in tqdm(tbexec["tb"], leave=False):
tb_info_asm = tbinfo_tb_indexed.at[tb, "assembler"]
tb_info_total_size = tbinfo_tb_indexed.at[tb, "size"]

tb_info_asm = [
int(instr.split("]")[0], 16)
for instr in tb_info_asm.split("[ ")[1:]
]
if fault.address not in tb_info_asm:
continue

tb_info_size = list(numpy.diff(tb_info_asm))
tb_info_size.append(
tb_info_total_size - sum(tb_info_size)
) # calculate the last instr size

fault_idx = tb_info_asm.index(fault.address)

try:
fault.mask = fault.mask[str(tb_info_size[fault_idx])]
fault.num_bytes = tb_info_size[fault_idx]
except (ValueError, KeyError):
logger.info(
f"No matching fault mask could be found for fault entry {faultentry['index']}, "
f"removing the fault entry..."
)
remove_list.append(faultentry)

break

for faultentry in remove_list:
faultconfig.remove(faultentry)
Loading