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

📄 exmap.cpp

📁 内存管理工具Exmap。该工具比 ps 或 top 更精确
💻 CPP
📖 第 1 页 / 共 3 页
字号:
    if (!read_textfile(EXMAP_FILE, lines)) {	warn << "read_page_info - can't read exmap: " << pid << "\n";	return false;    }    list<Page> empty_pagelist;    list<Page> *current_pagelist = NULL;        list<string>::const_iterator it;    for (it = lines.begin(); it != lines.end(); ++it) {        // Lines are either:        // Start a new VMA:        // VMA <vma base as %p> <npages>        // or        // Page info        // <pfn (as %p)> <writable:bool> <swap_entry>	if (it->length() < 3) {	    warn << "read_page_info - short line: " << *it << "\n";	    continue;	}	if (it->substr(0, 3) == "VMA") {	    Address start_addr;	    string token;	    sstr.str(it->substr(4)); // "VMA deadbeef"	    sstr >> hex >> start_addr;	    // Put a (copy of) the empty pagelist in for this address	    page_info[start_addr] = empty_pagelist;	    // And remember where to put the pages	    current_pagelist = &(page_info[start_addr]);	}	else {	    bool writable, resident;	    PageCookie cookie;	    if (!parse_page_line(*it, resident, writable, cookie)) {		warn << "read_page_info - bad page line:" << pid << "\n";		continue;	    }	    if (current_pagelist == NULL) {		warn << "read_page_info: page info line before VMA\n";		continue;	    }	    Page p(cookie, resident, writable);	    current_pagelist->push_back(p);	}    }    return true;}bool LinuxSysInfo::parse_page_line(const string &line,	bool &resident,	bool &writable,	PageCookie &cookie){    stringstream sstr(line);    int i, i_resident;    sstr >> i_resident;    resident = i_resident;    sstr >> i;    writable = i;    sstr >> hex >> cookie;    cookie |= (i_resident << 31);    return true;}std::string LinuxSysInfo::read_cmdline(pid_t pid){    stringstream fname;    list<string> lines;    string cmdline;    fname << "/proc/" << pid << "/cmdline";    if (read_textfile(fname.str(), lines)	&& lines.size() == 1) {	cmdline = lines.front();    }        return cmdline;}bool LinuxSysInfo::read_vmas(const PagePoolPtr &pp,			     pid_t pid,			     list<VmaPtr> &vmas){    vmas.clear();    string mapfile = proc_map_file(pid);    list<string> lines;    if (!read_textfile(mapfile, lines)) {	warn << "read_vmas - can't load maps for: " << pid << "\n";	return false;    }    list<string>::iterator it;    for(it = lines.begin(); it != lines.end(); ++it) {	VmaPtr vma = parse_vma_line(*it);	if (!vma) {	    warn << "read_vmas - can't parse line\n";	    continue;	}	vma->selfptr(vma);	vmas.push_back(vma);    }    return true;}VmaPtr LinuxSysInfo::parse_vma_line(const string &line_arg){    const string ANON_NAME("[anon]");    string line(line_arg);    string perms;    Elf::Address start, end;    off_t offset;    string fname;    string::size_type dashpos;    VmaPtr vma;    string token;        // Break the range into two hex numbers    dashpos = line.find('-');    if (dashpos == string::npos) {	warn << "Can't find dash in VMA line: " << line << "\n";	return vma;    }    line[dashpos] = ' ';        stringstream sstr(line);    sstr >> hex >> start;    sstr >> end;    sstr >> perms;    sstr >> offset;    sstr >> token;    sstr >> token;    sstr >> fname;    if (fname.empty()) {	fname = ANON_NAME;    }    vma.reset(new Vma(start, end, offset, fname));    return vma;}string LinuxSysInfo::proc_map_file(pid_t pid){    stringstream sstr;    sstr << "/proc/" << pid << "/maps";    return sstr.str();}    MapCalculator::MapCalculator(const list<VmaPtr> &vmas,			     FilePoolPtr &file_pool,			     const ProcessPtr &proc): _vmas(vmas), _file_pool(file_pool), _proc(proc){    _maps.clear();}bool MapCalculator::calc_maps(list<MapPtr> &maps){    walk_vma_files();    list<string> fnames = map_keys(_fname_to_vmas);    list<string>::iterator it;    for (it = fnames.begin(); it != fnames.end(); ++it) {	if (!calc_maps_for_file(*it)) {	    warn << "calc_maps: failed to calc for " << *it << "\n";	    return false;	}    }    if (!add_holes()) {	warn << "calc_maps: failed to add hole maps\n";	return false;    }    maps = Map::sort(_maps);    if (!sanity_check(maps)) {	warn << "calc_maps: sanity check failed\n";	return false;    }    return true;}bool MapCalculator::add_holes(){    stringstream pref;    pref << _proc->pid() << " add_holes: ";    list<MapPtr>::iterator map_it;    list<RangePtr> map_ranges;    // this wouldn't require a loop or a (named) helper function in a    // decent language    for (map_it = _maps.begin(); map_it != _maps.end(); ++map_it) {	map_ranges.push_back((*map_it)->mem_range());    }    list<VmaPtr>::iterator vma_it;    list<RangePtr>::iterator hole_it;    RangePtr null_range;    for (vma_it = _vmas.begin(); vma_it != _vmas.end(); ++vma_it) {	VmaPtr &vma = *vma_it;	dbg << pref.str() << "adding holes for vma range"	    << vma->range() << "\n";	list<RangePtr> vma_holes = vma->range()->invert_list(map_ranges);	FilePtr file = _file_pool->get_or_make_file(vma->fname());	for (hole_it = vma_holes.begin();		hole_it != vma_holes.end();		++hole_it) {	    MapPtr map(new Map(vma, *hole_it, null_range));	    _maps.push_back(map);	    file->add_map(map);	    dbg << pref.str() << "adding hole " << map->to_string() << "\n";	}    }    return true;}bool MapCalculator::sanity_check(const list<MapPtr> &maps){    stringstream pref;    pref << _proc->pid() << " sanity_check: ";    list<MapPtr>::const_iterator map_it = maps.begin();    list<VmaPtr>::iterator vma_it = _vmas.begin();    while (vma_it != _vmas.end()) {	VmaPtr &vma = *vma_it;	if ((*map_it)->mem_range()->start() != vma->start()) {	    warn << pref.str() << "map not at start of vma: "		<< (*map_it)->to_string() << " " << vma->to_string() << "\n";	    return false;	}	MapPtr lastmap;	while ((*map_it)->mem_range()->end() < vma->end()) {	    if (!vma->range()->contains((*map_it)->mem_range())) {		warn << pref.str() << "map not contained within vma: "		    << (*map_it)->to_string() << " " << vma->to_string()		    << "\n";		return false;	    }	    ++map_it;	    if (map_it == maps.end()) {		warn << pref.str() << "maps don't cover vma "		    << vma->to_string() << "\n";		return false;	    }	    if (lastmap && lastmap->mem_range()->end() != (*map_it)->mem_range()->start()) {		warn << pref.str() << "maps are not contiguous "		    << lastmap->to_string() << " "		    << (*map_it)->to_string() << "\n";		warn << "----------------------------\n";		for (map_it = maps.begin(); map_it != maps.end(); ++map_it) {		    warn << (*map_it)->to_string() << "\n";		}		warn << "----------------------------\n";		return false;	    }	    lastmap = *map_it;	}	if ((*map_it)->mem_range()->end() != vma->end()) {	    warn << pref.str() << "map doesn't end at end of vma: "		<< (*map_it)->to_string() << " " << vma->to_string() << "\n";	    return false;	}		++vma_it;	++map_it;	if (vma_it != _vmas.end() && map_it == maps.end()) {	    warn << pref.str() << "not enough maps for vmas "		<< vma->to_string() << "\n";	    return false;	}    }    if (map_it != maps.end()) {	warn << pref.str() << "too many maps for vmas\n";	return false;    }    return true;}bool MapCalculator::calc_maps_for_file(const string &fname){    stringstream pref;    pref << _proc->pid() << " " << fname << " calc_maps_for_file: ";    FilePtr file = _file_pool->get_or_make_file(fname);    size_t num_maps_before = _maps.size();    if (file->is_elf()) {	dbg << pref.str() << "elf file\n";	if(!calc_maps_for_elf_file(fname, file)) {	    warn << pref.str() << "failed to calc elf file maps\n";	    return false;	}    }    else {	dbg << pref.str() << "non elf file\n";	if(!calc_maps_for_nonelf_file(fname, file)) {	    warn << pref.str() << "failed to calc nonelf file maps\n";	    return false;	}    }    if (_maps.size() == num_maps_before) {	warn << pref.str() << "no maps added for file\n";	return false;    }    return true;}bool MapCalculator::calc_maps_for_nonelf_file(const string &fname,	const FilePtr &file){    stringstream pref;    pref << _proc->pid() << " " << fname << " calc_maps_for_nonelf_file: ";    list<VmaPtr> filevmas = _fname_to_vmas[fname];    if (filevmas.empty()) {	warn << pref.str() << "no vmas for nonelf file\n";	return false;    }    list <VmaPtr>::const_iterator it;    RangePtr null_range;    for (it = filevmas.begin(); it != filevmas.end(); ++it) {	const VmaPtr &vma = *it;	// filevmas includes any trailing non file backed vmas. we don't	// want them here	if (vma->fname() != fname) {	    continue;	    // not a warning	    dbg << pref.str() << "vma name mismatch "		<< vma->to_string() << "\n";//	    warn << pref.str() << "vma name mismatch "//		<< vma->to_string() << "\n";	}	MapPtr map(new Map(vma, vma->range(), null_range));	_maps.push_back(map);	file->add_map(map);	dbg << pref.str() << "adding nonelf map " << map->to_string() << "\n";    }    return true;}bool MapCalculator::calc_maps_for_elf_file(const string &fname,	const FilePtr &file){    stringstream pref;    pref << _proc->pid() << " " << fname << " calc_maps_for_elf_file: ";    list<Elf::SegmentPtr> segs = file->elf()->loadable_segments();    if (segs.empty()) {	warn << pref.str() << "no loadable segments\n";	return false;    }    list<VmaPtr> filevmas = _fname_to_vmas[fname];    if (filevmas.empty()) {	warn << pref.str() << "no vmas for segment\n";	return false;    }    list<Elf::SegmentPtr>::iterator it;    for (it = segs.begin(); it != segs.end(); ++it) {	if (!calc_map_for_seg(file, *it, filevmas)) {	    warn << pref.str() << "can't calc map for seg\n";	    return false;	}    }    return true;}bool MapCalculator::calc_map_for_seg(const FilePtr &file,	const Elf::SegmentPtr &seg,	list<VmaPtr> &filevmas){    stringstream pref;    string fname = file->name();    pref << _proc->pid() << " " << fname << " calc_map_for_seg: ";    dbg << pref.str() << "calc_map_for_seg\n";    if (filevmas.empty()) {	warn << pref.str() << "empty vma list\n";    }    list<VmaPtr>::const_iterator it;    Address seg_to_mem;    for (it = filevmas.begin(); it != filevmas.end(); ++it) {	const VmaPtr &vma = *it;	if (vma->is_file_backed()) {	    seg_to_mem = get_seg_to_mem(seg, vma);	}	RangePtr seg_mem_range = seg->mem_range()->add(seg_to_mem);	RangePtr working_mrange = seg_mem_range->intersect(*(vma->range()));	if (!working_mrange || working_mrange->size() <= 0) {	    continue;	}	RangePtr elf_mem_range = working_mrange->subtract(seg_to_mem);	MapPtr map(new Map(vma, working_mrange, elf_mem_range));	_maps.push_back(map);	file->add_map(map);	dbg << pref.str() << "adding elf map " << map->to_string() << "\n";    }    filevmas.pop_front();    dbg << pref.str() << "consuming vma\n";    return true;}void MapCalculator::walk_vma_files(){    list<VmaPtr>::iterator it;    string last_file_backed;    for(it = _vmas.begin(); it != _vmas.end(); ++it) {	VmaPtr &vma = *it;	FilePtr file = _file_pool->get_or_make_file(vma->fname());	file->add_proc(_proc);	_proc->add_file(file);	// associate non-file-backed vmas with the last file backed	// one	if (vma->is_file_backed()) {	    last_file_backed = vma->fname();	}	if (!last_file_backed.empty()) {	    _fname_to_vmas[last_file_backed].push_back(vma);	}    }}Elf::Address MapCalculator::get_seg_to_mem(const Elf::SegmentPtr &seg,	const VmaPtr &vma){    Address segmem_base = seg->mem_range()->start() - seg->offset();    Address vmamem_base = vma->start() - vma->offset();    return vmamem_base - segmem_base;}

⌨️ 快捷键说明

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