Add MemoryMap to read /proc/[pid]/maps
This commit is contained in:
parent
ea7405e3ba
commit
13283d8e2a
2 changed files with 198 additions and 0 deletions
102
src/MemoryMap.cpp
Normal file
102
src/MemoryMap.cpp
Normal file
|
@ -0,0 +1,102 @@
|
|||
#include "MemoryMap.hpp"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
void MemoryMap::MapEntry::dump(ostream& os) const {
|
||||
os << "MapEntry: "
|
||||
<< hex << mem_region.begin << '-' << mem_region.end
|
||||
<< " offset " << 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;
|
||||
|
||||
lstream >> std::hex;
|
||||
lstream >> entry.mem_region.begin;
|
||||
lstream.ignore(1);
|
||||
lstream >> entry.mem_region.end;
|
||||
lstream.ignore(6);
|
||||
lstream >> discard;
|
||||
lstream.ignore(7);
|
||||
lstream >> entry.offset;
|
||||
lstream >> entry.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())
|
||||
throw std::out_of_range("No region containing this address");
|
||||
if(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();
|
||||
}
|
96
src/MemoryMap.hpp
Normal file
96
src/MemoryMap.hpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
#pragma once
|
||||
|
||||
/** MemoryMap: load, parse and make available the process' memory map
|
||||
*
|
||||
* This class allows the easy loading, parsing and reading of the process'
|
||||
* memory map, that is, the correspondance between the various compile units
|
||||
* and shared libraries' sections, and their mapping location in memory.
|
||||
*
|
||||
* This class is absolutely not portable and reads /proc/[pid]/maps. For more
|
||||
* information, please read `man 5 proc`.
|
||||
*/
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
class MemoryMap {
|
||||
public:
|
||||
/// Thrown when the constructor fails to read the map's data
|
||||
class ReadMapFailed: public std::exception {};
|
||||
|
||||
struct MemoryRegion {
|
||||
/** A contiguous memory region. */
|
||||
|
||||
MemoryRegion() = default;
|
||||
MemoryRegion(uintptr_t begin, uintptr_t end)
|
||||
: begin(begin), end(end) {}
|
||||
|
||||
uintptr_t begin; ///< First address (incl.) in the region
|
||||
uintptr_t end; ///< Past-the-end address for the region
|
||||
|
||||
bool operator==(const MemoryRegion& oth) const {
|
||||
return begin == oth.begin && end == oth.end;
|
||||
}
|
||||
|
||||
bool operator<(const MemoryRegion& oth) const {
|
||||
if(begin < oth.begin)
|
||||
return true;
|
||||
return (begin == oth.begin && end < oth.end);
|
||||
}
|
||||
|
||||
/// Checks whether `addr` is in this region
|
||||
bool contains(uintptr_t addr) const {
|
||||
return begin <= addr && addr < end;
|
||||
}
|
||||
};
|
||||
|
||||
struct MapEntry {
|
||||
std::string pathname;
|
||||
MemoryRegion mem_region;
|
||||
uintptr_t offset;
|
||||
|
||||
/// Debug feature: dumps the MapEntry on the given stream
|
||||
void dump(std::ostream& os) const;
|
||||
};
|
||||
|
||||
/// An iterator to the map entries. The underlying type might change.
|
||||
typedef std::vector<MapEntry>::const_iterator iter_t;
|
||||
|
||||
public:
|
||||
/** Loads and constructs the map.
|
||||
*
|
||||
* \throws ReadMapFailed upon failure */
|
||||
MemoryMap();
|
||||
|
||||
/** Get the MapEntry for a given id
|
||||
*
|
||||
* \throws std::out_of_range if there is no such entry */
|
||||
const MapEntry& get_entry(size_t id) const;
|
||||
|
||||
/// Synonymous for get_entry
|
||||
const MapEntry& operator[](size_t id) const;
|
||||
|
||||
/** Get the MapEntry id of the region containing addr
|
||||
*
|
||||
* \throws std::out_of_range if no such region is mapped */
|
||||
size_t id_of_address(uintptr_t addr) const;
|
||||
|
||||
/// Get a constant iterator to the first map entry
|
||||
iter_t begin() const;
|
||||
|
||||
/// Get a constant iterator to a past-the-end iterator
|
||||
iter_t end() const;
|
||||
|
||||
/// Get the number of entries in the map
|
||||
size_t size() const;
|
||||
|
||||
private:
|
||||
std::vector<MapEntry> map_entries;
|
||||
|
||||
/// Maps regions back to their id
|
||||
std::map<MemoryRegion, size_t> rev_addr_map;
|
||||
};
|
Loading…
Reference in a new issue