📄 exmap.cpp
字号:
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 + -