From d46b81eb3deea340bc55fb214eaeed4052a2ee96 Mon Sep 17 00:00:00 2001 From: Michael Lenz Date: Wed, 10 Feb 2016 12:15:01 +0100 Subject: [PATCH] GenericTracing/-Experiment: add SDC detection This change adds detection of SDCs to GenericTracing and GenericExperiment via Bochs's I/O port E9. Change-Id: Ie036aa97468b45cad94b6c8f73d1ef2d227547b2 --- .../generic-experiment/experiment.cc | 48 ++++++++++++++++++- .../generic-experiment/experiment.hpp | 6 +++ .../generic-experiment.proto | 4 +- src/experiments/generic-tracing/experiment.cc | 27 +++++++++++ .../generic-tracing/experiment.hpp | 2 + 5 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/experiments/generic-experiment/experiment.cc b/src/experiments/generic-experiment/experiment.cc index 496df53e..680d233f 100644 --- a/src/experiments/generic-experiment/experiment.cc +++ b/src/experiments/generic-experiment/experiment.cc @@ -42,6 +42,23 @@ google::protobuf::Message* GenericExperiment::cb_new_result(ExperimentData* data return result; } +std::vector loadFile(std::string filename) +{ + std::vector data; + FILE *f = fopen(filename.c_str(), "rb"); + if (!f) { + return data; + } + fseek(f, 0, SEEK_END); + long len = ftell(f); + fseek(f, 0, SEEK_SET); + if (len > 0) { + data.resize(len); + fread(&data[0], len, 1, f); + } + fclose(f); + return data; +} void handleEvent(GenericExperimentMessage_Result& result, GenericExperimentMessage_Result_ResultType restype, @@ -95,6 +112,9 @@ bool GenericExperiment::cb_start_experiment() { CommandLine::option_handle TIMEOUT = cmd.addOption("", "timeout", Arg::Required, "--timeout \t Experiment Timeout in uS"); + CommandLine::option_handle E9_FILE = cmd.addOption("", "e9-file", Arg::Required, + "--e9-file FILE \t data logged via port 0xE9 in golden run"); + std::map option_handles; for (std::map::iterator it = end_marker_groups.begin(); @@ -152,6 +172,12 @@ bool GenericExperiment::cb_start_experiment() { } } + if (cmd[E9_FILE]) { + m_log << "enabled logging on port E9 for SDC-detection" << std::endl; + enabled_e9_sol = true; + e9_file = std::string(cmd[E9_FILE].first()->arg); + } + if (cmd[WRITE_MEM_TEXT]) { m_log << "Catch writes to text segment from " << hex << minimal_ip << " to " << maximal_ip << std::endl; enabled_mem_text = true; @@ -229,6 +255,10 @@ bool GenericExperiment::cb_before_resume() { simulator.addListener(*it); } + if (enabled_e9_sol) { + simulator.addFlow(&e9_sol); + } + return true; // everything OK } @@ -238,7 +268,6 @@ void GenericExperiment::cb_after_resume(fail::BaseListener *event) { // Record the crash time result->set_crash_time(simulator.getTimerTicks()); - if (event == &l_timeout) { handleEvent(*result, result->TIMEOUT, m_Timeout); } else if (event == &l_trap) { @@ -258,6 +287,17 @@ void GenericExperiment::cb_after_resume(fail::BaseListener *event) { const ElfSymbol *symbol = listener_to_symbol[event]; handleEvent(*result, result->OK_MARKER, symbol->getAddress()); + // check experiment's data for SDC + if (enabled_e9_sol) { + // compare golden run to experiment + std::vector e9_goldenrun = loadFile(e9_file); + std::string e9_experiment = e9_sol.getOutput(); + if ( ! (e9_experiment.size() == e9_goldenrun.size() + && equal(e9_experiment.begin(), e9_experiment.end(), e9_goldenrun.begin())) ) { + handleEvent(*result, result->SDC, 0); + } + } + } else if (FAIL_marker.find(event) != FAIL_marker.end()) { const ElfSymbol *symbol = listener_to_symbol[event]; handleEvent(*result, result->FAIL_MARKER, symbol->getAddress()); @@ -285,4 +325,10 @@ void GenericExperiment::cb_after_resume(fail::BaseListener *event) { } else { handleEvent(*result, result->UNKNOWN, 0); } + + // remove and reset 0xE9 logger even if this run was not "OK" + if (enabled_e9_sol) { + simulator.removeFlow(&e9_sol); + e9_sol.resetOutput(); + } } diff --git a/src/experiments/generic-experiment/experiment.hpp b/src/experiments/generic-experiment/experiment.hpp index ae63e9bb..81358b0a 100644 --- a/src/experiments/generic-experiment/experiment.hpp +++ b/src/experiments/generic-experiment/experiment.hpp @@ -7,6 +7,7 @@ #include "efw/JobClient.hpp" #include "util/Logger.hpp" #include "util/ElfReader.hpp" +#include "../plugins/serialoutput/SerialOutputLogger.hpp" #include #include #include @@ -19,6 +20,10 @@ class GenericExperiment : public fail::DatabaseExperiment { std::string m_state_dir; + bool enabled_e9_sol; + std::string e9_file; + SerialOutputLogger e9_sol; + bool enabled_mem_text; fail::MemAccessListener l_mem_text; @@ -52,6 +57,7 @@ class GenericExperiment : public fail::DatabaseExperiment { public: GenericExperiment() : DatabaseExperiment("GenericExperiment"), m_state_dir("state"), + e9_sol(0xE9), l_trap(fail::ANY_TRAP), l_timeout(0) { enabled_mem_text = false; enabled_mem_outerspace = false; diff --git a/src/experiments/generic-experiment/generic-experiment.proto b/src/experiments/generic-experiment/generic-experiment.proto index 09b25fc6..9baaf4a4 100644 --- a/src/experiments/generic-experiment/generic-experiment.proto +++ b/src/experiments/generic-experiment/generic-experiment.proto @@ -13,7 +13,7 @@ message GenericExperimentMessage { OK_MARKER = 1; FAIL_MARKER = 2; DETECTED_MARKER = 3; - + GROUP1_MARKER = 4; GROUP2_MARKER = 5; GROUP3_MARKER = 6; @@ -24,6 +24,8 @@ message GenericExperimentMessage { WRITE_TEXTSEGMENT = 10; WRITE_OUTERSPACE = 11; + SDC = 12; + UNKNOWN = 100; } // result type, see above diff --git a/src/experiments/generic-tracing/experiment.cc b/src/experiments/generic-tracing/experiment.cc index 7ce02d6f..4e3f450a 100644 --- a/src/experiments/generic-tracing/experiment.cc +++ b/src/experiments/generic-tracing/experiment.cc @@ -67,6 +67,8 @@ void GenericTracing::parseOptions() { "--serial-port \tListen to a given I/O address (default: 0x3F8)"); CommandLine::option_handle SERIAL_FILE = cmd.addOption("", "serial-file", Arg::Required, "--serial-file \tSave the serial output to file"); + CommandLine::option_handle E9_FILE = cmd.addOption("", "e9-file", Arg::Required, + "--e9-file FILE \tData logged via port 0xE9 is stored in this file"); if (!cmd.parse()) { cerr << "Error parsing arguments." << endl; @@ -228,6 +230,14 @@ void GenericTracing::parseOptions() { serial_file = ""; } + if (cmd[E9_FILE]) { + e9_file = std::string(cmd[E9_FILE].first()->arg); + m_log << "port E9 output is written to: " << e9_file << std::endl; + } else { + e9_file = ""; + } + + if (m_elf != NULL) { m_log << "start/save symbol: " << start_symbol << " 0x" << std::hex << start_address << std::endl; m_log << "stop symbol: " << stop_symbol << " 0x" << std::hex << stop_address << std::endl; @@ -287,6 +297,12 @@ bool GenericTracing::run() simulator.addFlow(&sol); } + SerialOutputLogger e9_sol(0xE9); + if (e9_file != "") { + simulator.addFlow(&e9_sol); + } + + //////////////////////////////////////////////////////////////// // Step 2: Continue to the stop point simulator.addListener(&l_stop_symbol); @@ -314,6 +330,17 @@ bool GenericTracing::run() of_serial.close(); } + if (e9_file != "") { + simulator.removeFlow(&e9_sol); + ofstream of_e9(e9_file.c_str(), ios::out|ios::binary); + if (!of_e9.fail()) { + of_e9 << e9_sol.getOutput(); + } else { + m_log << "failed to write " << e9_file << endl; + } + of_e9.close(); + } + simulator.clearListeners(); simulator.terminate(); diff --git a/src/experiments/generic-tracing/experiment.hpp b/src/experiments/generic-tracing/experiment.hpp index e605cf0b..4b2364e0 100644 --- a/src/experiments/generic-tracing/experiment.hpp +++ b/src/experiments/generic-tracing/experiment.hpp @@ -28,6 +28,8 @@ class GenericTracing : public fail::ExperimentFlow { fail::guest_address_t serial_port; std::string serial_file; + std::string e9_file; + fail::Logger m_log; fail::ElfReader *m_elf;