summaryrefslogtreecommitdiff
path: root/hypodermic/memory.py
diff options
context:
space:
mode:
Diffstat (limited to 'hypodermic/memory.py')
-rw-r--r--hypodermic/memory.py111
1 files changed, 111 insertions, 0 deletions
diff --git a/hypodermic/memory.py b/hypodermic/memory.py
new file mode 100644
index 0000000..6ffa5d1
--- /dev/null
+++ b/hypodermic/memory.py
@@ -0,0 +1,111 @@
+# Copyright (C) 2017 Jakob Kreuze, All Rights Reserved.
+#
+# This file is part of Hypodermic.
+#
+# Hypodermic is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# Hypodermic is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Hypodermic. If not, see <http://www.gnu.org/licenses/>.
+
+"""Parsing of a program's memory mapping info from procfs."""
+
+import collections
+import re
+
+
+Device = collections.namedtuple(
+ "Device",
+ ["major", "minor"]
+)
+
+Perms = collections.namedtuple(
+ "Perms",
+ ["r", "w", "x", "s"]
+)
+
+Region = collections.namedtuple(
+ "Region",
+ ["start", "end", "perms", "off", "dev", "inode", "path"]
+)
+
+
+def parse_device(line: str) -> Device:
+ """Converts a device line of the form "maj:min" into a Device
+ object.
+
+ Args:
+ line(str): The line to parse.
+
+ Returns:
+ The parsed Device object.
+ """
+ major, minor = line.split(':')
+ return Device(major, minor)
+
+
+def parse_perms(line: str) -> Perms:
+ """Converts a permissions line of the form "rwxp" into a Perms
+ object.
+
+ Args:
+ line(str): The line to parse.
+
+ Returns:
+ The parsed Perms object.
+ """
+ return Perms(line[0] == 'r', line[1] == 'w', line[2] == 'x', line[3] == 's')
+
+
+def parse_region(line: str) -> Region:
+ """Converts a line of text from the "maps" file into a Region
+ object.
+
+ Args:
+ line(str): The line to parse.
+
+ Returns:
+ The parsed Region object.
+ """
+ ret = re.split(r"\s+", line.strip())
+ if len(ret) == 6:
+ address, perms, off, dev, inode, path = ret
+ else:
+ address, perms, off, dev, inode = ret
+ path = ""
+ start, end = address.split('-')
+ return Region(int(start, 16), int(end, 16), parse_perms(perms),
+ int(off, 16), parse_device(dev), int(inode), path)
+
+
+def maps(pid: int) -> list:
+ """Gets memory mapping information for a given pid.
+
+ Args:
+ pid (int): The pid of the process to get memory mapping
+ information for.
+
+ Raises:
+ TypeError: If the pid argument is not an int.
+ PermissionError: If the mapping information cannot be read.
+
+ Returns:
+ A list of Region objects.
+ """
+ if not isinstance(pid, int):
+ raise TypeError("pid argument must be an int")
+
+ regions = []
+
+ with open("/proc/{}/maps".format(pid)) as maps:
+ for line in maps:
+ regions.append(parse_region(line))
+
+ return regions