#include #include #include #include #include using namespace std; void MemoryMap::MapEntry::dump(ostream& os) const { os << "MapEntry: " << hex << mem_region.begin << '-' << mem_region.end << " offset " << hex << offset << dec << " - <" << pathname << ">" << endl; } MemoryMap::MemoryMap() { int pid = getpid(); ostringstream path; path << "/proc/" << pid << "/maps"; ifstream handle(path.str()); if(handle.fail()) throw ReadMapFailed(); string line; while(getline(handle, line).good()) { istringstream lstream(line); MapEntry entry; uintptr_t discard; /* Line format: * ============ * (cf man 5 proc for details) * * beg_addr-end_addr [perms] offset [dev] [inode] pathname * [x]: x, ignored here. */ lstream >> std::hex; lstream >> entry.mem_region.begin; // beg_addr lstream.ignore(1); // ignore `-` lstream >> entry.mem_region.end; // end_addr lstream.ignore(6); // ignore ` [perms] ` (perms is 4ch long) lstream >> entry.offset; // offset lstream.ignore(7); // ignore device lstream >> discard; // ignore inode lstream >> entry.pathname; // pathname rev_addr_map.insert(make_pair(entry.mem_region, map_entries.size())); map_entries.push_back(entry); } handle.close(); } const MemoryMap::MapEntry& MemoryMap::get_entry(size_t id) const { try { return map_entries.at(id); } catch(const std::out_of_range& e) { // Just here to remind one to throw a std::out_of_range if the // underlying structure is changed at some point, and doesn't raise // std::out_of_range anymore upon .at() throw e; } } const MemoryMap::MapEntry& MemoryMap::operator[](size_t id) const { return get_entry(id); } size_t MemoryMap::id_of_address(uintptr_t addr) const { /* I have found no nice operator< for MemoryRegions that work nice with * both the internal consistency of map_entries and the search of the * containing interval. * We thus have two cases: * - either we seek the range [a, b[ containing a, * - or the range [a, b[ containing some c, a <= c < b. * * In the first case, if such a range exists, it is necessarily * lower_bound(MemoryRegion(a, a)). * In the second case, it is necessarily * --lower_bound(MemoryRegion(c, c)). */ MemoryRegion reg_index(addr, addr); auto bound_it = rev_addr_map.lower_bound(reg_index); if(bound_it != rev_addr_map.end() && bound_it->first.contains(addr)) return bound_it->second; if(bound_it != rev_addr_map.begin()) { --bound_it; if(bound_it->first.contains(addr)) return bound_it->second; } throw std::out_of_range("No region containing this address"); } MemoryMap::iter_t MemoryMap::begin() const { return map_entries.cbegin(); } MemoryMap::iter_t MemoryMap::end() const { return map_entries.cend(); } size_t MemoryMap::size() const { return map_entries.size(); }