Example #1
0
void MemoryTracer::onCustomInstruction(S2EExecutionState* state, uint64_t opcode)
{
    if (!OPCODE_CHECK(opcode, MEMORY_TRACER_OPCODE)) {
        return;
    }

    //XXX: remove this mess. Should have a function for extracting
    //info from opcodes.
    opcode >>= 16;
    uint8_t op = opcode & 0xFF;
    opcode >>= 8;


    MemoryTracerOpcodes opc = (MemoryTracerOpcodes)op;
    switch(opc) {
    case Enable:
        enableTracing();
        break;

    case Disable:
        disableTracing();
        break;

    default:
        s2e()->getWarningsStream() << "MemoryTracer: unsupported opcode " << hexval(opc) << '\n';
        break;
    }

}
Example #2
0
void MemoryTracer::onTimer()
{
    if (m_elapsedTics++ < m_timeTrigger) {
        return;
    }

    enableTracing();

    m_timerConnection.disconnect();
}
Example #3
0
void MemoryTracer::initialize()
{

    m_tracer = static_cast<ExecutionTracer*>(s2e()->getPlugin("ExecutionTracer"));
    m_execDetector = static_cast<ModuleExecutionDetector*>(s2e()->getPlugin("ModuleExecutionDetector"));

    //Retrict monitoring to configured modules only
    m_monitorModules = s2e()->getConfig()->getBool(getConfigKey() + ".monitorModules");
    if (m_monitorModules && !m_execDetector) {
        s2e()->getWarningsStream() << "MemoryTracer: The monitorModules option requires ModuleExecutionDetector\n";
        exit(-1);
    }

    //Catch all accesses to the stack
    m_monitorStack = s2e()->getConfig()->getBool(getConfigKey() + ".monitorStack");

    //Catch accesses that are above the specified address
    m_catchAbove = s2e()->getConfig()->getInt(getConfigKey() + ".catchAccessesAbove");
    m_catchBelow = s2e()->getConfig()->getInt(getConfigKey() + ".catchAccessesBelow");

    //Whether or not to include host addresses in the trace.
    //This is useful for debugging, bug yields larger traces
    m_traceHostAddresses = s2e()->getConfig()->getBool(getConfigKey() + ".traceHostAddresses");

    //Check that the current state is actually allowed to write to
    //the object state. Can be useful to debug the engine.
    m_debugObjectStates = s2e()->getConfig()->getBool(getConfigKey() + ".debugObjectStates");

    //Start monitoring after the specified number of seconds
    bool hasTimeTrigger = false;
    m_timeTrigger = s2e()->getConfig()->getInt(getConfigKey() + ".timeTrigger", 0, &hasTimeTrigger);
    m_elapsedTics = 0;

    bool manualMode = s2e()->getConfig()->getBool(getConfigKey() + ".manualTrigger");

    m_monitorMemory = s2e()->getConfig()->getBool(getConfigKey() + ".monitorMemory");
    m_monitorPageFaults = s2e()->getConfig()->getBool(getConfigKey() + ".monitorPageFaults");
    m_monitorTlbMisses  = s2e()->getConfig()->getBool(getConfigKey() + ".monitorTlbMisses");

    s2e()->getDebugStream() << "MonitorMemory: " << m_monitorMemory << 
    " PageFaults: " << m_monitorPageFaults << " TlbMisses: " << m_monitorTlbMisses << '\n';

    if (hasTimeTrigger) {
        m_timerConnection = s2e()->getCorePlugin()->onTimer.connect(
                sigc::mem_fun(*this, &MemoryTracer::onTimer));
    } else if (manualMode) {
        s2e()->getCorePlugin()->onCustomInstruction.connect(
                sigc::mem_fun(*this, &MemoryTracer::onCustomInstruction));
    } else {
        enableTracing();
    }
}
Example #4
0
void MemoryTracer::onCustomInstruction(S2EExecutionState* state, uint64_t opcode)
{
    if (!OPCODE_CHECK(opcode, MEMORY_TRACER_OPCODE)) {
        return;
    }

    uint64_t subfunction = OPCODE_GETSUBFUNCTION(opcode);

    MemoryTracerOpcodes opc = (MemoryTracerOpcodes)subfunction;
    switch(opc) {
    case Enable:
        enableTracing();
        break;

    case Disable:
        disableTracing();
        break;

    default:
        s2e()->getWarningsStream() << "MemoryTracer: unsupported opcode " << hexval(opc) << '\n';
        break;
    }

}
Example #5
0
int main(int argc, char *argv[])
{
    Core *core;
    int option;
    bool enableMemoryDump = false;
    uint32_t memDumpBase = 0;
    uint32_t memDumpLength = 0;
    char *memDumpFilename = NULL;
    size_t memDumpFilenameLen = 0;
    bool verbose = false;
    uint32_t fbWidth = 640;
    uint32_t fbHeight = 480;
    bool blockDeviceOpen = false;
    bool enableFbWindow = false;
    uint32_t totalThreads = 4;
    char *separator;
    uint32_t memorySize = 0x1000000;
    const char *sharedMemoryFile = NULL;
    struct stat st;

    enum
    {
        MODE_NORMAL,
        MODE_COSIMULATION,
        MODE_GDB_REMOTE_DEBUG
    } mode = MODE_NORMAL;

    while ((option = getopt(argc, argv, "f:d:vm:b:t:c:r:s:i:o:")) != -1)
    {
        switch (option)
        {
            case 'v':
                verbose = true;
                break;

            case 'r':
                gScreenRefreshRate = parseNumArg(optarg);
                break;

            case 'f':
                enableFbWindow = true;
                separator = strchr(optarg, 'x');
                if (!separator)
                {
                    fprintf(stderr, "Invalid framebuffer size %s\n", optarg);
                    return 1;
                }

                fbWidth = parseNumArg(optarg);
                fbHeight = parseNumArg(separator + 1);
                break;

            case 'm':
                if (strcmp(optarg, "normal") == 0)
                    mode = MODE_NORMAL;
                else if (strcmp(optarg, "cosim") == 0)
                    mode = MODE_COSIMULATION;
                else if (strcmp(optarg, "gdb") == 0)
                    mode = MODE_GDB_REMOTE_DEBUG;
                else
                {
                    fprintf(stderr, "Unkown execution mode %s\n", optarg);
                    return 1;
                }

                break;

            case 'd':
                // Memory dump, of the form: filename,start,length
                separator = strchr(optarg, ',');
                if (separator == NULL)
                {
                    fprintf(stderr, "bad format for memory dump\n");
                    usage();
                    return 1;
                }

                memDumpFilenameLen = (size_t)(separator - optarg);
                memDumpFilename = (char*) malloc(memDumpFilenameLen + 1);
                strncpy(memDumpFilename, optarg, memDumpFilenameLen);
                memDumpFilename[memDumpFilenameLen] = '\0';
                memDumpBase = parseNumArg(separator + 1);

                separator = strchr(separator + 1, ',');
                if (separator == NULL)
                {
                    fprintf(stderr, "bad format for memory dump\n");
                    usage();
                    return 1;
                }

                memDumpLength = parseNumArg(separator + 1);
                enableMemoryDump = true;
                break;

            case 'b':
                if (openBlockDevice(optarg) < 0)
                    return 1;

                blockDeviceOpen = true;
                break;

            case 'c':
                memorySize = parseNumArg(optarg);
                break;

            case 't':
                totalThreads = parseNumArg(optarg);
                if (totalThreads < 1 || totalThreads > 32)
                {
                    fprintf(stderr, "Total threads must be between 1 and 32\n");
                    return 1;
                }

                break;

            case 's':
                sharedMemoryFile = optarg;
                break;

            case 'i':
                recvInterruptFd = open(optarg, O_RDWR);
                if (recvInterruptFd < 0)
                {
                    perror("main: failed to open receive interrupt pipe");
                    return 1;
                }

                if (fstat(recvInterruptFd, &st) < 0)
                {
                    perror("main: stat failed on receive interrupt pipe");
                    return 1;
                }

                if ((st.st_mode & S_IFMT) != S_IFIFO)
                {
                    fprintf(stderr, "%s is not a pipe\n", optarg);
                    return 1;
                }

                break;

            case 'o':
                sendInterruptFd = open(optarg, O_RDWR);
                if (sendInterruptFd < 0)
                {
                    perror("main: failed to open send interrupt pipe");
                    return 1;
                }

                if (fstat(sendInterruptFd, &st) < 0)
                {
                    perror("main: stat failed on send interrupt pipe");
                    return 1;
                }

                if ((st.st_mode & S_IFMT) != S_IFIFO)
                {
                    fprintf(stderr, "%s is not a pipe\n", optarg);
                    return 1;
                }

                break;

            case '?':
                usage();
                return 1;
        }
    }

    if (optind == argc)
    {
        fprintf(stderr, "No image filename specified\n");
        usage();
        return 1;
    }

    // Don't randomize memory for cosimulation mode, because
    // memory is checked against the hardware model to ensure a match

    core = initCore(memorySize, totalThreads, mode != MODE_COSIMULATION,
                    sharedMemoryFile);
    if (core == NULL)
        return 1;

    if (loadHexFile(core, argv[optind]) < 0)
    {
        fprintf(stderr, "Error reading image %s\n", argv[optind]);
        return 1;
    }

    if (enableFbWindow)
    {
        if (initFramebuffer(fbWidth, fbHeight) < 0)
            return 1;
    }

    switch (mode)
    {
        case MODE_NORMAL:
            if (verbose)
                enableTracing(core);

            setStopOnFault(core, false);
            if (enableFbWindow)
            {
                while (executeInstructions(core, ALL_THREADS, gScreenRefreshRate))
                {
                    updateFramebuffer(core);
                    pollFbWindowEvent();
                    checkInterruptPipe(core);
                }
            }
            else
            {
                while (executeInstructions(core, ALL_THREADS, 1000000))
                    checkInterruptPipe(core);
            }

            break;

        case MODE_COSIMULATION:
            setStopOnFault(core, false);
            if (runCosimulation(core, verbose) < 0)
                return 1;	// Failed

            break;

        case MODE_GDB_REMOTE_DEBUG:
            setStopOnFault(core, true);
            remoteGdbMainLoop(core, enableFbWindow);
            break;
    }

    if (enableMemoryDump)
        writeMemoryToFile(core, memDumpFilename, memDumpBase, memDumpLength);

    dumpInstructionStats(core);
    if (blockDeviceOpen)
        closeBlockDevice();

    if (stoppedOnFault(core))
        return 1;

    return 0;
}
// Read events from standard in.  Step each emulator thread in lockstep
// and ensure the side effects match.
int runCosimulation(Core *core, bool verbose)
{
	char line[1024];
	uint32_t threadId;
	uint32_t address;
	uint32_t pc;
	uint64_t writeMask;
	uint32_t vectorValues[NUM_VECTOR_LANES];
	char valueStr[256];
	uint32_t reg;
	uint32_t scalarValue;
	bool verilogModelHalted = false;
	unsigned long len;

	enableCosimulation(core);
	if (verbose)
		enableTracing(core);

	while (fgets(line, sizeof(line), stdin))
	{
		if (verbose)
			printf("%s", line);

		len = strlen(line);
		if (len > 0)
			line[len - 1] = '\0';	// Strip off newline

		if (sscanf(line, "store %x %x %x %" PRIx64 " %s", &pc, &threadId, &address, &writeMask, valueStr) == 5)
		{
			// Memory Store
			if (parseHexVector(valueStr, vectorValues, true) < 0)
				return 0;

			cosimCheckEvent = EVENT_MEM_STORE;
			cosimCheckPc = pc;
			cosimCheckThread = threadId;
			cosimCheckAddress = address;
			cosimCheckMask = writeMask;
			memcpy(cosimCheckValues, vectorValues, sizeof(uint32_t) * NUM_VECTOR_LANES);
	
			if (!cosimStep(core, threadId))
				return -1;
		} 
		else if (sscanf(line, "vwriteback %x %x %x %" PRIx64 " %s", &pc, &threadId, &reg, &writeMask, valueStr) == 5)
		{
			// Vector writeback
			if (parseHexVector(valueStr, vectorValues, false) < 0)
			{
				printf("test failed\n");
				return 0;
			}

			cosimCheckEvent = EVENT_VECTOR_WRITEBACK;
			cosimCheckPc = pc;
			cosimCheckThread = threadId;
			cosimCheckRegister = reg;
			cosimCheckMask = writeMask;
			memcpy(cosimCheckValues, vectorValues, sizeof(uint32_t) * NUM_VECTOR_LANES);
	
			if (!cosimStep(core, threadId))
				return -1;
		}
		else if (sscanf(line, "swriteback %x %x %x %x", &pc, &threadId, &reg, &scalarValue) == 4)
		{
			// Scalar Writeback
			cosimCheckEvent = EVENT_SCALAR_WRITEBACK;
			cosimCheckPc = pc;
			cosimCheckThread = threadId;
			cosimCheckRegister = reg;
			cosimCheckValues[0] = scalarValue;

			if (!cosimStep(core, threadId))
				return -1;
		}
		else if (strcmp(line, "***HALTED***") == 0)
		{
			verilogModelHalted = true;
			break;
		}
		else if (sscanf(line, "interrupt %d %x", &threadId, &pc) == 2)
			cosimInterrupt(core, threadId, pc);
		else if (!verbose)
			printf("%s\n", line);	// Echo unrecognized lines to stdout (verbose already does this for all lines)
	}

	if (!verilogModelHalted)
	{
		printf("program did not finish normally\n");
		printf("%s\n", line);	// Print error (if any)
		return -1;
	}

	// Ensure emulator is also halted. If it executes any more instructions
	// cosimError will be flagged.
	cosimEventTriggered = false;
	cosimCheckEvent = EVENT_NONE;
	while (!coreHalted(core))
	{
		executeInstructions(core, ALL_THREADS, 1);
		if (cosimError)
			return -1;
	}

	return 0;
}
Example #7
0
// Read events from standard in.  Step each emulator thread in lockstep
// and ensure the side effects match.
// Returns 1 if successful, 0 if there was an error
int runCosimulation(Core *core, int verbose)
{
	char line[1024];
	int threadId;
	uint32_t address;
	uint32_t pc;
	uint64_t writeMask;
	uint32_t vectorValues[16];
	char valueStr[256];
	int reg;
	uint32_t scalarValue;
	int verilogModelHalted = 0;
	int len;

	enableCosimulation(core, 1);
	if (verbose)
		enableTracing(core);

	while (fgets(line, sizeof(line), stdin))
	{
		if (verbose)
			printf("%s", line);

		len = strlen(line);
		if (len > 0)
			line[len - 1] = '\0';	// Strip off newline

		if (sscanf(line, "store %x %x %x %llx %s", &pc, &threadId, &address, &writeMask, valueStr) == 5)
		{
			// Memory Store
			if (!parseHexVector(valueStr, vectorValues, 1))
				return 0;

			cosimCheckEvent = kEventMemStore;
			cosimCheckPc = pc;
			cosimCheckThread = threadId;
			cosimCheckAddress = address;
			cosimCheckMask = writeMask;
			memcpy(cosimCheckValues, vectorValues, sizeof(uint32_t) * 16);
	
			if (!cosimStep(core, threadId))
				return 0;
		} 
		else if (sscanf(line, "vwriteback %x %x %x %llx %s", &pc, &threadId, &reg, &writeMask, valueStr) == 5)
		{
			// Vector writeback
			if (!parseHexVector(valueStr, vectorValues, 0))
			{
				printf("test failed\n");
				return 0;
			}

			cosimCheckEvent = kEventVectorWriteback;
			cosimCheckPc = pc;
			cosimCheckThread = threadId;
			cosimCheckRegister = reg;
			cosimCheckMask = writeMask;
			memcpy(cosimCheckValues, vectorValues, sizeof(uint32_t) * 16);
	
			if (!cosimStep(core, threadId))
				return 0;
		}
		else if (sscanf(line, "swriteback %x %x %x %x", &pc, &threadId, &reg, &scalarValue) == 4)
		{
			// Scalar Writeback
			cosimCheckEvent = kEventScalarWriteback;
			cosimCheckPc = pc;
			cosimCheckThread = threadId;
			cosimCheckRegister = reg;
			cosimCheckValues[0] = scalarValue;

			if (!cosimStep(core, threadId))
				return 0;
		}
		else if (strcmp(line, "***HALTED***") == 0)
		{
			// Note: we don't check that the reference model is actually verilogModelHalted
			verilogModelHalted = 1;
			break;
		}
		else if (sscanf(line, "interrupt %d %x", &threadId, &pc) == 2)
			cosimInterrupt(core, threadId, pc);
		else if (!verbose)
			printf("%s\n", line);	// Echo unrecognized lines to stdout (verbose already does this for all lines)
	}

	if (!verilogModelHalted)
	{
		printf("program did not finish normally\n");
		printf("%s\n", line);	// Print error (if any)
		return 0;
	}

	// Ensure emulator is also halted. If it executes any more instructions
	// cosimError will be flagged.
	cosimEventTriggered = 0;
	cosimCheckEvent = kEventNone;
	while (!coreHalted(core))
	{
		executeInstructions(core, -1, 1);
		if (cosimError)
			return 0;
	}

	return 1;
}