Handler::handler_ret_t iRPCPreCallbackHandler::handleEvent(Event::ptr ev) { EventRPC *event = static_cast<EventRPC *>(ev.get()); int_iRPC::ptr rpc = event->getllRPC()->rpc; int_thread::State newstate = rpc->getRestoreToState(); if (newstate == int_thread::none) return ret_success; int_thread *thr = ev->getThread()->llthrd(); thr->getUserState().setState(newstate); return ret_success; }
Handler::handler_ret_t iRPCLaunchHandler::handleEvent(Event::ptr ev) { int_process *proc = ev->getProcess()->llproc(); int_thread *thr = ev->getThread()->llthrd(); int_iRPC::ptr posted_rpc = thr->nextPostedIRPC(); if (!posted_rpc || thr->runningRPC()) return Handler::ret_success; assert(posted_rpc->getState() != int_iRPC::Posted); pthrd_printf("Handling next posted irpc %lu on %d/%d of type %s in state %s\n", posted_rpc->id(), proc->getPid(), thr->getLWP(), posted_rpc->getStrType(), posted_rpc->getStrState()); /** * Check if we've successfully made it to the stopped state. * (There's no longer any work to be done to move from prepping to prepped-- * it all happens in the procstop logic.) **/ if (posted_rpc->getState() == int_iRPC::Prepping) { pthrd_printf("Marking RPC %lu on %d/%d as prepped\n", posted_rpc->id(), proc->getPid(), thr->getLWP()); assert(posted_rpc->isRPCPrepped()); posted_rpc->setState(int_iRPC::Prepped); } std::set<response::ptr> async_resps; /** * Save registers and memory **/ if (posted_rpc->getState() == int_iRPC::Prepped) { pthrd_printf("Saving RPC state on %d/%d\n", proc->getPid(), thr->getLWP()); bool result = posted_rpc->saveRPCState(); if (!result) { pthrd_printf("Failed to save RPC state on %d/%d\n", proc->getPid(), thr->getLWP()); return Handler::ret_error; } } //Wait for async if (posted_rpc->getState() == int_iRPC::Saving) { if (!posted_rpc->checkRPCFinishedSave()) { pthrd_printf("Async, RPC has not finished save\n"); posted_rpc->getPendingResponses(async_resps); proc->handlerPool()->notifyOfPendingAsyncs(async_resps, ev); return Handler::ret_async; } else { posted_rpc->setState(int_iRPC::Saved); } } /** * Write PC register and memory **/ if (posted_rpc->getState() == int_iRPC::Saved) { pthrd_printf("Writing RPC on %d\n", proc->getPid()); bool result = posted_rpc->writeToProc(); if (!result) { pthrd_printf("Failed to write RPC on %d\n", proc->getPid()); return Handler::ret_error; } } //Wait for async if (posted_rpc->getState() == int_iRPC::Writing) { if (!posted_rpc->checkRPCFinishedWrite()) { pthrd_printf("Async, RPC has not finished memory write\n"); posted_rpc->getPendingResponses(async_resps); proc->handlerPool()->notifyOfPendingAsyncs(async_resps, ev); return Handler::ret_async; } else { posted_rpc->setState(int_iRPC::Ready); } } if (posted_rpc->getState() == int_iRPC::Ready) { posted_rpc->runIRPC(); } return Handler::ret_success; }
Handler::handler_ret_t iRPCHandler::handleEvent(Event::ptr ev) { //An RPC has completed, clean-up int_thread *thr = ev->getThread()->llthrd(); int_process *proc = ev->getProcess()->llproc(); EventRPC *event = static_cast<EventRPC *>(ev.get()); int_eventRPC *ievent = event->getInternal(); int_iRPC::ptr rpc = event->getllRPC()->rpc; iRPCMgr *mgr = rpcMgr(); bool isLastRPC = !thr->hasPostedRPCs(); assert(rpc); assert(mgr); assert(rpc->getState() == int_iRPC::Cleaning); // Is this a temporary thread created just for this RPC? bool ephemeral = thr->isRPCEphemeral(); pthrd_printf("Handling RPC %lu completion on %d/%d\n", rpc->id(), proc->getPid(), thr->getLWP()); if ((rpc->getType() == int_iRPC::InfMalloc || rpc->getType() == int_iRPC::Allocation) && !ievent->alloc_regresult) { //Post a request for the return value of the allocation pthrd_printf("Cleaning up allocation RPC\n"); ievent->alloc_regresult = reg_response::createRegResponse(); bool result = proc->plat_collectAllocationResult(thr, ievent->alloc_regresult); if( (long)ievent->alloc_regresult->getResult() < 0){ perr_printf("System call returned value is negative.\n"); assert(0); } assert(result); if(!result) return ret_error; proc->handlerPool()->notifyOfPendingAsyncs(ievent->alloc_regresult, ev); } if (rpc->shouldSaveData() && !ievent->memrestore_response) { //Post a request to restore the memory used by the RPC pthrd_printf("Restoring memory to %lx from %p of size %lu\n", rpc->addr(), rpc->allocation()->orig_data, rpc->allocSize()); assert(rpc->allocation()->orig_data); ievent->memrestore_response = result_response::createResultResponse(); bool result = proc->writeMem(rpc->allocation()->orig_data, rpc->addr(), rpc->allocSize(), ievent->memrestore_response); assert(result); if(!result) return ret_error; } if (rpc->directFree()) { assert(rpc->addr()); thr->llproc()->direct_infFree(rpc->addr()); } if (ephemeral) { // Don't restore registers; instead, kill the thread if there // aren't any other pending iRPCs for it. // We count as an active iRPC... assert(mgr->numActiveRPCs(thr) > 0); if (mgr->numActiveRPCs(thr) == 1) { pthrd_printf("Terminating RPC thread %d\n", thr->getLWP()); thr->terminate(); // CLEANUP on aisle 1 #if defined(os_windows) windows_process *winproc = dynamic_cast<windows_process *>(thr->llproc()); if (winproc) { pthrd_printf("Destroying RPC thread %d\n", thr->getLWP()); winproc->destroyRPCThread(); } #endif } else { pthrd_printf("RPC thread %d has %d active RPCs, parking thread\n", thr->getLWP(), mgr->numActiveRPCs(thr)); // don't do an extra desync here, it's handled by throwEventsBeforeContinue() } } else if (!ievent->regrestore_response && (!ievent->alloc_regresult || ievent->alloc_regresult->isReady())) { //Restore the registers--need to wait for above getreg first ievent->regrestore_response = result_response::createResultResponse(); pthrd_printf("Restoring all registers\n"); bool result = thr->restoreRegsForRPC(isLastRPC, ievent->regrestore_response); assert(result); if(!result) return ret_error; } set<response::ptr> async_pending; ievent->getPendingAsyncs(async_pending); if (!async_pending.empty()) { proc->handlerPool()->notifyOfPendingAsyncs(async_pending, ev); return ret_async; } if (ievent->alloc_regresult) { //Collect and use the return value of the allocation assert(ievent->alloc_regresult->isReady()); Address addr = ievent->alloc_regresult->getResult(); pthrd_printf("Allocation RPC %lu returned memory at %lx\n", rpc->id(), addr); if (rpc->getType() == int_iRPC::Allocation) { rpc->targetAllocation()->addr = addr; } else if (rpc->getType() == int_iRPC::InfMalloc) { rpc->setMallocResult(addr); } } if (rpc->isProcStopRPC()) { pthrd_printf("Restoring RPC state after procstop completion\n"); thr->getIRPCWaitState().restoreStateProc(); thr->getIRPCState().restoreState(); } if (rpc->isMemManagementRPC() || rpc->isInternalRPC()) { //Free memory associated with RPC for future use pthrd_printf("Freeing exec memory at %lx\n", rpc->addr()); proc->freeExecMemory(rpc->addr()); } pthrd_printf("RPC %lu is moving to state finished\n", rpc->id()); thr->clearRunningRPC(); rpc->setState(int_iRPC::Finished); if (rpc->countedSync()) { thr->decSyncRPCCount(); } if (rpc->needsToRestoreInternal()) { rpc->thread()->getInternalState().restoreState(); } if(mgr->numActiveRPCs(thr) == 0) { if (rpc->thread()->getUserRPCState().isDesynced()) rpc->thread()->getUserRPCState().restoreState(); } else { thr->throwEventsBeforeContinue(); } return ret_success; }