Skip to content

Instantly share code, notes, and snippets.

@neonbyte1
Last active November 29, 2025 17:27
Show Gist options
  • Select an option

  • Save neonbyte1/44182849df6004c4242e5bcfb2cae094 to your computer and use it in GitHub Desktop.

Select an option

Save neonbyte1/44182849df6004c4242e5bcfb2cae094 to your computer and use it in GitHub Desktop.
Parse /proc/<pid>/maps
// The MIT License (MIT)
//
// Copyright (c) 2025 neonbyte1
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#pragma once
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>
// <move_to_src>
#include <sstream>
#include <iomanip>
#include <fstream>
// </move_to_src>
struct memory_segment
{
union permission_t
{
std::uint8_t flag{};
struct
{
std::uint8_t is_readable : 1;
std::uint8_t is_writeable : 1;
std::uint8_t is_executeable : 1;
std::uint8_t is_shared : 1;
std::uint8_t is_private : 1;
std::uint8_t _reserved : 3;
};
};
unsigned long start{};
unsigned long end{};
unsigned long offset{};
std::uint32_t major{};
std::uint32_t minor{};
ino_t inode{};
permission_t permissions{};
std::string name{};
};
[[nodiscard]]
auto
parse_segment(
std::string& line,
memory_segment& segment
) noexcept -> bool
{
std::stringstream ss(line);
std::string address_range;
std::string perms;
std::string dev;
std::string pathname;
ss >> address_range
>> perms
>> std::hex
>> segment.offset
>> std::dec
>> dev
>> segment.inode;
const auto dash_pos = address_range.find('-');
if (dash_pos == std::string::npos) {
return false;
}
segment.start = std::stoull(address_range.substr(0, dash_pos), nullptr, 16);
segment.end = std::stoull(address_range.substr(dash_pos + 1), nullptr, 16);
if (const auto colon_pos = dev.find(':'); colon_pos != std::string::npos) {
segment.major = std::stoul(dev.substr(0, colon_pos), nullptr, 16);
segment.minor = std::stoul(dev.substr(colon_pos + 1), nullptr, 16);
}
if (ss >> std::ws && !ss.eof()) {
std::getline(ss, pathname);
pathname.erase(0, pathname.find_first_not_of(' '));
}
segment.name = pathname;
for (const auto& c : perms) {
switch (c) {
case 'r':
segment.permissions.is_readable = 1;
break;
case 'w':
segment.permissions.is_writeable = 1;
break;
case 'x':
segment.permissions.is_executeable = 1;
break;
case 's':
segment.permissions.is_shared = 1;
break;
case 'p':
segment.permissions.is_private = 1;
break;
default:
break;
}
}
return true;
}
[[nodiscard]]
auto
parse_maps(
const std::uint32_t pid
) noexcept -> std::vector<memory_segment>
{
std::stringstream maps_path;
std::vector<memory_segment> result;
maps_path << "/proc/" << pid << "/maps";
if (std::ifstream stream(maps_path.str()); stream) {
std::string line{};
while (std::getline(stream, line)) {
if (memory_segment segment{}; parse_segment(line, segment)) {
result.push_back(std::move(segment));
}
}
}
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment