L4Sys: also trace memory accesses
Change-Id: I20d8fea1f0f6cfee42804296515e50fdabf12f81
This commit is contained in:
@ -30,9 +30,10 @@ using namespace fail;
|
|||||||
|
|
||||||
// Check if configuration dependencies are satisfied:
|
// Check if configuration dependencies are satisfied:
|
||||||
#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) || \
|
#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) || \
|
||||||
|
!defined(CONFIG_EVENT_MEMREAD) || !defined(CONFIG_EVENT_MEMWRITE) || \
|
||||||
!defined(CONFIG_SR_SAVE) || \
|
!defined(CONFIG_SR_SAVE) || \
|
||||||
!defined(CONFIG_EVENT_IOPORT)
|
!defined(CONFIG_EVENT_IOPORT)
|
||||||
#error This experiment needs: breakpoints and I/O port events, \
|
#error This experiment needs: breakpoints, memory accesses, I/O port events, \
|
||||||
save, and restore. Enable these in the configuration.
|
save, and restore. Enable these in the configuration.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -240,24 +241,49 @@ void L4SysExperiment::collectInstructionTrace(fail::BPSingleListener& bp)
|
|||||||
RangeSetInstructionFilter filtering(L4SYS_FILTER);
|
RangeSetInstructionFilter filtering(L4SYS_FILTER);
|
||||||
bp.setWatchInstructionPointer(ANY_ADDR);
|
bp.setWatchInstructionPointer(ANY_ADDR);
|
||||||
|
|
||||||
size_t count = 0, accepted = 0;
|
fail::MemAccessListener ML(ANY_ADDR, MemAccessEvent::MEM_READWRITE);
|
||||||
|
if (!simulator.addListener(&ML)) {
|
||||||
|
log << "did not add memory listener..." << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!simulator.addListener(&bp)) {
|
||||||
|
log << "did not add breakpoint listener..." << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t count = 0, inst_accepted = 0, mem = 0, mem_valid = 0;
|
||||||
|
simtime_t prevtime = 0, currtime;
|
||||||
|
simtime_diff_t deltatime;
|
||||||
map<address_t, unsigned> times_called_map;
|
map<address_t, unsigned> times_called_map;
|
||||||
bool injecting = false;
|
bool injecting = false;
|
||||||
|
|
||||||
ogzstream out("trace.pb");
|
ogzstream out_instr("trace_inst.pb");
|
||||||
ProtoOStream *os = new ProtoOStream(&out);
|
ogzstream out_mem("trace_mem.pb");
|
||||||
|
ProtoOStream *os_instr = new ProtoOStream(&out_instr);
|
||||||
|
ProtoOStream *os_mem = new ProtoOStream(&out_mem);
|
||||||
|
|
||||||
while (bp.getTriggerInstructionPointer() != L4SYS_FUNC_EXIT) {
|
while (bp.getTriggerInstructionPointer() != L4SYS_FUNC_EXIT) {
|
||||||
simulator.addListenerAndResume(&bp);
|
fail::BaseListener *res = simulator.resume();
|
||||||
count++;
|
address_t curr_addr = 0;
|
||||||
//short sanity check
|
|
||||||
address_t curr_addr = bp.getTriggerInstructionPointer();
|
// XXX: See the API problem below!
|
||||||
assert(
|
if (res == &ML) {
|
||||||
curr_addr == simulator.getCPU(0).getInstructionPointer());
|
curr_addr = ML.getTriggerInstructionPointer();
|
||||||
|
simulator.addListener(&ML);
|
||||||
unsigned times_called = times_called_map[curr_addr];
|
++mem;
|
||||||
times_called++;
|
} else if (res == &bp) {
|
||||||
times_called_map[curr_addr] = times_called;
|
curr_addr = bp.getTriggerInstructionPointer();
|
||||||
|
assert(curr_addr == simulator.getCPU(0).getInstructionPointer());
|
||||||
|
simulator.addListener(&bp);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
currtime = simulator.getTimerTicks();
|
||||||
|
deltatime = currtime - prevtime;
|
||||||
|
|
||||||
|
unsigned times_called = times_called_map[curr_addr];
|
||||||
|
++times_called;
|
||||||
|
times_called_map[curr_addr] = times_called;
|
||||||
|
|
||||||
if (curr_addr == L4SYS_FILTER_ENTRY) {
|
if (curr_addr == L4SYS_FILTER_ENTRY) {
|
||||||
injecting = true;
|
injecting = true;
|
||||||
@ -267,36 +293,64 @@ void L4SysExperiment::collectInstructionTrace(fail::BPSingleListener& bp)
|
|||||||
injecting = false;
|
injecting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now check if we want to add the instruction for fault injection
|
if (!injecting or
|
||||||
if (injecting and filtering.isValidInstr(curr_addr,
|
!filtering.isValidInstr(curr_addr, reinterpret_cast<char const*>(calculateInstructionAddress()))) {
|
||||||
reinterpret_cast<char const*>(calculateInstructionAddress()))
|
//log << "connt..." << std::endl;
|
||||||
) {
|
continue;
|
||||||
accepted++;
|
}
|
||||||
|
|
||||||
|
if (res == &ML) {
|
||||||
|
#if 0
|
||||||
|
log << "Memory event IP " << std::hex << ML.getTriggerInstructionPointer()
|
||||||
|
<< " @ " << ML.getTriggerAddress() << "("
|
||||||
|
<< ML.getTriggerAccessType() << "," << ML.getTriggerWidth()
|
||||||
|
<< ")" << std::endl;
|
||||||
|
#endif
|
||||||
|
++mem_valid;
|
||||||
|
|
||||||
|
Trace_Event te;
|
||||||
|
if (deltatime != 0) { te.set_time_delta(deltatime) };
|
||||||
|
te.set_ip(curr_addr);
|
||||||
|
te.set_memaddr(ML.getTriggerAddress());
|
||||||
|
te.set_accesstype( (ML.getTriggerAccessType() & MemAccessEvent::MEM_READ) ? te.READ : te.WRITE );
|
||||||
|
te.set_width(ML.getTriggerWidth());
|
||||||
|
os_mem->writeMessage(&te);
|
||||||
|
} else if (res == &bp) {
|
||||||
|
//log << "breakpoint event" << std::endl;
|
||||||
|
// now check if we want to add the instruction for fault injection
|
||||||
|
++inst_accepted;
|
||||||
|
|
||||||
// 1) The 'old' way of logging instructions -> DEPRECATE soon
|
// 1) The 'old' way of logging instructions -> DEPRECATE soon
|
||||||
TraceInstr new_instr;
|
// BUT: we are currently using the bp_counter stored in this
|
||||||
log << "writing IP " << hex << curr_addr << " counter "
|
// file!
|
||||||
<< dec << times_called << "(" << hex << BX_CPU(0)->cr3 << ")"
|
TraceInstr new_instr;
|
||||||
<< endl;
|
//log << "writing IP " << hex << curr_addr << " counter "
|
||||||
new_instr.trigger_addr = curr_addr;
|
// << dec << times_called << "(" << hex << BX_CPU(0)->cr3 << ")"
|
||||||
new_instr.bp_counter = times_called;
|
// << endl;
|
||||||
|
new_instr.trigger_addr = curr_addr;
|
||||||
|
new_instr.bp_counter = times_called;
|
||||||
|
|
||||||
instr_list_file.write(reinterpret_cast<char*>(&new_instr), sizeof(TraceInstr));
|
instr_list_file.write(reinterpret_cast<char*>(&new_instr), sizeof(TraceInstr));
|
||||||
|
|
||||||
// 2) The 'new' way -> generate Events that can be processed by
|
// 2) The 'new' way -> generate Events that can be processed by
|
||||||
// the generic *-trace tools
|
// the generic *-trace tools
|
||||||
// XXX: need to log CR3 if we want multiple binaries here
|
// XXX: need to log CR3 if we want multiple binaries here
|
||||||
Trace_Event e;
|
Trace_Event e;
|
||||||
e.set_time_delta(1);
|
if (deltatime != 0) { e.set_time_delta(deltatime) };
|
||||||
e.set_ip(curr_addr);
|
e.set_ip(curr_addr);
|
||||||
os->writeMessage(&e);
|
os_instr->writeMessage(&e);
|
||||||
}
|
} else {
|
||||||
|
printf("Unknown res? %p\n", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
//short sanity check
|
||||||
|
//log << "continue..." << std::endl;
|
||||||
}
|
}
|
||||||
log << "saving instructions triggered during normal execution" << endl;
|
log << "saving instructions triggered during normal execution" << endl;
|
||||||
instr_list_file.close();
|
instr_list_file.close();
|
||||||
log << "test function calculation position reached after "
|
log << "test function calculation position reached after "
|
||||||
<< dec << count << " instructions; " << accepted << " accepted" << endl;
|
<< dec << count << " instructions; " << inst_accepted << " accepted" << endl;
|
||||||
|
log << "mem accesses: " << mem << ", valid: " << mem_valid << std::endl;
|
||||||
#else
|
#else
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int ul = 0, kernel = 0;
|
int ul = 0, kernel = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user