2018-04-04 14:42:50 +02:00
|
|
|
#include <dwarfinterpret/MemoryMap.hpp>
|
2018-04-03 12:23:15 +02:00
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fstream>
|
|
|
|
#include <sstream>
|
2018-04-04 14:42:50 +02:00
|
|
|
#include <iostream>
|
2018-04-03 12:23:15 +02:00
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
void MemoryMap::MapEntry::dump(ostream& os) const {
|
|
|
|
os << "MapEntry: "
|
|
|
|
<< hex << mem_region.begin << '-' << mem_region.end
|
2018-04-04 14:42:50 +02:00
|
|
|
<< " offset " << hex << offset
|
2018-04-03 12:23:15 +02:00
|
|
|
<< 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()) {
|
2018-04-04 14:42:50 +02:00
|
|
|
cerr << "## " << line << endl;
|
2018-04-03 12:23:15 +02:00
|
|
|
istringstream lstream(line);
|
|
|
|
MapEntry entry;
|
|
|
|
uintptr_t discard;
|
|
|
|
|
2018-04-04 14:42:50 +02:00
|
|
|
/* Line format:
|
|
|
|
* ============
|
|
|
|
* (cf man 5 proc for details)
|
|
|
|
*
|
|
|
|
* beg_addr-end_addr [perms] offset [dev] [inode] pathname
|
|
|
|
* [x]: x, ignored here.
|
|
|
|
*/
|
|
|
|
|
2018-04-03 12:23:15 +02:00
|
|
|
lstream >> std::hex;
|
2018-04-04 14:42:50 +02:00
|
|
|
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
|
2018-04-03 12:23:15 +02:00
|
|
|
|
|
|
|
rev_addr_map.insert(make_pair(entry.mem_region, map_entries.size()));
|
|
|
|
map_entries.push_back(entry);
|
|
|
|
}
|
2018-04-04 14:42:50 +02:00
|
|
|
cerr << endl;
|
2018-04-03 12:23:15 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2018-04-05 19:17:02 +02:00
|
|
|
if(bound_it != rev_addr_map.end() && bound_it->first.contains(addr))
|
2018-04-03 12:23:15 +02:00
|
|
|
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();
|
|
|
|
}
|