dwarfinterpret/src/MemoryMap.cpp

110 lines
3.1 KiB
C++

#include <dwarfinterpret/MemoryMap.hpp>
#include <unistd.h>
#include <fstream>
#include <sstream>
#include <iostream>
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();
}