⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exmap.hpp

📁 内存管理工具Exmap。该工具比 ps 或 top 更精确
💻 HPP
字号:
/* * (c) John Berthels 2005 <jjberthels@gmail.com>. See COPYING for license. */#ifndef _EXMAP_H#define _EXMAP_H#include <list>#include <map>#include <string>#include <vector>#include <set>#include <boost/smart_ptr.hpp>#include <sys/types.h>#include "jutil.hpp"#include "Elf.hpp"namespace Exmap {    typedef unsigned long PageCookie;    // We exclusively pass around class instances via the reference-counted    // boost smart ptr 'shared_ptr'. Forward declare all classes here, we'll    // need most/all of them in method declarations.     class Vma;    typedef boost::shared_ptr<Vma> VmaPtr;    class Map;    typedef boost::shared_ptr<Map> MapPtr;    class Sizes;    typedef boost::shared_ptr<Sizes> SizesPtr;    class Process;    typedef boost::shared_ptr<Process> ProcessPtr;    class File;    typedef boost::shared_ptr<File> FilePtr;    class PagePool;    typedef boost::shared_ptr<PagePool> PagePoolPtr;    class Page;    typedef boost::shared_ptr<Page> PagePtr;    class SysInfo;    typedef boost::shared_ptr<SysInfo> SysInfoPtr;    /// This is the interface to the system to query information    /// about processes (pids, vmas, page info). It's abstract to    /// allow plugging in mock objects for testing (and to help    /// porting).    class SysInfo    {    public:	virtual ~SysInfo();	/// Get a list of pids for which we can read info	virtual std::list<pid_t> accessible_pids() = 0;	/// Check that the system is in a good state (e.g. required	/// kernel modules available, versions, etc).	virtual bool sanity_check() = 0;	/// Read the page info for a pid	virtual bool read_page_info(pid_t pid,				    std::map<Elf::Address,				    std::list<Page> > &pi) = 0;	/// Read cmdline for pid	virtual std::string read_cmdline(pid_t pid) = 0;	/// Read vma list for pid	virtual bool read_vmas(const PagePoolPtr &pp,			       pid_t pid,			       std::list<VmaPtr> &vmas) = 0;    private:    };    /// Concrete implementation of Sysinfo for a Linux system.    class LinuxSysInfo : public SysInfo    {    public:	virtual ~LinuxSysInfo();	virtual std::list<pid_t> accessible_pids();	virtual bool sanity_check();	virtual bool read_page_info(pid_t pid,			    std::map<Elf::Address, std::list<Page> > &pi);	virtual std::string read_cmdline(pid_t pid);	virtual bool read_vmas(const PagePoolPtr &pp,			       pid_t pid,			       std::list<VmaPtr> &vmas);    protected:	/// Parse a single /proc/xxx/maps line and instantiate a vma	/// protected to allow use by mock testing objects.	VmaPtr parse_vma_line(const std::string &line);	/// Parse a single /proc/exmap page line	bool parse_page_line(const std::string &line,		bool &resident,		bool &writable,		PageCookie &cookie);    private:        std::string proc_map_file(pid_t pid);	static const std::string EXMAP_FILE;    };    /// Holds the various measures we can make of a File, Process or    /// ELF memory range. Sizes are measured as doubles, to avoid too much    /// rounding down when calculating the effective values.    /// A static unit/scale may also be set.    class Sizes    {    public:	Sizes();	/// These are the size measures we support. Keep in sync with the	/// Sizes::names[] array.	/// They are ordered by 'usefulness'.	enum Measure {	    EFFECTIVE_RESIDENT = 0,	    EFFECTIVE_MAPPED,	    WRITABLE,	    VM,	    SOLE_MAPPED,	    MAPPED,	    RESIDENT,	    NUM_SIZES,	};		/// Get the value, scaled into the current units	double sval(int which);	/// Get the value	double val(int which);	/// Add to a value	void increase(enum Measure which, double amount);	/// Human readable name for the size	static std::string size_name(int which);	/// Add the values from another set of sizes.	void add(const SizesPtr &other);	/// Set scale factor to 1	static void scale_units();		/// Set scale factor to kbytes	static void scale_kbytes();		/// Set scale factor to mbytes	static void scale_mbytes();	    private:	/// These are the size names	const static std::string names[];	/// The measure values	double _values[NUM_SIZES];	/// Scale starts off as 1	static int _scale_factor;	/// Scale name starts off as empty	static std::string _scale_name;    };    /// Thin class to hold information about a single page    class Page    {    public:	Page(PageCookie cookie, bool resident, bool writable);	bool is_mapped() const;	bool is_resident() const;	bool is_writable() const;	PageCookie cookie() const;	void print(std::ostream &os) const;    private:	PageCookie _cookie;	int _resident : 1;	int _writable : 1;    };        /// Hold information about one process vma (i.e. one line from    /// /proc/xxx/maps).    class Vma    {    public:	Vma(Elf::Address start,	    Elf::Address end,	    off_t offset,	    const std::string &fname);	PagePoolPtr &page_pool();		/// Record that we own these pages	void add_pages(const std::list<Page> &pages);	/// The vma start address	Elf::Address start();	/// The vma end addres	Elf::Address end();	/// For convenience the range of the start/end	RangePtr range();		/// The name of the underlying file (possibly [anon] or other	/// if there is no real file)	std::string fname();	/// The offset of the vma start within the file	/// (not a useful value unless the Vma is file backed)	off_t offset();	/// The length of the VM area	Elf::Address vm_size();	std::string to_string() const;	/// True if the vma is the special page - we generally wish to	/// ignore.	bool is_vdso();		/// True if there is a file backing this VMA (checks the	/// filename for specials like [anon], etc	bool is_file_backed();	std::list<MapPtr> calc_maps(const FilePtr &file,				    const VmaPtr &previous_vma,				    const FilePtr &previous_file,				    pid_t pid);	boost::shared_ptr<Vma> selfptr();	void selfptr(boost::shared_ptr<Vma> &p);	int num_pages();	/// Struct to hold page + overlap info	struct PartialPageInfo	{	    PartialPageInfo(const Page &p,		    Elf::Address b) : page(p), bytes(b) { }	    Page page;	    Elf::Address bytes;	};		/// Get a list of pages which cover the range, together	/// with the per-page size of the overlap with the range	/// (i.e. always page-size except at the start and end)	/// Does a lot of error checking, too.	bool get_pages_for_range(const RangePtr &mrange,				 std::list<PartialPageInfo> &info);	    private:	/// Get the pgnum (index into the page vector) of the given	/// address.	bool addr_to_pgnum(Elf::Address addr, unsigned int &pgnum);		RangePtr _range;	off_t _offset;	std::string _fname;	std::vector<Page> _pages;	boost::weak_ptr<Vma> _selfptr;    };    /// A map represents a range of memory (mem_range) within a    /// vma. Unlike a VMA, it has a single 'meaning' throughout its range.    ///    /// Some maps maintain a 1-1 relationship between 'ELF memory addresses'    /// and "VMA memory addresses". The ELF memory addresses refer to the    /// virtual addresses used within a particular ELF file (the 'file' of    /// the Vma referenced by the map).    ///    /// Note that a Map may actually be outside the Vma to which it refers.     /// This is due to a possibility that the '.bss' section of an ELF    /// Segment may "spill over" into a following VMA.    class Map    {    public:	Map(const VmaPtr &vma,	    const RangePtr &mem_range,	    const RangePtr &elf_range);	/// The VMA memory range of the map	RangePtr mem_range() const;	/// The 'ELF virtual memory' of the map (may be NULL)	RangePtr elf_range() const;	/// Convert an elf-mem-range to a VMA memory range	RangePtr elf_to_mem_range(const RangePtr &elf_range);	/// Return the sizes for the whole Map VMA mem range	SizesPtr sizes_for_mem_range(const PagePoolPtr &pp);	/// Return the sizes for a subrange of the vma mem range	SizesPtr sizes_for_mem_range(const PagePoolPtr &pp,				     const RangePtr &mrange);	/// Represent the map in string form	std::string to_string() const;	/// Write the map to a ostream in string form	void print(std::ostream &os) const;	/// Add up all the sizes for a list of maps	static SizesPtr sum_sizes(const PagePoolPtr &pp,				  const std::list<MapPtr> &maps);	/// Sort a list of MapPtr	static std::list<MapPtr> sort(const std::list<MapPtr> &maplist);    private:	Elf::Address elf_to_mem_offset();	VmaPtr _vma;	RangePtr _mem_range;	RangePtr _elf_range;    };        /// Hold the information about one file.    class File    {    public:	File(const std::string &fname);	std::string name();	/// List of processes which map this file.	std::list<ProcessPtr> procs();	/// List of all maps which refer to this file (over many procs)	std::list<MapPtr> maps();	/// Return the file ELF object if it is an ELF file, null o/w	Elf::FilePtr elf();	/// True if the file is an ELF file.	bool is_elf();	/// Return the sizes for all maps over this file.	SizesPtr sizes();	/// Register a map with this file	void add_map(const MapPtr &map);	/// Register a list of maps with this file	void add_maps(const std::list<MapPtr> &maps);	/// Register a proc with this file	void add_proc(const ProcessPtr &proc);    private:	std::string _fname;	std::list<MapPtr> _maps;	std::set<ProcessPtr> _procs;	Elf::FilePtr _elf;    };    /// Holds all the file objects, indexed by name    class FilePool    {    public:	void clear();	FilePtr name_to_file(const std::string &name);	FilePtr get_or_make_file(const std::string &name);	std::list<FilePtr> files();    private:	std::map<std::string, FilePtr> _files;    };    typedef boost::shared_ptr<FilePool> FilePoolPtr;    /// Hold information regarding each page in use    class PagePool    {    public:	/// Empty the pagepool	void clear();	/// Fetch the usage count of a page	inline int count(const Page &page) {	    return _counts[page.cookie()];	};	/// Increase the count of a page (to 1 if the page is previously	/// unseen).	inline void inc_page_count(const Page &page) {	    _counts[page.cookie()] = _counts[page.cookie()]++;	};	/// Increase the count of a list of pages.	inline void inc_pages_count(const std::list<Page> &pages) {	    std::list<Page>::const_iterator it;	    for (it = pages.begin(); it != pages.end(); ++it) {		inc_page_count(*it);	    }	};    private:	std::map<PageCookie, int> _counts;    };        /// Hold the information about one process.    class Process    {    public:	Process(const PagePoolPtr &pp, pid_t pid);	/// Load the pid-specific information from the sysinfo	bool load(SysInfoPtr &sys_info);	/// True if the process has its own memory region (some kernel threads	/// have pids but no mem).	bool has_mm();	/// The pid	pid_t pid();	/// The process command line	std::string cmdline();	/// The list of files the process maps	std::list<FilePtr> files();	/// The sizes over all the process maps	SizesPtr sizes();	/// The sizes over all the maps associated with a given file	SizesPtr sizes(const FilePtr &file);	/// The sizes over a given elf range associated with a given file	SizesPtr sizes(const FilePtr &file,		       const RangePtr &elf_range);	/// Process the vma info into a collection of maps. Also associates	/// the maps with the files and processes.	bool calculate_maps(FilePoolPtr &file_pool);	/// Todo - private ctors and write a factory method which removes the	/// need for selfptr()	boost::shared_ptr<Process> selfptr();	/// Todo - private ctors and write a factory method which removes the	/// need for selfptr()	void selfptr(boost::shared_ptr<Process> &p);	/// Associate a file with this process	void add_file(const FilePtr &file);	/// Retrieve the page_pool	const PagePoolPtr &page_pool();	/// Write some process info to the ostream	void print(std::ostream &os) const;    private:	void remove_vdso_if_nopages();	boost::weak_ptr<Process> _selfptr;	bool load_page_info(SysInfoPtr &sys_info);	bool find_vma_by_addr(Elf::Address start,			       VmaPtr &current_vma);	std::list<MapPtr> restrict_maps_to_file(const FilePtr &file);	/// The ordered list of vmas read from /proc/xxx/maps.	std::list<VmaPtr> _vmas;	/// The pid of this process.	pid_t _pid;	/// Read from /proc/xxx/cmdline and processed	std::string _cmdline;	std::list<MapPtr> _maps;	std::set<FilePtr> _files;	const PagePoolPtr &_page_pool;    };    /// Hold info about one complete snapshot of process info    class Snapshot    {    public:	/// Ctor requires a source of info	Snapshot(SysInfoPtr &sys_info);		/// Get a list of all processes in the snapshot.	const std::list<ProcessPtr> procs();	/// Get a list of pids of all processes in the snapshot.	const std::list<pid_t> pids();		/// Return number of procs in the snapshot.	inline int num_procs() { return _procs.size(); }		/// Get a process with a particular pid.	const ProcessPtr proc(pid_t pid);	/// Get a list of all files in the snapshot.	const std::list<FilePtr> files();		/// Get a particular file	const FilePtr file(const std::string &fname);		/// Load the snapshot	bool load();    private:	// ----------------------------------------	// Methods	// ----------------------------------------	/// Load the pid list as procs.	bool load_procs(const std::list<pid_t> &pids);	/// Calculate the ELF file->VMA mappings	bool calculate_file_mappings();	// ----------------------------------------	// Data	// ----------------------------------------		/// Map pid -> process. Also store all our processes	std::map<pid_t, ProcessPtr> _procs;		/// Global per-page information	PagePoolPtr _page_pool;	/// Map name -> file. Also store all our files.	FilePoolPtr _file_pool;	/// Source of our information about processes	SysInfoPtr &_sys_info;    };    typedef boost::shared_ptr<Snapshot> SnapshotPtr;    /// Method class to wrap the (complex) calculation of maps within vmas    class MapCalculator    {	public:	    /// Init the calculator. The calculator is per-proc, per vma-list	    MapCalculator(const std::list<VmaPtr> &vmas,		    FilePoolPtr &file_pool,		    const ProcessPtr &proc);	    /// Do the calculation.	    bool calc_maps(std::list<MapPtr> &maps);	private:	    /// Calculate offset from segment virtual addresses to vma addrs	    Elf::Address get_seg_to_mem(const Elf::SegmentPtr &seg,		    const VmaPtr &vma);	    bool calc_maps_for_file(const std::string &fname);	    bool calc_maps_for_elf_file(const std::string &fname,		    const FilePtr &file);	    bool calc_maps_for_nonelf_file(const std::string &fname,		    const FilePtr &file);	    bool calc_map_for_seg(const FilePtr &file,		    const Elf::SegmentPtr &seg,		    std::list<VmaPtr> &vmas);	    bool add_holes();	    bool sanity_check(const std::list<MapPtr> &maps);	    void walk_vma_files();	    std::map<std::string, std::list<Exmap::VmaPtr> > _fname_to_vmas;	    std::list<VmaPtr> _vmas;	    FilePoolPtr _file_pool;	    const ProcessPtr _proc;	    std::list<MapPtr> _maps;    };};std::ostream &operator<<(std::ostream &os, const Exmap::Process &proc);std::ostream &operator<<(std::ostream &os, const Exmap::Map &map);#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -