plugin/tracing: merge full-tracing plugin into generic version
The full-tracing plugin was used in the DSN paper. It additionally traces the data that was accessed/written on a memory access and the contents of some CPU registers. Change-Id: I61f5230699009ce523aba341985b98148160556d
This commit is contained in:
committed by
Gerrit Code Review
parent
cffafa411c
commit
4e8098a636
@ -24,6 +24,8 @@ void GenericTracing::parseOptions() {
|
|||||||
CommandLine &cmd = CommandLine::Inst();
|
CommandLine &cmd = CommandLine::Inst();
|
||||||
CommandLine::option_handle IGNORE = cmd.addOption("", "", Arg::None, "USAGE: fail-client -Wf,[option] -Wf,[option] ... <BochsOptions...>\n\n");
|
CommandLine::option_handle IGNORE = cmd.addOption("", "", Arg::None, "USAGE: fail-client -Wf,[option] -Wf,[option] ... <BochsOptions...>\n\n");
|
||||||
CommandLine::option_handle HELP = cmd.addOption("h", "help", Arg::None, "-h,--help\t Print usage and exit");
|
CommandLine::option_handle HELP = cmd.addOption("h", "help", Arg::None, "-h,--help\t Print usage and exit");
|
||||||
|
|
||||||
|
|
||||||
CommandLine::option_handle ELF_FILE = cmd.addOption("", "elf-file", Arg::Required,
|
CommandLine::option_handle ELF_FILE = cmd.addOption("", "elf-file", Arg::Required,
|
||||||
"--elf-file\t ELF Binary File (default: $FAIL_ELF_PATH)");
|
"--elf-file\t ELF Binary File (default: $FAIL_ELF_PATH)");
|
||||||
CommandLine::option_handle START_SYMBOL = cmd.addOption("s", "start-symbol", Arg::Required,
|
CommandLine::option_handle START_SYMBOL = cmd.addOption("s", "start-symbol", Arg::Required,
|
||||||
@ -37,6 +39,7 @@ void GenericTracing::parseOptions() {
|
|||||||
CommandLine::option_handle TRACE_FILE = cmd.addOption("t", "trace-file", Arg::Required,
|
CommandLine::option_handle TRACE_FILE = cmd.addOption("t", "trace-file", Arg::Required,
|
||||||
"-t,--trace-file\t File to save the execution trace to\n");
|
"-t,--trace-file\t File to save the execution trace to\n");
|
||||||
|
|
||||||
|
CommandLine::option_handle FULL_TRACE = cmd.addOption("", "full-trace", Arg::None, "--full-trace\t Do a full trace (more data, default: off)");
|
||||||
CommandLine::option_handle MEM_SYMBOL = cmd.addOption("m", "memory-symbol", Arg::Required,
|
CommandLine::option_handle MEM_SYMBOL = cmd.addOption("m", "memory-symbol", Arg::Required,
|
||||||
"-m,--memory-symbol\t ELF symbol(s) to trace accesses (without specifiying all mem read/writes are traced)");
|
"-m,--memory-symbol\t ELF symbol(s) to trace accesses (without specifiying all mem read/writes are traced)");
|
||||||
CommandLine::option_handle MEM_REGION = cmd.addOption("M", "memory-region", Arg::Required,
|
CommandLine::option_handle MEM_REGION = cmd.addOption("M", "memory-region", Arg::Required,
|
||||||
@ -155,6 +158,10 @@ void GenericTracing::parseOptions() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cmd[FULL_TRACE]) {
|
||||||
|
this->full_trace = true;
|
||||||
|
}
|
||||||
|
|
||||||
assert(m_elf->getSymbol(start_symbol).isValid());
|
assert(m_elf->getSymbol(start_symbol).isValid());
|
||||||
assert(m_elf->getSymbol(stop_symbol).isValid());
|
assert(m_elf->getSymbol(stop_symbol).isValid());
|
||||||
assert(m_elf->getSymbol(save_symbol).isValid());
|
assert(m_elf->getSymbol(save_symbol).isValid());
|
||||||
@ -165,6 +172,8 @@ void GenericTracing::parseOptions() {
|
|||||||
|
|
||||||
m_log << "state file: " << state_file << std::endl;
|
m_log << "state file: " << state_file << std::endl;
|
||||||
m_log << "trace file: " << trace_file << std::endl;
|
m_log << "trace file: " << trace_file << std::endl;
|
||||||
|
m_log << "full-trace: " << this->full_trace << std::endl;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,6 +192,7 @@ bool GenericTracing::run()
|
|||||||
|
|
||||||
// restrict memory access logging to injection target
|
// restrict memory access logging to injection target
|
||||||
TracingPlugin tp;
|
TracingPlugin tp;
|
||||||
|
tp.setFullTrace(this->full_trace);
|
||||||
|
|
||||||
if (use_memory_map) {
|
if (use_memory_map) {
|
||||||
m_log << "Use restricted memory map for tracing" << std::endl;
|
m_log << "Use restricted memory map for tracing" << std::endl;
|
||||||
|
|||||||
@ -22,6 +22,8 @@ class GenericTracing : public fail::ExperimentFlow {
|
|||||||
bool use_memory_map;
|
bool use_memory_map;
|
||||||
fail::MemoryMap traced_memory_map;
|
fail::MemoryMap traced_memory_map;
|
||||||
|
|
||||||
|
bool full_trace;
|
||||||
|
|
||||||
fail::Logger m_log;
|
fail::Logger m_log;
|
||||||
fail::ElfReader *m_elf;
|
fail::ElfReader *m_elf;
|
||||||
|
|
||||||
@ -29,7 +31,7 @@ public:
|
|||||||
void parseOptions();
|
void parseOptions();
|
||||||
bool run();
|
bool run();
|
||||||
|
|
||||||
GenericTracing() : m_log("GenericTracing", false) {};
|
GenericTracing() : full_trace(false), m_log("GenericTracing", false) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __TRACING_TEST_HPP__
|
#endif // __TRACING_TEST_HPP__
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "sal/SALInst.hpp"
|
#include "sal/SALInst.hpp"
|
||||||
#include "sal/Register.hpp"
|
#include "sal/Register.hpp"
|
||||||
|
#include "sal/Memory.hpp"
|
||||||
#include "sal/Listener.hpp"
|
#include "sal/Listener.hpp"
|
||||||
#include "TracingPlugin.hpp"
|
#include "TracingPlugin.hpp"
|
||||||
|
|
||||||
@ -10,6 +12,8 @@ using namespace fail;
|
|||||||
|
|
||||||
bool TracingPlugin::run()
|
bool TracingPlugin::run()
|
||||||
{
|
{
|
||||||
|
MemoryManager& mm = simulator.getMemoryManager();
|
||||||
|
|
||||||
MemAccessListener ev_mem(ANY_ADDR);
|
MemAccessListener ev_mem(ANY_ADDR);
|
||||||
BPSingleListener ev_step(ANY_ADDR);
|
BPSingleListener ev_step(ANY_ADDR);
|
||||||
BaseListener *ev;
|
BaseListener *ev;
|
||||||
@ -24,6 +28,17 @@ bool TracingPlugin::run()
|
|||||||
ps = new ProtoOStream(m_protoStreamFile);
|
ps = new ProtoOStream(m_protoStreamFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef BUILD_X86
|
||||||
|
size_t ids[] = {RID_CSP, RID_CBP, RID_FLAGS};
|
||||||
|
#else
|
||||||
|
size_t ids[] = {};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Register *regs[sizeof(ids)/sizeof(*ids)];
|
||||||
|
for (unsigned i = 0; i < sizeof(ids)/sizeof(*ids); ++i)
|
||||||
|
regs[i] = simulator.getCPU(0).getRegister(ids[i]);
|
||||||
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
ev = simulator.resume();
|
ev = simulator.resume();
|
||||||
|
|
||||||
@ -66,6 +81,29 @@ bool TracingPlugin::run()
|
|||||||
e.set_accesstype(
|
e.set_accesstype(
|
||||||
(ev_mem.getTriggerAccessType() & MemAccessEvent::MEM_READ) ?
|
(ev_mem.getTriggerAccessType() & MemAccessEvent::MEM_READ) ?
|
||||||
e.READ : e.WRITE);
|
e.READ : e.WRITE);
|
||||||
|
|
||||||
|
/* When we're doing a full trace, we log more data in
|
||||||
|
the case of a memory event */
|
||||||
|
if (m_full_trace) {
|
||||||
|
Trace_Event_Extended &ext = *e.mutable_trace_ext();
|
||||||
|
// Read the accessed data
|
||||||
|
assert(width <= 8);
|
||||||
|
uint64_t data = 0;
|
||||||
|
mm.getBytes(addr, width, &data);
|
||||||
|
ext.set_data(data);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < sizeof(ids)/sizeof(*ids); ++i) {
|
||||||
|
Trace_Event_Extended_Registers *er = ext.add_registers();
|
||||||
|
er->set_id(ids[i]);
|
||||||
|
er->set_value(simulator.getCPU(0).getRegisterContent(regs[i]));
|
||||||
|
if (er->value() <= mm.getPoolSize() - width) {
|
||||||
|
uint32_t value_deref;
|
||||||
|
mm.getBytes(er->value(), 4, &value_deref);
|
||||||
|
er->set_value_deref(value_deref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ps->writeMessage(&e);
|
ps->writeMessage(&e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -42,15 +42,16 @@ private:
|
|||||||
fail::MemoryMap *m_ipMap; //!< instruction address restriction
|
fail::MemoryMap *m_ipMap; //!< instruction address restriction
|
||||||
bool m_memonly; //!< log instructions only if they are memory accesses
|
bool m_memonly; //!< log instructions only if they are memory accesses
|
||||||
bool m_iponly; //!< log instruction addresses only
|
bool m_iponly; //!< log instruction addresses only
|
||||||
|
bool m_full_trace; //!< do a full trace (more information for the events)
|
||||||
|
|
||||||
std::ostream *m_protoStreamFile;
|
std::ostream *m_protoStreamFile;
|
||||||
std::ostream *m_os; //!< ostream to write human-readable trace into
|
std::ostream *m_os; //!< ostream to write human-readable trace into
|
||||||
fail::ProtoOStream *ps;
|
fail::ProtoOStream *ps;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TracingPlugin()
|
TracingPlugin(bool full_trace = false)
|
||||||
: m_memMap(0), m_ipMap(0), m_memonly(false), m_iponly(false),
|
: m_memMap(0), m_ipMap(0), m_memonly(false), m_iponly(false),
|
||||||
m_protoStreamFile(0), m_os(0) { }
|
m_full_trace(full_trace), m_protoStreamFile(0), m_os(0) { }
|
||||||
bool run();
|
bool run();
|
||||||
/**
|
/**
|
||||||
* Restricts tracing to memory addresses listed in this MemoryMap. An
|
* Restricts tracing to memory addresses listed in this MemoryMap. An
|
||||||
@ -75,6 +76,10 @@ public:
|
|||||||
* If invoked with iponly=true, only instruction addresses are logged.
|
* If invoked with iponly=true, only instruction addresses are logged.
|
||||||
*/
|
*/
|
||||||
void setLogIPOnly(bool iponly) { m_iponly = iponly; }
|
void setLogIPOnly(bool iponly) { m_iponly = iponly; }
|
||||||
|
/**
|
||||||
|
* If invoked with fulltrace=true, a extended (full) trace is done.
|
||||||
|
*/
|
||||||
|
void setFullTrace(bool fulltrace) { m_full_trace = fulltrace; }
|
||||||
/**
|
/**
|
||||||
* ostream to trace into (human-readable)
|
* ostream to trace into (human-readable)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,3 +1,21 @@
|
|||||||
|
message Trace_Event_Extended {
|
||||||
|
// data value read/written
|
||||||
|
optional uint64 data = 5;
|
||||||
|
// register contents
|
||||||
|
repeated group Registers = 6 {
|
||||||
|
// register ID
|
||||||
|
required uint32 id = 1;
|
||||||
|
// register value
|
||||||
|
optional uint64 value = 2;
|
||||||
|
// data register points to
|
||||||
|
optional uint32 value_deref = 3;
|
||||||
|
}
|
||||||
|
// selected stack content
|
||||||
|
repeated group Stack = 7 {
|
||||||
|
required uint32 value = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
message Trace_Event {
|
message Trace_Event {
|
||||||
required uint64 ip = 1;
|
required uint64 ip = 1;
|
||||||
optional uint64 memaddr = 2;
|
optional uint64 memaddr = 2;
|
||||||
@ -7,4 +25,7 @@ message Trace_Event {
|
|||||||
WRITE = 2;
|
WRITE = 2;
|
||||||
}
|
}
|
||||||
optional AccessType accesstype = 4;
|
optional AccessType accesstype = 4;
|
||||||
|
|
||||||
|
optional Trace_Event_Extended trace_ext = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
4
tools/dump-trace/Makefile
Normal file
4
tools/dump-trace/Makefile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
all: trace_pb2.py
|
||||||
|
|
||||||
|
trace_pb2.py: ../../src/plugins/tracing/trace.proto
|
||||||
|
protoc --python_out=. --proto_path `dirname $<` $<
|
||||||
@ -6,6 +6,7 @@
|
|||||||
import trace_pb2
|
import trace_pb2
|
||||||
import sys
|
import sys
|
||||||
import struct
|
import struct
|
||||||
|
from gzip import GzipFile
|
||||||
|
|
||||||
if len(sys.argv) != 2:
|
if len(sys.argv) != 2:
|
||||||
print "Usage:", sys.argv[0], "tracefile.pb"
|
print "Usage:", sys.argv[0], "tracefile.pb"
|
||||||
@ -13,14 +14,21 @@ if len(sys.argv) != 2:
|
|||||||
|
|
||||||
trace_event = trace_pb2.Trace_Event()
|
trace_event = trace_pb2.Trace_Event()
|
||||||
|
|
||||||
|
def open_trace(filename):
|
||||||
|
f = open(filename, "rb")
|
||||||
|
if ord(f.read(1)) == 0x1f and ord(f.read(1)) == 0x8b:
|
||||||
|
f.seek(0,0)
|
||||||
|
return GzipFile(fileobj = f)
|
||||||
|
f.seek(0,0)
|
||||||
|
return f
|
||||||
|
|
||||||
try:
|
try:
|
||||||
f = open(sys.argv[1], "rb")
|
f = open_trace(sys.argv[1])
|
||||||
except IOError:
|
except IOError:
|
||||||
print sys.argv[1] + ": Could not open file."
|
print sys.argv[1] + ": Could not open file."
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
while 1:
|
while True:
|
||||||
# Read trace length
|
# Read trace length
|
||||||
try:
|
try:
|
||||||
lengthNO = f.read(4)
|
lengthNO = f.read(4)
|
||||||
@ -40,8 +48,15 @@ while 1:
|
|||||||
if not trace_event.HasField("memaddr"):
|
if not trace_event.HasField("memaddr"):
|
||||||
print "IP {0:x}".format(trace_event.ip)
|
print "IP {0:x}".format(trace_event.ip)
|
||||||
else:
|
else:
|
||||||
print "MEM {0} {1:x} width {2:d} IP {3:x}".format(
|
ext = ""
|
||||||
|
if trace_event.HasField("trace_ext"):
|
||||||
|
ext = "DATA {0:x}".format(trace_event.trace_ext.data)
|
||||||
|
for reg in trace_event.trace_ext.registers:
|
||||||
|
ext += " REG: {0} *{1:x}={2:x}".format(reg.id, reg.value, reg.value_deref)
|
||||||
|
if len(trace_event.trace_ext.stack) > 0:
|
||||||
|
ext += " STACK: " + "".join(["%x"%x for x in trace_event.trace_ext.stack])
|
||||||
|
print "MEM {0} {1:x} width {2:d} IP {3:x} {4}".format(
|
||||||
"R" if trace_event.accesstype == trace_pb2.Trace_Event.READ else "W",
|
"R" if trace_event.accesstype == trace_pb2.Trace_Event.READ else "W",
|
||||||
trace_event.memaddr, trace_event.width, trace_event.ip)
|
trace_event.memaddr, trace_event.width, trace_event.ip, ext)
|
||||||
|
|
||||||
f.close()
|
f.close()
|
||||||
Reference in New Issue
Block a user