Skip to content

Commit

Permalink
Support multiple end points
Browse files Browse the repository at this point in the history
Multiple end points are specified as an array to the "end" fault
configuration entry.
  • Loading branch information
lukasauer committed Dec 15, 2022
1 parent 7030a77 commit bf931ab
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 29 deletions.
2 changes: 2 additions & 0 deletions controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,8 @@ def process_arguments(args):
if "start" in faultlist:
qemu_conf["start"] = faultlist["start"]
if "end" in faultlist:
if type(faultlist["end"]) == dict:
faultlist["end"] = [faultlist["end"]]
qemu_conf["end"] = faultlist["end"]

if "memorydump" in faultlist:
Expand Down
4 changes: 3 additions & 1 deletion fault-readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Criteria for ending the instruction count (if "end" block exists in fault.json):
Criteria for ending the instruction count (if "end" block does not exists in fault.json):
* max_instruction_count (limit) instructions have been executed (absolute limit)

The limit is necessary, since the program could be caught up in an infinite loop caused by the "injected" faults. To determine which of these terminating conditions applied, the output file (in HDF5 format) can be consulted. In table "faults" (under "experiments"), the attribute "endpoint" reveals whether the "end" address (value: 1) or whether the absolute or relative limit (value: 0) was reached. In addition, the termination reason ("max tb" or "endpoint {address}/{counter}") is included in the attribute "end_reason" of table "faults". The number of instructions specified in max_instruction_count is only treated as an absolute value when "end" is not defined, otherwise max_instruction_count only goes into the calculation of the limit (*end - start + max_instruction_count*) for the termination of the plugin.
The limit is necessary, since the program could be caught up in an infinite loop caused by the "injected" faults. To determine which of these terminating conditions applied, the output file (in HDF5 format) can be consulted. In table "faults" (under "experiments"), the attribute "endpoint" reveals whether the first end point (value: 1) or whether the absolute or relative limit (value: 0) was reached. In addition, the termination reason ("max tb" or "endpoint {address}/{counter}") is included in the attribute "end_reason" of table "faults". The number of instructions specified in max_instruction_count is only treated as an absolute value when "end" is not defined, otherwise max_instruction_count only goes into the calculation of the limit (*end - start + max_instruction_count*) for the termination of the plugin.

Currently, when the start point is set, the respective translation block that contains "start" is skipped. The counting of instructions is begun after this TB. A translation block is begun (and ended) after (at) any kind of branch operation. In single-stepping mode, one instruction corresponds to one TB. Single-stepping is enabled automatically after the trigger counter incrementation terminates and the fault is "injected". Hence, a more detailed analysis of the fault propagation is provided. Single-stepping can also be enabled via the command line (within QEMU) or by setting fault_lifespan to a value that differs from 0. In certain cases, single-stepping can be activated unintentionally: Just before the trigger counter has performed its last incrementation (i.e., the last trigger count was not yet reached), single-stepping is enabled. If however, the trigger address is not passed again within the program flow, single-stepping still remains enabled.

Expand All @@ -53,6 +53,8 @@ End is similar to start. It defines the end point of execution. It has two varia
Address is the address of the end instruction. It needs to be a valid instruction address!
Counter is the amount of executions of the end point. 0 means at the first encounter of the "end" instruction, the program is terminated. If it is 1 it is terminated at the second execution etc. The behaviour is n-1, with n being the number of executions.

Multiple end points can be specified by defining "end" as an array.

**Attention!**
The end point counter is not an absolute value, but relative to the specified "start".
The start of counting depends on if "start" is set or not. If it is set, the end point counter is enabled as soon as the start point is reached. If it is not set, the end point is enabled from the start of the execution of the kernel. This means that as soon as the "start" address in the respective TB has been found, the counter for the end point begins to run. In case of an AES algorithm, where the start was set to round 4, and the end point was set to round 9, the end point counter will start at round 4, thus terminating the plugin tracking at 4+9 rounds. Keep that in mind!
Expand Down
5 changes: 3 additions & 2 deletions faultclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -664,8 +664,9 @@ def configure_qemu(control, config_qemu, num_faults, memorydump_list):
out = out + "$$ start_counter: {}\n".format((config_qemu["start"])["counter"])

if "end" in config_qemu:
out = out + "$$ end_address: {}\n".format((config_qemu["end"])["address"])
out = out + "$$ end_counter: {}\n".format((config_qemu["end"])["counter"])
for end_loc in config_qemu["end"]:
out = out + "$$ end_address: {}\n".format(end_loc["address"])
out = out + "$$ end_counter: {}\n".format(end_loc["counter"])

if memorydump_list is not None:
out = out + "$$num_memregions: {}\n".format(len(memorydump_list))
Expand Down
98 changes: 73 additions & 25 deletions faultplugin/faultplugin.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,12 @@ int tb_counter_max;
fault_trigger_t start_point;

/* End point struct (using fault struct) */
fault_trigger_t end_point;
struct end_point_t
{
fault_trigger_t location;
struct end_point_t *next;
};
struct end_point_t *end_point = NULL;


int tb_info_enabled;
Expand Down Expand Up @@ -111,6 +116,41 @@ int mem_info_list_enabled;

struct avl_table *mem_avl_root;

static void free_end_point_list(struct end_point_t *list)
{
struct end_point_t *cur = list, *tmp;

while (cur != NULL)
{
tmp = cur->next;
free(cur);
cur = tmp;
}
}

static struct end_point_t *get_end_point_tail(struct end_point_t *list,
uint64_t type)
{
struct end_point_t *cur = list;

/* Find entry which flag "type" not set */
while ((cur->location.trignum & type) && cur->next != NULL)
{
cur = cur->next;
}

/* We did not find an empty entry, create a new one */
if (cur->location.trignum & type)
{
cur->next = malloc(sizeof(struct end_point_t));
cur = cur->next;
cur->location.trignum = 0;
cur->next = NULL;
}

return cur;
}

/**
* mem_info_free()
*
Expand Down Expand Up @@ -752,14 +792,15 @@ void plugin_dump_mem_information()
void plugin_end_information_dump(GString *end_reason)
{
int *error = NULL;
if(end_point.trignum == 4)
if(end_point->location.trignum == 4)
{
plugin_write_to_data_pipe("$$$[Endpoint]: 1\n", 17);
}
else
{
plugin_write_to_data_pipe("$$$[Endpoint]: 0\n", 17);
}
free_end_point_list(end_point);
plugin_write_to_data_pipe("$$$[End Reason]:", 16);
plugin_write_to_data_pipe(end_reason->str, end_reason->len);
plugin_write_to_data_pipe("\n", 1);
Expand Down Expand Up @@ -822,13 +863,15 @@ void tb_exec_end_max_event(unsigned int vcpu_index, void *vcurrent)

void tb_exec_end_cb(unsigned int vcpu_index, void *vcurrent)
{
struct end_point_t *end_point = (struct end_point_t *)vcurrent;

if(start_point.trignum != 3)
{
qemu_plugin_outs("[End]: CB called\n");
if(end_point.hitcounter == 0)
if(end_point->location.hitcounter == 0)
{
qemu_plugin_outs("[End]: Reached end point\n");
end_point.trignum = 4;
end_point->location.trignum = 4;

g_autoptr(GString) reason = g_string_new(NULL);
g_string_printf(reason, "endpoint %" PRIu64 "/%" PRIu64,
Expand All @@ -837,7 +880,7 @@ void tb_exec_end_cb(unsigned int vcpu_index, void *vcurrent)

plugin_end_information_dump(reason);
}
end_point.hitcounter--;
end_point->location.hitcounter--;
}
}

Expand Down Expand Up @@ -960,24 +1003,25 @@ static void vcpu_translateblock_translation_event(qemu_plugin_id_t id, struct qe
qemu_plugin_outs(out->str);
handle_tb_translate_data(tb);
check_tb_faulted(tb);
if(end_point.trignum == 3)
for (struct end_point_t *cur = end_point; cur != NULL; cur = cur->next)
{
size_t tb_size = calculate_bytesize_instructions(tb);
qemu_plugin_outs("[End]: Check endpoint\n");
if((tb->vaddr <= end_point.address)&&((tb->vaddr + tb_size) >= end_point.address))
{
for(int i = 0; i < tb->n; i++)
if(cur->location.trignum == 3)
{
size_t tb_size = calculate_bytesize_instructions(tb);
qemu_plugin_outs("[End]: Check endpoint\n");
if((tb->vaddr <= cur->location.address)&&((tb->vaddr + tb_size) >= cur->location.address))
{
struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
if((end_point.address >= qemu_plugin_insn_vaddr(insn))&&(end_point.address < qemu_plugin_insn_vaddr(insn) + qemu_plugin_insn_size(insn)))
for(int i = 0; i < tb->n; i++)
{
/* Trigger address met*/
qemu_plugin_outs("[End]: Inject cb\n");
qemu_plugin_register_vcpu_insn_exec_cb(insn, tb_exec_end_cb, QEMU_PLUGIN_CB_RW_REGS, NULL);
struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
if((cur->location.address >= qemu_plugin_insn_vaddr(insn))&&(cur->location.address < qemu_plugin_insn_vaddr(insn) + qemu_plugin_insn_size(insn)))
{
/* Trigger address met*/
qemu_plugin_outs("[End]: Inject cb\n");
qemu_plugin_register_vcpu_insn_exec_cb(insn, tb_exec_end_cb, QEMU_PLUGIN_CB_RW_REGS, cur);
}
}
}
//qemu_plugin_outs("[End]: Inject cb\n");
//qemu_plugin_register_vcpu_tb_exec_cb(tb, tb_exec_end_cb, QEMU_PLUGIN_CB_RW_REGS, NULL);
}
}
}
Expand Down Expand Up @@ -1093,16 +1137,20 @@ int readout_control_config(GString *conf)
}
if(strstr(conf->str, "end_address: "))
{
struct end_point_t *end_point_p = get_end_point_tail(end_point, 2);

// convert number in string to number
end_point.address = strtoimax(strstr(conf->str, "end_address: ") + 12, NULL, 0);
end_point.trignum = end_point.trignum | 2;
end_point_p->location.address = strtoimax(strstr(conf->str, "end_address: ") + 12, NULL, 0);
end_point_p->location.trignum |= 2;
return 1;
}
if(strstr(conf->str, "end_counter: "))
{
struct end_point_t *end_point_p = get_end_point_tail(end_point, 1);

// convert number in string to number
end_point.hitcounter = strtoimax(strstr(conf->str, "end_counter: ") + 12, NULL, 0);
end_point.trignum = end_point.trignum | 1;
end_point_p->location.hitcounter = strtoimax(strstr(conf->str, "end_counter: ") + 12, NULL, 0);
end_point_p->location.trignum |= 1;
return 1;
}
if(strstr(conf->str, "num_memregions: "))
Expand Down Expand Up @@ -1235,9 +1283,9 @@ int initialise_plugin(GString * out, int argc, char **argv, int architecture)
start_point.hitcounter = 0;
start_point.trignum = 0;
// End point initialization
end_point.address = 0;
end_point.hitcounter = 0;
end_point.trignum = 0;
end_point = malloc(sizeof(struct end_point_t));
end_point->location.trignum = 0;
end_point->next = NULL;

// Init tb_info
tb_info_init();
Expand Down
2 changes: 1 addition & 1 deletion goldenrun.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def run_goldenrun(

for experiment in experiments:
if experiment["type"] == "pre_goldenrun":
goldenrun_config["end"] = config_qemu["start"]
goldenrun_config["end"] = [config_qemu["start"]]
# Set max_insn_count to ridiculous high number to never reach it
goldenrun_config["max_instruction_count"] = 10000000000000

Expand Down

0 comments on commit bf931ab

Please sign in to comment.