/**
 * Inject faults in the system.
 * 
 * @param changedBytes - number of bytes changed in within the address range
 * @param changedBits  - number of bits changed (0 (auto)... 8)
 */
void FaultInjector::injectFaults(unsigned long changedBytes,
		uint8_t changedBits) {

	unsigned long addrStart, addrEnd;

	addrStart = getRandomUInt(0, memorySize - 1);
	addrEnd = getRandomUInt(addrStart, memorySize - 1);
	logger.log(" inicial %lu final %lu\t", addrStart, addrEnd);
	injectFaults(addrStart, addrEnd, changedBytes, changedBits);
}
void FaultInjector::generateFaults() {

//	WeatherStation::getInstance()->getLogger()->log("Inserting faults");

	DigitalOut led4(LED4);

	led4 = 1;
	logger.log(" memorySize %hu\t", memorySize);
	injectFaults(DEFAULT_CHANGED_BYTES, DEFAULT_CHANGED_BITS);
	wait(0.5);
	led4 = 0;
}
//  开始进行故障注入,
//  startInjtection是最顶层的故障注入处理模块
//  它会调用injectFaults完成故障注入,
//  而后者则通过读取故障注入表的每一项一次进行故障注入
//
//  startInject的处理流程吐下
//
//  如果是对某个已经存在的进程(依据进程号)进行故障注入,
//  则通过ptrace中断程序的运行, 然后用injectFault读取故障注入表进行故障注入
//
//  如果是对某个可执行程序进行故障注入
//  则先fork启动子进程, 再ptrace中断子进程, 然后用injectFault读取故障注入表进行故障注入
int Injector::startInjection( void )
{
	int iRet;
	int data = 0;

    //inject fault into an existing proces
    /*  内核线程无法进行跟踪
     *  内核线程没有用户空间虚拟地址(mm== NULL, avtive_mm是上一个用户进程的虚拟地址)
     *  因此对内核线程的故障注入需要其他手段
     */
	if( this->m_targetPid > 0 && this->m_exeArguments == NULL && is_kthread(this->m_targetPid))
	{
        dcout <<endl <<"[" <<__FILE__  <<", "<<__LINE__ <<"]--KERNEL THREAD pid = " <<this->m_targetPid <<endl;
		iRet = injectFaults( this->m_targetPid );
		if( iRet != RT_OK )
        {
			writeResult( this->m_targetPid, KT_RUN, 0);	//exit or term
            return RT_FAIL;
        }
		return RT_OK;
	}
    else if( this->m_targetPid > 0 && this->m_exeArguments == NULL )    //  用户进程需要跟踪用户的状态
	{
        dcout <<endl <<"[" <<__FILE__  <<", "<<__LINE__ <<"]--USER PROCESS pid = " <<this->m_targetPid <<endl;

        //设置跟踪进程,等待子进程停止
        //bool ptraceFlag = true;
		childProcess = -1;

        signalPid = this->m_targetPid;		//用于给sigAlrm函数传递进程号
		iRet = ptraceAttach( this->m_targetPid );
		if( iRet == RT_FAIL )
        {
//#ifdef TEST_PTRACE
            //  某些系统内部的进程是无法被跟踪的, 返回信息如下
            //  ptraceAttach error : : Operation not permitted
            //  [          ptrace.cpp,  27] : ptraceAttach error : (29:Illegal seek)
            //  因此我们这里判断, 无法跟踪的进程直接进行注入即可
            //
            //  查看是否可悲跟踪的简单方法 strace -p pid
            if(errno == 29 || errno == 1)
            {
                //ptraceFlag = false;
		        iRet = injectFaults( this->m_targetPid );
		        if( iRet != RT_OK )
                {
                    return RT_FAIL;
                }
			    writeResult( this->m_targetPid, RUN, 0 );	//exit or term
		        return RT_OK;
            }
            else
//#endif
            {
                return RT_FAIL;
            }
        }

		do
        {
			iRet = procMonitor( this->m_targetPid, data );

            if( iRet == RT_FAIL ) { return RT_FAIL; }

        }while( iRet == RUN );

		// should be STOP
		if( iRet != STOP )
		{
            //dbgcout <<"test.." <<endl;
			writeResult( this->m_targetPid, iRet, data );	//exit or term
            return RT_FAIL;
		}
		//  进行故障注入
		iRet = injectFaults( this->m_targetPid );
		if( iRet != RT_OK )
        {
            dbgcout <<"inject error..." <<endl;
            return RT_FAIL;
        }

		//  继续执行
		ptraceCont( this->m_targetPid );

		//  跟踪继续执行后的子进程
        iRet = waitingProcMonitor(this->m_targetPid, data);
        return iRet;
	}
	//inject fault into an excultable program
    else if( this->m_exeArguments != NULL && this->m_targetPid < 0 )
	{

        dcout <<endl <<"["<<__FILE__  <<", "<<__LINE__ <<"]--exe = " <<*(this->m_exeArguments) <<", inject fault into an excultable program" <<endl;
		errno = 0;
		pid_t child = fork();
		if( child < 0 )
		{
			perror("fork");
			return RT_FAIL;
		}
		else if( child == 0 )	/// child
		{
            dcout <<endl <<"["<<__FILE__  <<", "<<__LINE__ <<"]--child pid = " <<getpid( ) <<endl;
#ifdef BUGS
            dcout <<endl <<"BUG002--[" <<__FILE__  <<", " <<__func__ <<", "<<__LINE__ <<"]--exe = " <<this->m_exeArguments[0] <<", address = " <<this->m_exeArguments <<endl;
#endif
			startExe();
			_exit( RT_EXIT );
		}
		else	/// parent
		{
			childProcess = child;
            dcout <<endl <<"["<<__FILE__  <<", "<<__LINE__ <<"]--exe = " <<*(this->m_exeArguments) <<", pid = " <<childProcess <<" inject fault into an excultable program" <<endl;
            //inject fault into physical memory address
#ifdef BUGS     //  BUG_002

            dcout <<endl <<"["<<__FILE__  <<", "<<__LINE__ <<"]--" <<"start inject child process pid = " <<child <<endl;
            //exit(0);
#endif
			iRet = injectFaults(child);
			if( iRet == RT_FAIL ) { cleanup(); }
            iRet = waitingProcMonitor(child, data);

            return iRet;
		}
	}

	cerr << "injection target is wrong" << endl;
	return RT_FAIL;
}