DysectAPI::DysectErrorCode Backend::handleTimerActions() { pthread_mutex_lock(&probesPendingActionMutex); if (probesPendingAction.size() > 0) { DYSECTVERBOSE(true, "Handle timer actions"); vector<Probe*>::iterator probeIter = probesPendingAction.begin(); for(;probeIter != probesPendingAction.end(); probeIter++) { Probe* probe = *probeIter; Domain* dom = probe->getDomain(); DYSECTVERBOSE(true, "Sending enqueued actions for timed probe: %x", dom->getId()); probe->sendEnqueuedActions(); if(probe->numWaitingProcs() > 0) { ProcessSet::ptr lprocset = probe->getWaitingProcs(); probe->enableChildren(lprocset); if(probe->getLifeSpan() == fireOnce) probe->disable(lprocset); lprocset->continueProcs(); probe->releaseWaitingProcs(); } } probesPendingAction.clear(); } pthread_mutex_unlock(&probesPendingActionMutex); return OK; }
Process::cb_ret_t Backend::handleTimeEvent() { // Get all subscribed events set<Event*>& events = Time::getTimeSubscribers(); set<Event*>::iterator eventIter = events.begin(); for(;eventIter != events.end(); eventIter++) { Event* event = *eventIter; ProcessSet::ptr procset = ((Time *)event)->getProcset(); ProcessSet::iterator procIter = procset->begin(); if(procset->size() == 0) continue; if(!event || !event->isEnabled(*procIter)) continue; // this is to avoid a race condition where a time event occurs in the middle of iterating through the processes DYSECTVERBOSE(true, "Time event with timeout %d detected on %d processes", ((Time *)event)->getTimeout(), procset->size()); for(;procIter != procset->end(); procIter++) { Process::ptr procPtr = *procIter; if(event && event->isEnabled(procPtr)) { Thread::ptr threadPtr = procPtr->threads().getInitialThread(); Walker *proc = (Walker *)procPtr->getData(); handleEvent(procPtr, threadPtr, event); } } if(event->getOwner()->getLifeSpan() == fireOnce) event->disable(); } return Process::cbDefault; }
bool Probe::staticGroupWaiting() { assert(dom != 0); ProcessSet::ptr procset; dom->getAttached(procset); DYSECTVERBOSE(true, "staticGroupWaiting %d %d", procset->size(), waitingProcs->size()); return (procset->size() <= waitingProcs->size()); }
// XXX: Process scope for signal handlers bool Async::enable(ProcessSet::ptr lprocset) { if(procset) { ProcessSet::ptr origSet = procset; procset = origSet->set_union(lprocset); } else { procset = lprocset; } return enable(); }
bool Location::disable(ProcessSet::ptr lprocset) { assert(owner != 0); if(codeLocations.empty()) { return Err::verbose(true, "No code locations"); } if(!lprocset) { return Err::warn(false, "Process set not present"); } ProcessSet::iterator procIter = lprocset->begin(); for(;procIter != lprocset->end(); procIter++) { Process::ptr procPtr = *procIter; Walker* proc = (Walker*)procPtr->getData(); vector<DysectAPI::CodeLocation*>::iterator locationIter = codeLocations.begin(); for(;locationIter != codeLocations.end(); locationIter++) { DysectAPI::CodeLocation* location = *locationIter; if(!location->addProcLib(proc)) { return Err::warn(false, "Symbol not found in process"); } vector<Dyninst::Address> addrs; if(!location->getAddrs(proc, addrs) || addrs.empty()) { return Err::warn(false, "Addresses for symbol could not be determined"); } // Breakpoint locations at hand for(int i = 0; i < addrs.size() ; i++) { Dyninst::Address addr = addrs[i]; if(!procPtr->rmBreakpoint(addr, bp)) { Err::verbose(false, "Breakpoint not removed! %s", ProcControlAPI::getLastErrorMsg()); } } } } return true; }
ProcessSet::ptr ProcessMgr::filterDetached(ProcessSet::ptr inSet) { if(!inSet) { return inSet; } if(!detached) { return inSet; } return inSet->set_difference(detached); }
DysectAPI::DysectErrorCode Backend::resumeApplication() { ProcessSet::ptr allProcs = ProcessMgr::getAllProcs(); if(!allProcs) { return Err::warn(Error, "Procset not available"); } // Processes might have exited before setup allProcs = ProcessMgr::filterExited(allProcs); if(!allProcs) return OK; if(allProcs->empty()) return OK; if(allProcs->continueProcs()) { return OK; } else { return Err::warn(Error, "Procset could not continue processes"); } }
ProcessSet::ptr ProcessMgr::filterExited(ProcessSet::ptr inSet) { if(!inSet) return inSet; if(inSet->empty()) return inSet; ProcessSet::ptr procs = ProcessSet::newProcessSet(); // Filter out exited processes ProcessSet::iterator procIter = inSet->begin(); for(; procIter != inSet->end(); procIter++) { Process::ptr process = *procIter; if(process->isTerminated() || process->isExited() || process->isCrashed() || process->isDetached()) { continue; } procs->insert(process); } return procs; }
bool ProcessMgr::detachAll() { Err::verbose(true, "Detaching from all!"); if(!allProcs) return true; if(allProcs->size() <= 0) return true; Err::verbose(true, "Filtering set!"); allProcs = filterExited(allProcs); if(!allProcs) return true; if(allProcs->size() <= 0) return true; Err::verbose(true, "Get running set!"); // Continue stopped processes ProcessSet::ptr runningProcs = allProcs->getAnyThreadRunningSubset(); if(runningProcs && (runningProcs->size() > 0)) { Err::verbose(true, "Stopping %d processes...", runningProcs->size()); runningProcs->stopProcs(); Err::verbose(true, "Processes stop done"); } if(allProcs && allProcs->size() > 0) { Err::verbose(true, "Detaching from %d processes...", allProcs->size()); allProcs->temporaryDetach(); } Err::verbose(true, "Done"); return true; }
DysectAPI::DysectErrorCode Backend::pauseApplication() { ProcessSet::ptr allProcs = ProcessMgr::getAllProcs(); if(!allProcs) { return DYSECTWARN(Error, "Procset not available"); } // Processes might have exited before setup allProcs = ProcessMgr::filterExited(allProcs); if(!allProcs) return OK; if(allProcs->empty()) return OK; if(allProcs->stopProcs()) { DYSECTLOG(true, "stop all processes"); return OK; } else { return DYSECTWARN(Error, "Procset could not stop processes"); } }
bool ProcessMgr::detach(ProcessSet::ptr detachedSet) { if(!detachedSet) { return Err::warn(false, "detach from empty detachSet"); } bool ret = detachedSet->temporaryDetach(); if (ret == false) { return Err::warn(false, "detach from detachSet failed: %s", ProcControlAPI::getLastErrorMsg()); } allProcs = allProcs->set_difference(detachedSet); detached = detached->set_union(detachedSet); return true; }
bool Probe::enable(ProcessSet::ptr procset) { assert(event != 0); assert(dom != 0); if(!dom->anyTargetsAttached()) return true; ProcessSet::ptr staticProcs; if(!dom->getAttached(staticProcs)) { return DYSECTWARN(false, "Could not get static process set"); } ProcessSet::ptr affectedProcs = staticProcs->set_intersection(procset); if(affectedProcs->size() <= 0) { return DYSECTVERBOSE(true, "No processes from incoming set attached for probe %lx, staticProcs %d procset %d", dom->getId(), staticProcs->size(), procset->size()); } DYSECTVERBOSE(true, "Enabling probe %lx with dynamic set with %d processes", dom->getId(), affectedProcs->size()); bool result = event->enable(affectedProcs); return result; }
bool Location::enable(ProcessSet::ptr lprocset) { assert(owner != 0); if(codeLocations.empty()) { return Err::verbose(true, "No code locations"); } if(!lprocset) { return Err::warn(false, "Process set not present"); } ProcessSet::iterator procIter = lprocset->begin(); AddressSet::ptr addrset = AddressSet::newAddressSet(); if(lprocset->size() <= 0) { return Err::info(true, "Process set empty!"); } // Find library location for target processes for(;procIter != lprocset->end(); procIter++) { Process::ptr procPtr = *procIter; Walker* proc = (Walker*)procPtr->getData(); vector<DysectAPI::CodeLocation*>::iterator locationIter = codeLocations.begin(); for(;locationIter != codeLocations.end(); locationIter++) { DysectAPI::CodeLocation* location = *locationIter; if(!location->addProcLib(proc)) { return Err::warn(false, "Symbol not found in process"); } vector<Dyninst::Address> addrs; if(!location->getAddrs(proc, addrs) || addrs.empty()) { return Err::warn(false, "Addresses for symbol could not be determined"); } // Breakpoint locations at hand for(int i = 0; i < addrs.size() ; i++) { Dyninst::Address addr = addrs[i]; if(!procPtr->addBreakpoint(addr, bp)) { return Err::verbose(false, "Breakpoint not installed: %s", ProcControlAPI::getLastErrorMsg()); } else { Err::verbose(true, "Breakpoint installed at %lx", addr); } //addrset->insert(addr, procPtr); } //if(addrs.empty()) { // Err::verbose(true, "No addresses"); //} } } //if(addrset->size() <= 0) { // return Err::verbose(true, "Empty address set"); //} //if(!lprocset->addBreakpoint(addrset, nbp)) { // return Err::warn(false, "Could not insert breakpoints!"); //} else { // Err::info(true, "%d breakpoints inserted in %d processes", addrset->size(), lprocset->size()); //} return true; }
Process::cb_ret_t Backend::handleEvent(Dyninst::ProcControlAPI::Process::const_ptr curProcess, Dyninst::ProcControlAPI::Thread::const_ptr curThread, DysectAPI::Event* dysectEvent) { Process::cb_ret_t retState = Process::cbDefault; // Let event know that it was triggered. // Used for event composition Walker* proc = (Walker*)curProcess->getData(); if(!proc) { DYSECTWARN(true, "Missing payload in process object: could not get walker for PID %d", curProcess->getPid()); } else { dysectEvent->triggered(curProcess, curThread); // Find owning probe Probe* probe = dysectEvent->getOwner(); if(!probe) { DYSECTWARN(true, "Probe could not be found for event object"); } else { // If enqueued disabled - stop and await //if(probe->isDisabled(curProcess)) { // probe->addWaitingProc(curProcess); // return Process::cbProcStop; // //return Process::cbDefault; //} // Composed events might require several events being triggered if(probe->wasTriggered(curProcess, curThread)) { // Required events indeed triggered // Evaluate conditions ConditionResult result; DYSECTVERBOSE(true, "Evaluate condition for %d!", curProcess->getPid()); if(probe->evaluateConditions(result, curProcess, curThread) == DysectAPI::OK) { if(result == ResolvedTrue) { DYSECTVERBOSE(true, "Condition satisfied"); Domain* dom = probe->getDomain(); assert(dom != 0); if(dom->getWaitTime() == Wait::inf) { // Block strictly, until all processes have shown up DYSECTVERBOSE(true, "Enqueuing notification for static domain"); probe->enqueueNotifyPacket(); probe->enqueueAction(curProcess, curThread); } else if(dom->getWaitTime() != Wait::NoWait) { if(!DysectAPI::SafeTimer::syncTimerRunning(probe)) { DYSECTVERBOSE(true, "Start timer (%ld) and enqueue: %x", dom->getWaitTime(), dom->getId()); DysectAPI::SafeTimer::startSyncTimer(probe); } else { DYSECTVERBOSE(true, "Timer already running - just enqueue"); } if(probe->doNotify()) { probe->enqueueNotifyPacket(); } probe->enqueueAction(curProcess, curThread); } else { // No-wait probe if(probe->doNotify()) { probe->notifyTriggered(); } probe->triggerAction(curProcess, curThread); } ProcessSet::ptr lprocset; probe->getDomain()->getAttached(lprocset); if(probe->waitForOthers()) { DYSECTVERBOSE(true, "Wait (%ld) for group members %d/%d", dom->getWaitTime(), probe->getProcessCount(), lprocset->size()); probe->addWaitingProc(curProcess); if((dom->getWaitTime() == Wait::inf) && (probe->staticGroupWaiting())) { DYSECTVERBOSE(true, "Sending enqueued notifications"); if(probe->doNotify()) { probe->sendEnqueuedNotifications(); pthread_mutex_lock(&probesPendingActionMutex); probesPendingAction.push_back(probe); pthread_mutex_unlock(&probesPendingActionMutex); } if (Backend::getPendingExternalAction == 0) probe->sendEnqueuedActions(); } retState = Process::cbThreadStop; } else { DYSECTVERBOSE(true, "Enable children for probe %x", dom->getId()); probe->enqueueEnable(curProcess); probe->addWaitingProc(curProcess); retState = Process::cbProcStop; if(probe->getLifeSpan() == fireOnce) { DYSECTVERBOSE(true, "Requesting disablement of probe"); probe->enqueueDisable(curProcess); retState = Process::cbProcStop; } } if(probe->waitForOthers() && (probe->getProcessCount() >= lprocset->size())) { DYSECTVERBOSE(true, "%d/%d group members reported, triggering action", probe->getProcessCount(), lprocset->size()); if (!DysectAPI::SafeTimer::resetSyncTimer(probe)) { DYSECTWARN(false, "Failed to reset timer (%ld) and invoke: %x", dom->getWaitTime(), dom->getId()); } } #if 0 } else if(result == CollectiveResolvable) { // Block process and await resolution of collective operations //probe->addWaitingCond(curProcess, curThread); Err::warn(false, "Condition stalls not yet supported"); Err::verbose(true, "Stopping thread in process %d", curProcess->getPid()); retState = Process::cbProcStop; //retState = Process::cbThreadStop; #endif } else if(result == ResolvedFalse) { if(probe->getLifeSpan() == fireOnce) { DYSECTVERBOSE(true, "Requesting disablement of unresolved probe"); // Get out of the way probe->enqueueDisable(curProcess); retState = Process::cbProcStop; } else { retState = Process::cbProcContinue; } } } else { DYSECTWARN(false, "Could not evaluate conditions for probe"); } } else { retState = Process::cbProcContinue; } } } return retState; }
bool Probe::processRequests() { if(requestQueue.empty()) { return true; } pthread_mutex_lock(&requestQueueMutex); vector<ProbeRequest*> queue = requestQueue; requestQueue.clear(); pthread_mutex_unlock(&requestQueueMutex); ProcessSet::ptr continueSet = ProcessSet::newProcessSet(); // Sort queue deque<ProbeRequest*> sortedQueue; vector<ProbeRequest*>::iterator requestIter = queue.begin(); for(int i = 0; requestIter != queue.end(); requestIter++) { ProbeRequest* request = *requestIter; if(!request) { DYSECTWARN(true, "Invalid request in request queue"); break; } if(request->type == DisableType) { sortedQueue.push_back(request); } else { sortedQueue.push_front(request); } } if (sortedQueue.size() == 0) return true; DYSECTVERBOSE(true, "Handling %d process requests", sortedQueue.size()); deque<ProbeRequest*>::iterator sortedRequestIter = sortedQueue.begin(); for(int i = 0; sortedRequestIter != sortedQueue.end(); sortedRequestIter++) { ProbeRequest* request = *sortedRequestIter; if(!request) { DYSECTWARN(true, "Invalid request in request queue"); break; } DYSECTVERBOSE(true, "processRequests() %d", i++); Probe* probe = request->probe; if(!probe) { DYSECTWARN(false, "Probe not found for disable request!"); break; } ProcessSet::ptr waitingProcs = request->scope; if(waitingProcs && waitingProcs->size() > 0) { DYSECTVERBOSE(true, "Adding %d request processes to %d continue set...", waitingProcs->size(), continueSet->size()); continueSet = continueSet->set_union(waitingProcs); } ProcessSet::ptr operationSet = ProcessSet::newProcessSet(); ProcessSet::ptr stopSet = ProcessSet::newProcessSet(); ProcessSet::ptr scope = request->scope; if(scope && scope->size() > 0) { DYSECTVERBOSE(true, "Adding processes from scope set (%d) to affected procs (%d)", scope->size(), operationSet->size()); operationSet = operationSet->set_union(scope); } // // Filter out detached // operationSet = ProcessMgr::filterDetached(operationSet); stopSet = ProcessMgr::filterDetached(stopSet); DYSECTVERBOSE(true, "%d procs in op set, %d procs in stop set", operationSet->size(), stopSet->size()); // // Stop processes // stopSet = operationSet->getAnyThreadRunningSubset(); if(stopSet && stopSet->size() > 0) { DYSECTVERBOSE(true, "Stopping %d processes", stopSet->size()); stopSet->stopProcs(); } // // Carry out operations // if(operationSet && operationSet->size() > 0) { if(request->type == DisableType) { DYSECTVERBOSE(true, "Disabling %d processes", operationSet->size()); probe->disable(operationSet); } else { DYSECTVERBOSE(true, "Enabling %d processes", operationSet->size()); probe->enableChildren(operationSet); } } // // Processes must be started when all operations have been carried out. // if(operationSet && operationSet->size() > 0) { continueSet = continueSet->set_union(operationSet); } delete(request); } continueSet = ProcessMgr::filterDetached(continueSet); if(continueSet && continueSet->size() > 0) { DYSECTVERBOSE(true, "Continuing %d processes", continueSet->size()); if(continueSet->size() == 1) { ProcessSet::iterator procIter = continueSet->begin(); Process::ptr process = *procIter; DYSECTVERBOSE(true, "Continuing process %d", process->getPid()); } continueSet->continueProcs(); } DYSECTVERBOSE(true, "Done handling requests"); return true; }