📄 exmap.cpp
字号:
/* * (c) John Berthels 2005 <jjberthels@gmail.com>. See COPYING for license. */#include "jutil.hpp"#include "Exmap.hpp"#include "Elf.hpp"#include <sstream>#include <set>#include <ctype.h>#include <sys/types.h>#include <unistd.h>using namespace Exmap;using namespace std;using namespace jutil;using Elf::Address;ostream &operator<<(ostream &os, const Exmap::Process &proc){ proc.print(os); return os;}ostream &operator<<(ostream &os, const Exmap::Map &map){ map.print(os); return os;}// ------------------------------------------------------------Snapshot::Snapshot(SysInfoPtr &sys_info) : _page_pool(new PagePool), _file_pool(new FilePool), _sys_info(sys_info){}const list<ProcessPtr> Snapshot::procs(){ return map_values(_procs);}const list<pid_t> Snapshot::pids(){ return map_keys(_procs);} const ProcessPtr Snapshot::proc(pid_t pid){ ProcessPtr ret; map<pid_t, ProcessPtr>::const_iterator it; it = _procs.find(pid); if (it != _procs.end()) { ret = it->second; } return ret;}const list<FilePtr> Snapshot::files(){ return _file_pool->files();}const FilePtr Snapshot::file(const std::string &fname){ return _file_pool->name_to_file(fname);}bool Snapshot::load(){ list<pid_t> pids = _sys_info->accessible_pids(); if (!_sys_info->sanity_check()) { warn << "Can't get system info\n"; exit(-1); } if (pids.empty()) { warn << "Snapshot::load - can't get pid list\n"; return false; } if (!load_procs(pids)) { warn << "Snapshot::load - failed to load: processe\n"; return false; } if (!calculate_file_mappings()) { warn << "Snapshot::load - failed to load: calculate file mappings\n"; return false; } return true;}bool Snapshot::load_procs(const list<pid_t> &pids){ list<pid_t>::const_iterator it; pid_t mypid = getpid(); _procs.clear(); _page_pool->clear(); for (it = pids.begin(); it != pids.end(); ++it) { if (*it == mypid) { // Don't monitor ourselves continue; } ProcessPtr proc(new Process(_page_pool, *it)); proc->selfptr(proc); if (!proc->load(_sys_info)) { warn << "Snapshot::load_procs - can't load pid " << *it << "\n"; continue; } if (proc->has_mm()) { _procs[*it] = proc; } } return !_procs.empty();}bool Snapshot::calculate_file_mappings(){ list<ProcessPtr>::iterator it; list<ProcessPtr> processes = procs(); for (it = processes.begin(); it != processes.end(); ++it) { if (!(*it)->calculate_maps(_file_pool)) { warn << "Failed to process maps for pid " << (*it)->pid() << "\n"; return false; } } return !_file_pool->files().empty();}// ------------------------------------------------------------void PagePool::clear(){ _counts.clear();}// ------------------------------------------------------------void FilePool::clear(){ _files.clear();}FilePtr FilePool::name_to_file(const string &name){ return _files[name];}FilePtr FilePool::get_or_make_file(const string &name){ map<string, FilePtr>::iterator it; it = _files.find(name); if (it == _files.end()) { FilePtr f(new File(name)); _files[name] = f; it = _files.find(name); } return it->second;}list<FilePtr> FilePool::files(){ return map_values(_files);}// ------------------------------------------------------------Process::Process(const PagePoolPtr &page_pool, pid_t pid) : _pid(pid), _page_pool(page_pool){ }const PagePoolPtr &Process::page_pool(){ return _page_pool;}boost::shared_ptr<Process> Process::selfptr(){ return _selfptr.lock();}void Process::selfptr(boost::shared_ptr<Process> &p){ _selfptr = p;}bool Process::load(SysInfoPtr &sys_info){ _cmdline = sys_info->read_cmdline(_pid); if (_cmdline.empty()) { _cmdline = "[nocmdline]"; } if (!sys_info->read_vmas(_page_pool, _pid, _vmas)) { warn << "Process::load - can't load vmas: " << _pid << "\n"; return false; } // Can't load pages if we don't have any... if (!has_mm()) { return true; } if (!load_page_info(sys_info)) { warn << "Process::load - can't load page info: " << _pid << "\n"; return false; } remove_vdso_if_nopages(); return true;}void Process::remove_vdso_if_nopages(){ stringstream pref; pref << pid() << " remove_vdso_if_nopages: "; list<VmaPtr>::iterator it; for (it = _vmas.begin(); it != _vmas.end(); ++it) { if ((*it)->is_vdso() && (*it)->num_pages() == 0) { dbg << pref.str() << "removing\n"; _vmas.erase(it); return; } }}string Process::cmdline(){ return _cmdline;}list<FilePtr> Process::files(){ list<FilePtr> files(_files.begin(), _files.end()); return files;}pid_t Process::pid(){ return _pid;}SizesPtr Process::sizes(){ return Map::sum_sizes(_page_pool, _maps);}SizesPtr Process::sizes(const FilePtr &file){ list<MapPtr> maps; maps = restrict_maps_to_file(file); return Map::sum_sizes(_page_pool, maps);}SizesPtr Process::sizes(const FilePtr &file, const RangePtr &elf_range){ list<MapPtr> maps; list<MapPtr>::iterator it; maps = restrict_maps_to_file(file); SizesPtr sizes(new Sizes); for (it = maps.begin(); it != maps.end(); ++it) { RangePtr map_elf_range = (*it)->elf_range(); if (map_elf_range) { RangePtr subrange = elf_range->intersect(*map_elf_range); if (subrange) { RangePtr mem_range = (*it)->elf_to_mem_range(subrange); SizesPtr subsizes = (*it)->sizes_for_mem_range(_page_pool, mem_range); if (subsizes) { sizes->add(subsizes); } } } } return sizes;}list<MapPtr> Process::restrict_maps_to_file(const FilePtr &file){ list<MapPtr> result; list<MapPtr> file_maps = file->maps(); list<MapPtr> proc_maps = _maps; file_maps.sort(); proc_maps.sort(); dbg << _pid << ": " << "rmtf " << file->name() << ": " << proc_maps.size() << " procs " << file_maps.size() << " files\n"; while (!file_maps.empty() && !proc_maps.empty()) { if (file_maps.front() == proc_maps.front()) { result.push_back(proc_maps.front()); proc_maps.pop_front(); file_maps.pop_front(); } else if (file_maps.front() < proc_maps.front()) { file_maps.pop_front(); } else { proc_maps.pop_front(); } } if (result.size() == 0) { warn << _pid << ": empty restriction to file " << file->name() << "\n"; } return result;}void Process::add_file(const FilePtr &file){ _files.insert(file);}bool Process::calculate_maps(FilePoolPtr &file_pool){ MapCalculator mc(_vmas, file_pool, selfptr()); return mc.calc_maps(_maps) && !_maps.empty();}bool Process::load_page_info(SysInfoPtr &sys_info){ map<Address, list<Page> > page_info; stringstream pref; pref << pid() << " load_page_info: "; if (!sys_info->read_page_info(_pid, page_info)) { warn << pref.str() << "can't read page info for " << _pid; return false; } map<Address, list<Page> >::iterator pi_it; for (pi_it = page_info.begin(); pi_it != page_info.end(); ++pi_it) { Address start_address = pi_it->first; VmaPtr vma; if (!find_vma_by_addr(start_address, vma)) { // This can happen, a process can alloc whilst we are // running warn << pref.str() << "can't find vma at " << hex << start_address << dec << ": " << _pid << "\n"; continue; } if (pi_it->second.size() == 0) { warn << pref.str() << "VMA with no pages " << start_address << "\n"; } vma->add_pages(pi_it->second); _page_pool->inc_pages_count(pi_it->second); } return true;}bool Process::has_mm(){ return _vmas.size() > 0;}bool Process::find_vma_by_addr(Address start, VmaPtr &vma){ list<VmaPtr>::const_iterator it; for (it = _vmas.begin(); it != _vmas.end(); ++it) { if ((*it)->start() == start) { vma = *it; return true; } } return false;}void Process::print(ostream &os) const{ os << "PID: " << _pid << "\n" << "CMD: " << _cmdline << "\n"; std::list<MapPtr>::const_iterator map_it; for (map_it = _maps.begin(); map_it != _maps.end(); ++map_it) { os << **map_it << "\n"; } os << "\n";}// ------------------------------------------------------------Vma::Vma(Elf::Address start, Elf::Address end, off_t offset, const std::string &fname) : _offset(offset), _fname(fname){ _range = RangePtr(new Range(start, end));}Elf::Address Vma::start() { return _range->start(); }Elf::Address Vma::end() { return _range->end(); }RangePtr Vma::range() { return _range; }std::string Vma::fname() { return _fname; }off_t Vma::offset() { return _offset; }Elf::Address Vma::vm_size() { return _range->size(); }int Vma::num_pages(){ return _pages.size();}boost::shared_ptr<Vma> Vma::selfptr(){ return _selfptr.lock();}void Vma::selfptr(boost::shared_ptr<Vma> &p){ _selfptr = p;} void Vma::add_pages(const list<Page> &pages){ list<Page>::const_iterator it; for (it = pages.begin(); it != pages.end(); ++it) { _pages.push_back(*it); }}bool Vma::is_vdso(){ return fname() == "[vdso]";}bool Vma::is_file_backed(){ string::size_type pos = _fname.length(); if (pos == 0) { warn << "Zero length file name in vma\n"; return false; } // Names like [vdso], [anon], [stack] etc
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -