BochsController::restore() now recreates a state more expectable from the experiment. The state is now the same that save() leaves behind in its most prominent use case after hitting a breakpoint. This change breaks backwards compatibility with some experiments, see below! Right after a breakpoint on a specific address fired and BochsController::save() was called, another breakpoint on that specific address would not fire again (unless that instruction is executed again later on). Up to this change, the situation after calling BochsController::restore() was different: A breakpoint on that specific address would fire twice. This difference led to the problem that running the tracing plugin after save() would work fine (recording the current instruction once, since3dc752c"tracing: fix loss of first dynamic instruction"), but running it after restore() would record the current instruction *twice*. This change aligns restore()'s behavior to that of save(). The implications for existing experiments, traces and results are: - Existing result data should be not affected at all, as trace.time1/time2 were correct before this change. Nevertheless, the assumption time2-time1 >= instr2-instr1 does not hold for equivalence classes including the first instruction, if the latter was faultily recorded twice (see below). - Existing traces that were recorded after a restore() (with a tracing plugin including the aforementioned commit3dc752c) contain the first instruction twice. An affected trace can be corrected with this command line: dump-trace old.tc | tail -n +2 | convert-trace -f dump -t new.tc - For experiments that record traces after a restore() (such as ecos_kernel_test), nothing changes, as both the tracing and the fast-forwarding before the fault injection now see one instruction event less. - Experiments that record traces after a save(), especially those that rely on the generic-tracing experiment for tracing, now see one instruction event less, before they need to inject their fault. These experiments need to be adjusted, for example dciao-kernelstructs now should use bp.setCounter(injection_instr) instead of bp.setCounter(injection_instr+1). Change-Id: I913bed9f1cad91ed3025f610024d62cfc2b9b11b
48 lines
1.3 KiB
Plaintext
48 lines
1.3 KiB
Plaintext
#ifndef __RESTORE_STATE_AH__
|
|
#define __RESTORE_STATE_AH__
|
|
|
|
#include "config/VariantConfig.hpp"
|
|
#include "config/FailConfig.hpp"
|
|
|
|
#if defined(BUILD_BOCHS) && defined(CONFIG_SR_RESTORE)
|
|
|
|
#include <iostream>
|
|
|
|
#include "bochs.h"
|
|
|
|
#include "../SALInst.hpp"
|
|
|
|
aspect RestoreState {
|
|
pointcut restoreState() = "void bx_sr_after_restore_state()";
|
|
pointcut cpuLoop() = "void defineCPULoopJoinPoint(...)";
|
|
|
|
advice execution (restoreState()) : after ()
|
|
{
|
|
// did the experiment trigger this restore?
|
|
if (fail::restore_bochs_request) {
|
|
fail::restore_bochs_request = false;
|
|
fail::restore_bochs_finished = true;
|
|
}
|
|
}
|
|
|
|
// Make sure the "RestoreState" aspect comes *after* the breakpoint stuff
|
|
// to create a simulator / experiment state very similar to when the state
|
|
// was saved. In an "after" advice this means it must get a *higher*
|
|
// precedence, therefore it's first in the order list.
|
|
advice execution (cpuLoop()) : order ("RestoreState", "Breakpoints");
|
|
|
|
advice execution (cpuLoop()) : after ()
|
|
{
|
|
if (!fail::restore_bochs_finished) {
|
|
return;
|
|
}
|
|
fail::restore_bochs_finished = false;
|
|
std::cout << "[FAIL] Restore finished" << std::endl;
|
|
// TODO: Log-Level?
|
|
fail::simulator.restoreDone();
|
|
}
|
|
};
|
|
|
|
#endif // CONFIG_SR_RESTORE
|
|
#endif // __RESTORE_STATE_AH__
|