1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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
|