/* * See the dyninst/COPYRIGHT file for copyright information. * * We provide the Paradyn Tools (below described as "Paradyn") * on an AS IS basis, and do not warrant its validity or performance. * We reserve the right to update, modify, or discontinue this * software at any time. We shall have no obligation to supply such * updates or modifications or any other form of support to you. * * By your use of Paradyn, you understand and agree that we (or any * other person or entity with proprietary rights in Paradyn) are * under no obligation to provide either maintenance services, * update services, notices of latent defects, or correction of * defects for Paradyn. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #if !defined(PROCESSSET_H_) #define PROCESSSET_H_ #include #include #include #include #include #include #include "dyntypes.h" #include "PCProcess.h" #include "PCErrors.h" typedef std::multimap int_addressSet; typedef std::set int_threadSet; typedef std::set int_processSet; namespace Dyninst { namespace ProcControlAPI { class ProcessSet; class ThreadSet; class LibraryTrackingSet; class ThreadTrackingSet; class CallStackUnwindingSet; class FollowForkSet; class LWPTrackingSet; class RemoteIOSet; class MemoryUsageSet; class PSetFeatures; class TSetFeatures; typedef dyncompat::shared_ptr ProcessSet_ptr; typedef dyncompat::shared_ptr ThreadSet_ptr; typedef dyncompat::shared_ptr ProcessSet_const_ptr; typedef dyncompat::shared_ptr ThreadSet_const_ptr; /** * AddressSet represents a set of Process/Address pairs. It is used to * denote the address of something that exists across multiple processes. * * AddressSet is like a std::multimap object. * This means that it's easy to operate on the entire set, or to focus on an * Address and operate on each process that shares that Address. * * Unlike a standard multimap, you can't have duplicates of the Address/Process * pairs. In this way it behaves more like a set. * * Iteration over AddressSet is sorted by the Address. So, all Processes * that share an Address will appear together when iterating over the set. **/ class PC_EXPORT AddressSet { private: int_addressSet *iaddrs; friend void dyncompat::checked_delete(AddressSet *) noexcept; friend class ProcessSet; AddressSet(); ~AddressSet(); public: int_addressSet *get_iaddrs() { return iaddrs; } typedef dyncompat::shared_ptr ptr; typedef dyncompat::shared_ptr const_ptr; /** * Create new Address sets **/ static AddressSet::ptr newAddressSet(); static AddressSet::ptr newAddressSet(ProcessSet_const_ptr ps, Dyninst::Address addr); static AddressSet::ptr newAddressSet(Process::const_ptr proc, Dyninst::Address addr); static AddressSet::ptr newAddressSet(ProcessSet_const_ptr ps, std::string library_name, Dyninst::Offset off = 0); //More redundant factories, to work around gcc 4.1 bug static AddressSet::ptr newAddressSet(ProcessSet_ptr ps, Dyninst::Address addr); static AddressSet::ptr newAddressSet(Process::ptr proc, Dyninst::Address addr); static AddressSet::ptr newAddressSet(ProcessSet_ptr ps, std::string library_name, Dyninst::Offset off = 0); /** * Standard iterators methods and container access **/ typedef std::pair value_type; typedef std::multimap::iterator iterator; typedef std::multimap::const_iterator const_iterator; iterator begin(); iterator end(); iterator find(Dyninst::Address a); iterator find(Dyninst::Address a, Process::const_ptr p); const_iterator begin() const; const_iterator end() const; const_iterator find(Dyninst::Address a) const; const_iterator find(Dyninst::Address a, Process::const_ptr p) const; size_t count(Dyninst::Address a) const; size_t size() const; bool empty() const; std::pair insert(Dyninst::Address a, Process::const_ptr p); size_t insert(Dyninst::Address a, ProcessSet_const_ptr ps); std::pair insert(Dyninst::Address a, Process::ptr p); size_t insert(Dyninst::Address a, ProcessSet_ptr ps); void erase(iterator pos); size_t erase(Process::const_ptr p); size_t erase(Dyninst::Address a, Process::const_ptr p); void clear(); /** * Use lower_bound, upper_bound and equal_range to focus on an Address. * For example: * pair range = myset.equal_range(0x1000); * for (AddressSet::iterator i = range.first; i != range.second; i++) { * //Every Process::ptr with address equal to 0x1000 here * } **/ iterator lower_bound(Dyninst::Address a); iterator upper_bound(Dyninst::Address a); std::pair equal_range(Dyninst::Address a); const_iterator lower_bound(Dyninst::Address a) const; const_iterator upper_bound(Dyninst::Address a) const; std::pair equal_range(Dyninst::Address a) const; /** * Return a new set by performing these set operations with another AddressSet **/ AddressSet::ptr set_union(AddressSet::const_ptr pp) const; AddressSet::ptr set_intersection(AddressSet::const_ptr pp) const; AddressSet::ptr set_difference(AddressSet::const_ptr pp) const; }; /** * A ProcessSet is a set of processes. By grouping processes together we can * perform collective operations on the entire set, which may be more effecient * than the equivalent sequential operations. **/ class PC_EXPORT ProcessSet : public dyncompat::enable_shared_from_this { friend class ThreadSet; private: int_processSet *procset; PSetFeatures *features; ProcessSet(); ~ProcessSet(); friend void dyncompat::checked_delete(ProcessSet *) noexcept; public: int_processSet *getIntProcessSet(); //Not for public use typedef dyncompat::shared_ptr ptr; typedef dyncompat::shared_ptr const_ptr; typedef dyncompat::weak_ptr weak_ptr; typedef dyncompat::weak_ptr const_weak_ptr; /** * Create new ProcessSets from existing Process objects **/ static ProcessSet::ptr newProcessSet(); static ProcessSet::ptr newProcessSet(Process::const_ptr p); static ProcessSet::ptr newProcessSet(ProcessSet::const_ptr pp); static ProcessSet::ptr newProcessSet(const std::set &procs); static ProcessSet::ptr newProcessSet(AddressSet::const_iterator, AddressSet::const_iterator); //These non-const factories may seem redundant, but gcc 4.1 gets confused without them static ProcessSet::ptr newProcessSet(Process::ptr p); static ProcessSet::ptr newProcessSet(ProcessSet::ptr pp); static ProcessSet::ptr newProcessSet(const std::set &procs); /** * Create new ProcessSets by attaching/creating new Process objects **/ struct CreateInfo { std::string executable; std::vector argv; std::vector envp; std::map fds; ProcControlAPI::err_t error_ret; //Set on return Process::ptr proc; //Set on return }; static ProcessSet::ptr createProcessSet(std::vector &cinfo); struct AttachInfo { Dyninst::PID pid; std::string executable; ProcControlAPI::err_t error_ret; //Set on return Process::ptr proc; //Set on return }; static ProcessSet::ptr attachProcessSet(std::vector &ainfo); /** * Return a new set by performing these set operations with another set. **/ ProcessSet::ptr set_union(ProcessSet::ptr pp) const; ProcessSet::ptr set_intersection(ProcessSet::ptr pp) const; ProcessSet::ptr set_difference(ProcessSet::ptr pp) const; /** * Iterator and standard set utilities **/ class PC_EXPORT iterator { friend class Dyninst::ProcControlAPI::ProcessSet; private: int_processSet::iterator int_iter; iterator(int_processSet::iterator i); public: Process::ptr operator*() const; bool operator==(const iterator &i) const; bool operator!=(const iterator &i) const; ProcessSet::iterator operator++(); ProcessSet::iterator operator++(int); typedef Process::ptr value_type; typedef int difference_type; typedef Process::ptr *pointer; typedef Process::ptr &reference; typedef std::forward_iterator_tag iterator_category; }; class PC_EXPORT const_iterator { friend class Dyninst::ProcControlAPI::ProcessSet; private: int_processSet::iterator int_iter; const_iterator(int_processSet::iterator i) : int_iter(i) {} public: const_iterator(); ~const_iterator(); const_iterator(const const_iterator&) = default; Process::ptr operator*() const; bool operator==(const const_iterator &i) const; bool operator!=(const const_iterator &i) const; ProcessSet::const_iterator operator++(); ProcessSet::const_iterator operator++(int); typedef Process::ptr value_type; typedef int difference_type; typedef Process::ptr *pointer; typedef Process::ptr &reference; typedef std::forward_iterator_tag iterator_category; }; iterator begin(); iterator end(); iterator find(Process::const_ptr p); iterator find(Dyninst::PID p); const_iterator begin() const; const_iterator end() const; const_iterator find(Process::const_ptr p) const; const_iterator find(Dyninst::PID p) const; bool empty() const; size_t size() const; std::pair insert(Process::const_ptr p); void erase(iterator pos); size_t erase(Process::const_ptr); void clear(); /** * Error management. * * Return the subset of processes that had any error on the last operation, or * group them into subsets based on unique error codes. **/ ProcessSet::ptr getErrorSubset() const; void getErrorSubsets(std::map &err_sets) const; /** * Test state of processes **/ bool anyTerminated() const; bool anyExited() const; bool anyCrashed() const; bool anyDetached() const; bool anyThreadStopped() const; bool anyThreadRunning() const; bool allTerminated() const; bool allExited() const; bool allCrashed() const; bool allDetached() const; bool allThreadsStopped() const; bool allThreadsRunning() const; /** * Create new ProcessSets that are subsets of this set, and only * including processes with the specified state. **/ ProcessSet::ptr getTerminatedSubset() const; ProcessSet::ptr getExitedSubset() const; ProcessSet::ptr getCrashedSubset() const; ProcessSet::ptr getDetachedSubset() const; ProcessSet::ptr getAllThreadRunningSubset() const; ProcessSet::ptr getAnyThreadRunningSubset() const; ProcessSet::ptr getAllThreadStoppedSubset() const; ProcessSet::ptr getAnyThreadStoppedSubset() const; /** * Move all processes in set to specified state **/ bool continueProcs() const; bool stopProcs() const; bool detach(bool leaveStopped = false) const; bool terminate() const; bool temporaryDetach() const; bool reAttach() const; /** * Memory management **/ AddressSet::ptr mallocMemory(size_t size) const; bool mallocMemory(size_t size, AddressSet::ptr location) const; bool freeMemory(AddressSet::ptr addrs) const; /** * Read/Write memory * - Use the AddressSet forms to read/write from the same memory location in each process * - Use the read_t/write_t forms to read/write from different memory locations/sizes in each process * - The AddressSet forms of readMemory need to have their memory free'd by the user. * - The readMemory form that outputs 'std::map &result' groups processes * based on having the same memory contents. **/ struct write_t { void *buffer; Dyninst::Address addr; size_t size; err_t err; bool operator<(const write_t &w) { return (addr < w.addr) && (size < w.size) && (buffer < w.buffer); } }; struct read_t { Dyninst::Address addr; void *buffer; size_t size; err_t err; bool operator<(const read_t &w) { return (addr < w.addr) && (size < w.size) && (buffer < w.buffer); } }; bool readMemory(AddressSet::ptr addr, std::multimap &result, size_t size) const; bool readMemory(AddressSet::ptr addr, std::map &result, size_t size, bool use_checksum = true) const; bool readMemory(std::multimap &addrs) const; bool writeMemory(AddressSet::ptr addr, const void *buffer, size_t size) const; bool writeMemory(std::multimap &addrs) const; /** * Breakpoints **/ bool addBreakpoint(AddressSet::ptr addrs, Breakpoint::ptr bp) const; bool rmBreakpoint(AddressSet::ptr addrs, Breakpoint::ptr bp) const; /** * IRPC * The user may pass multiple IRPCs, which are each posted to their respective processes. * The user may pass a single example IRPC, copies of which are posted to each process and returned. * The user may pass a single example IRPC and an AddressSet. Copies of that IRPC are posted to each * process at the addresses provided. **/ bool postIRPC(const std::multimap &rpcs) const; bool postIRPC(IRPC::ptr irpc, std::multimap *result = NULL) const; bool postIRPC(IRPC::ptr irpc, AddressSet::ptr addrs, std::multimap *result = NULL) const; /** * Perform specific operations. Interface objects will only be returned * on appropriately supported platforms, others will return NULL. **/ LibraryTrackingSet *getLibraryTracking(); ThreadTrackingSet *getThreadTracking(); LWPTrackingSet *getLWPTracking(); FollowForkSet *getFollowFork(); RemoteIOSet *getRemoteIO(); MemoryUsageSet *getMemoryUsage(); const LibraryTrackingSet *getLibraryTracking() const; const ThreadTrackingSet *getThreadTracking() const; const LWPTrackingSet *getLWPTracking() const; const FollowForkSet *getFollowFork() const; const RemoteIOSet *getRemoteIO() const; const MemoryUsageSet *getMemoryUsage() const; }; /** * Return a unique ProcessSet representing every running process. It is an error to try to * manually modify this ProcessSet. Modifications are done automatically by ProcControlAPI * as processes are created and destroyed. **/ ProcessSet::const_ptr getAllProcs(); class PC_EXPORT ThreadSet : public dyncompat::enable_shared_from_this { private: int_threadSet *ithrset; TSetFeatures *features; ThreadSet(); ~ThreadSet(); friend void dyncompat::checked_delete(ThreadSet *) noexcept; public: typedef dyncompat::shared_ptr ptr; typedef dyncompat::shared_ptr const_ptr; typedef dyncompat::weak_ptr weak_ptr; typedef dyncompat::weak_ptr const_weak_ptr; int_threadSet *getIntThreadSet() const; /** * Create a new ThreadSet given existing threads **/ static ThreadSet::ptr newThreadSet(); static ThreadSet::ptr newThreadSet(Thread::ptr thr); static ThreadSet::ptr newThreadSet(const ThreadPool &threadp); static ThreadSet::ptr newThreadSet(const std::set &threads); static ThreadSet::ptr newThreadSet(ProcessSet::ptr ps, bool initial_only = false); /** * Modify current set by performing these set operations with another set. **/ ThreadSet::ptr set_union(ThreadSet::ptr tp) const; ThreadSet::ptr set_intersection(ThreadSet::ptr tp) const; ThreadSet::ptr set_difference(ThreadSet::ptr tp) const; /** * Iterator and standard set utilities **/ class PC_EXPORT iterator { friend class Dyninst::ProcControlAPI::ThreadSet; protected: std::set::iterator int_iter; iterator(int_threadSet::iterator i); public: Thread::ptr operator*(); bool operator==(const iterator &i) const; bool operator!=(const iterator &i) const; ThreadSet::iterator operator++(); ThreadSet::iterator operator++(int); }; class PC_EXPORT const_iterator { friend class Dyninst::ProcControlAPI::ThreadSet; protected: std::set::iterator int_iter; const_iterator(int_threadSet::iterator i); public: const_iterator(); ~const_iterator(); const_iterator(const const_iterator&) = default; Thread::ptr operator*(); bool operator==(const const_iterator &i) const; bool operator!=(const const_iterator &i) const; ThreadSet::const_iterator operator++(); ThreadSet::const_iterator operator++(int); }; iterator begin(); iterator end(); iterator find(Thread::const_ptr p); const_iterator begin() const; const_iterator end() const; const_iterator find(Thread::const_ptr p) const; bool empty() const; size_t size() const; std::pair insert(Thread::const_ptr p); void erase(iterator pos); size_t erase(Thread::const_ptr t); void clear(); /** * Error management. * * Return the subset of threads that had any error on the last operation, or * group them into subsets based on unique error codes. **/ ThreadSet::ptr getErrorSubset() const; void getErrorSubsets(std::map &err_sets) const; /** * Query thread states **/ bool allStopped() const; bool allRunning() const; bool allTerminated() const; bool allSingleStepMode() const; bool allHaveUserThreadInfo() const; bool anyStopped() const; bool anyRunning() const; bool anyTerminated() const; bool anySingleStepMode() const; bool anyHaveUserThreadInfo() const; ThreadSet::ptr getStoppedSubset() const; ThreadSet::ptr getRunningSubset() const; ThreadSet::ptr getTerminatedSubset() const; ThreadSet::ptr getSingleStepSubset() const; ThreadSet::ptr getHaveUserThreadInfoSubset() const; /** * Query user thread info **/ bool getStartFunctions(AddressSet::ptr result) const; bool getStackBases(AddressSet::ptr result) const; bool getTLSs(AddressSet::ptr result) const; /** * Move all threads to a specified state. **/ bool stopThreads() const; bool continueThreads() const; bool setSingleStepMode(bool v) const; /** * Get and set individual registers. * - The getRegister form that outputs 'std::map' groups * processes based on similar return values of registers. **/ bool getRegister(Dyninst::MachRegister reg, std::map &results) const; bool getRegister(Dyninst::MachRegister reg, std::map &results) const; bool setRegister(Dyninst::MachRegister reg, const std::map &vals) const; bool setRegister(Dyninst::MachRegister reg, Dyninst::MachRegisterVal val) const; bool getAllRegisters(std::map &results) const; bool setAllRegisters(const std::map ®_vals) const; /** * IRPC * The user may pass multiple IRPCs, which are posted to their respective threads. * The user may pass a single example IRPC, copies of which are posted to each process and returned. **/ bool postIRPC(const std::multimap &rpcs) const; bool postIRPC(IRPC::ptr irpc, std::multimap *result = NULL) const; /** * Perform specific operations. Interface objects will only be returned * on appropriately supported platforms, others will return NULL. **/ CallStackUnwindingSet *getCallStackUnwinding(); const CallStackUnwindingSet *getCallStackUnwinding() const; }; } } #endif